-
Notifications
You must be signed in to change notification settings - Fork 2
fix: resolve local Docker setup issues #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,98 +6,89 @@ | |||||||||||
| # ============================================================================ | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Required: Database | ||||||||||||
| # Database (PostgreSQL) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # PostgreSQL connection string (for postgres, neon, supabase) | ||||||||||||
| # Format: postgresql://user:password@host:port/database | ||||||||||||
| DATABASE_URL=postgres://user:password@localhost:5432/betterbase | ||||||||||||
| POSTGRES_USER=betterbase | ||||||||||||
| POSTGRES_PASSWORD=your_secure_password_here | ||||||||||||
| POSTGRES_DB=betterbase | ||||||||||||
|
|
||||||||||||
| # Or for Neon (serverless PostgreSQL) | ||||||||||||
| # DATABASE_URL=postgres://user:password@ep-xxx.us-east-1.aws.neon.tech/neondb?sslmode=require | ||||||||||||
|
|
||||||||||||
| # Or for Turso (libSQL) | ||||||||||||
| # TURSO_URL=libsql://your-database.turso.io | ||||||||||||
| # TURSO_AUTH_TOKEN=your-auth-token | ||||||||||||
| DATABASE_URL=postgresql://betterbase:your_secure_password_here@localhost:5432/betterbase | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Required: Authentication | ||||||||||||
| # Authentication | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Generate a secure secret: openssl rand -base64 32 | ||||||||||||
| AUTH_SECRET=your-super-secret-key-min-32-chars-long-change-in-production | ||||||||||||
| # Generate: openssl rand -base64 32 | ||||||||||||
| AUTH_SECRET=your-super-secret-key-min-32-chars-long | ||||||||||||
| AUTH_URL=http://localhost:3000 | ||||||||||||
|
Comment on lines
17
to
22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Environment variable names don't match server code. Lines 21-22 define Either update the server code or use the expected variable names here. Proposed fix to match server expectations # ----------------------------------------------------------------------------
# Authentication
# ----------------------------------------------------------------------------
# Generate: openssl rand -base64 32
-AUTH_SECRET=your-super-secret-key-min-32-chars-long
-AUTH_URL=http://localhost:3000
+BETTERBASE_JWT_SECRET=your-super-secret-key-min-32-chars-long
+BETTERBASE_PUBLIC_URL=http://localhost:3000-CORS_ORIGIN=http://localhost:3000,http://localhost:5173
+CORS_ORIGINS=http://localhost:3000,http://localhost:5173🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Optional: Storage (S3-compatible) | ||||||||||||
| # MinIO (S3-compatible storage) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Provider: s3, r2, backblaze, minio | ||||||||||||
| STORAGE_PROVIDER=r2 | ||||||||||||
| STORAGE_BUCKET=betterbase-storage | ||||||||||||
| STORAGE_REGION=auto | ||||||||||||
| STORAGE_ENDPOINT=https://your-r2-endpoint.r2.cloudflarestorage.com | ||||||||||||
| STORAGE_ACCESS_KEY_ID=your-access-key | ||||||||||||
| STORAGE_SECRET_ACCESS_KEY=your-secret-key | ||||||||||||
| MINIO_ROOT_USER=minioadmin | ||||||||||||
| MINIO_ROOT_PASSWORD=minioadmin_password | ||||||||||||
|
|
||||||||||||
| STORAGE_ENDPOINT=http://localhost:9000 | ||||||||||||
| STORAGE_ACCESS_KEY=minioadmin | ||||||||||||
| STORAGE_SECRET_KEY=minioadmin_password | ||||||||||||
| STORAGE_BUCKET=betterbase | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Optional: Email (SMTP) | ||||||||||||
| # Inngest (Durable Workflow Engine) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| SMTP_HOST=smtp.example.com | ||||||||||||
| SMTP_PORT=587 | ||||||||||||
| SMTP_USER=your-smtp-user | ||||||||||||
| SMTP_PASS=your-smtp-password | ||||||||||||
| SMTP_FROM=noreply@your-domain.com | ||||||||||||
| INNGEST_LOG_LEVEL=info | ||||||||||||
| # Generate: openssl rand -hex 32 | ||||||||||||
| INNGEST_SIGNING_KEY= | ||||||||||||
| # Generate: openssl rand -hex 16 | ||||||||||||
| INNGEST_EVENT_KEY= | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Optional: OAuth Providers | ||||||||||||
| # Application Settings | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # GitHub | ||||||||||||
| # GITHUB_CLIENT_ID=your-github-client-id | ||||||||||||
| # GITHUB_CLIENT_SECRET=your-github-client-secret | ||||||||||||
| NODE_ENV=development | ||||||||||||
| PORT=3001 | ||||||||||||
| HOST=0.0.0.0 | ||||||||||||
|
|
||||||||||||
| # GOOGLE_CLIENT_ID=your-google-client-id | ||||||||||||
| # GOOGLE_CLIENT_SECRET=your-google-client-secret | ||||||||||||
| CORS_ORIGIN=http://localhost:3000,http://localhost:5173 | ||||||||||||
|
|
||||||||||||
| # Discord | ||||||||||||
| # DISCORD_CLIENT_ID=your-discord-client-id | ||||||||||||
| # DISCORD_CLIENT_SECRET=your-discord-client-secret | ||||||||||||
| LOG_LEVEL=debug | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Optional: Phone Auth (Twilio) | ||||||||||||
| # Storage (S3-compatible - for production with external services) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # TWILIO_ACCOUNT_SID=your-twilio-sid | ||||||||||||
| # TWILIO_AUTH_TOKEN=your-twilio-token | ||||||||||||
| # TWILIO_PHONE_NUMBER=+1234567890 | ||||||||||||
| # STORAGE_PROVIDER=r2 | ||||||||||||
| # STORAGE_BUCKET=betterbase-storage | ||||||||||||
| # STORAGE_REGION=auto | ||||||||||||
| # STORAGE_ENDPOINT=https://your-r2-endpoint.r2.cloudflarestorage.com | ||||||||||||
| # STORAGE_ACCESS_KEY_ID=your-access-key | ||||||||||||
| # STORAGE_SECRET_ACCESS_KEY=your-secret-key | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Application Settings | ||||||||||||
| # Email (optional) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| NODE_ENV=development | ||||||||||||
| PORT=3000 | ||||||||||||
| HOST=0.0.0.0 | ||||||||||||
| # SMTP_HOST=smtp.example.com | ||||||||||||
| # SMTP_PORT=587 | ||||||||||||
| # SMTP_USER=your-smtp-user | ||||||||||||
| # SMTP_PASS=your-smtp-password | ||||||||||||
| # SMTP_FROM=noreply@your-domain.com | ||||||||||||
|
|
||||||||||||
| # Comma-separated list of allowed CORS origins | ||||||||||||
| CORS_ORIGIN=http://localhost:3000,http://localhost:5173 | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # OAuth Providers (optional) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # GITHUB_CLIENT_ID=your-github-client-id | ||||||||||||
| # GITHUB_CLIENT_SECRET=your-github-client-secret | ||||||||||||
|
|
||||||||||||
| # Logging | ||||||||||||
| LOG_LEVEL=debug | ||||||||||||
| # GOOGLE_CLIENT_ID=your-google-client-id | ||||||||||||
| # GOOGLE_CLIENT_SECRET=your-google-client-secret | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Vector Search (optional) | ||||||||||||
| # Phone Auth (optional - Twilio) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # VECTOR_PROVIDER=openai | ||||||||||||
| # OPENAI_API_KEY=your-openai-api-key | ||||||||||||
| # TWILIO_ACCOUNT_SID=your-twilio-sid | ||||||||||||
| # TWILIO_AUTH_TOKEN=your-twilio-token | ||||||||||||
| # TWILIO_PHONE_NUMBER=+1234567890 | ||||||||||||
|
|
||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # Inngest (Durable Workflow Engine) | ||||||||||||
| # Vector Search (optional) | ||||||||||||
| # ---------------------------------------------------------------------------- | ||||||||||||
| # For local development with Inngest Docker: | ||||||||||||
| # INNGEST_BASE_URL=http://localhost:8288 | ||||||||||||
| # | ||||||||||||
| # For self-hosted production: | ||||||||||||
| # INNGEST_BASE_URL=http://inngest:8288 | ||||||||||||
| # Generate signing key: openssl rand -hex 32 | ||||||||||||
| # INNGEST_SIGNING_KEY=change-me-to-a-random-hex-string | ||||||||||||
| # Generate event key: openssl rand -hex 16 | ||||||||||||
| # INNGEST_EVENT_KEY=change-me-to-another-random-hex-string | ||||||||||||
| # Log level (debug | info | warn | error) | ||||||||||||
| # INNGEST_LOG_LEVEL=info | ||||||||||||
| # VECTOR_PROVIDER=openai | ||||||||||||
| # OPENAI_API_KEY=your-openai-api-key | ||||||||||||
|
Comment on lines
+93
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Missing trailing newline. Static analysis flags missing blank line at end of file (EndingBlankLine). Fix # OPENAI_API_KEY=your-openai-api-key
+📝 Committable suggestion
Suggested change
🧰 Tools🪛 dotenv-linter (4.0.0)[warning] 94-94: [EndingBlankLine] No blank line at the end of the file (EndingBlankLine) 🤖 Prompt for AI Agents |
||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ============================================================================ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Betterbase Dashboard Dockerfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Builds the React dashboard and serves it with nginx. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Used in production self-hosted deployments. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Build: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # docker build -f apps/dashboard/Dockerfile -t betterbase-dashboard . | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ============================================================================ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM oven/bun:1.3.9-debian AS builder | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WORKDIR /app | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY package.json bun.lock* ./ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN bun install --frozen-lockfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY . . | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ARG VITE_API_URL=http://localhost:3001 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ENV VITE_API_URL=$VITE_API_URL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN bun run build | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM nginx:alpine | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| COPY --from=builder /app/dist /usr/share/nginx/html | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+13
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Build context and paths are incorrect for monorepo structure. The build instructions specify building from repo root (
Proposed fix for monorepo-aware build FROM oven/bun:1.3.9-debian AS builder
WORKDIR /app
-COPY package.json bun.lock* ./
+COPY package.json bun.lock ./
+COPY apps/dashboard/package.json ./apps/dashboard/
RUN bun install --frozen-lockfile
COPY . .
+WORKDIR /app/apps/dashboard
+
ARG VITE_API_URL=http://localhost:3001
ENV VITE_API_URL=$VITE_API_URL
-RUN bun run build
+RUN cd /app/apps/dashboard && bun run build
FROM nginx:alpine
-COPY --from=builder /app/dist /usr/share/nginx/html
+COPY --from=builder /app/apps/dashboard/dist /usr/share/nginx/html📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RUN cat > /etc/nginx/conf.d/default.conf << 'EOF' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| server { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| listen 80; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| server_name _; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| root /usr/share/nginx/html; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index index.html; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| location /assets/ { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expires 1y; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| add_header Cache-Control "public, immutable"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| location / { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try_files $uri $uri/ /index.html; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| add_header X-Frame-Options "SAMEORIGIN" always; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| add_header X-Content-Type-Options "nosniff" always; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EXPOSE 80 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CMD ["nginx", "-g", "daemon off;"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Add healthcheck and non-root user for production hardening. The nginx runtime stage lacks a healthcheck and runs as root. For production self-hosted deployments, these are recommended. Proposed additions FROM nginx:alpine
COPY --from=builder /app/apps/dashboard/dist /usr/share/nginx/html
RUN cat > /etc/nginx/conf.d/default.conf << 'EOF'
...
EOF
+RUN chown -R nginx:nginx /usr/share/nginx/html
+USER nginx
+
+HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
+ CMD wget -qO- http://localhost:80/ || exit 1
+
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]🧰 Tools🪛 Checkov (3.2.510)[low] 1-53: Ensure that HEALTHCHECK instructions have been added to container images (CKV_DOCKER_2) [low] 1-53: Ensure that a user for the container has been created (CKV_DOCKER_3) 🪛 Hadolint (2.14.0)[error] 31-31: unexpected 's' (DL1000) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,34 +1,49 @@ | ||
| version: "3.9" | ||
| # ============================================================================ | ||
| # Betterbase Self-Hosted Production Docker Compose | ||
| # | ||
| # Full self-hosted deployment with all services. | ||
| # No external dependencies required. | ||
| # | ||
| # Usage: | ||
| # 1. Build: bun run build | ||
| # 2. cp .env.example .env && edit .env | ||
| # 3. docker compose -f docker-compose.self-hosted.yml up -d | ||
| # | ||
| # Services: | ||
| # - PostgreSQL: localhost:5432 | ||
| # - MinIO: localhost:9000 (console: localhost:9001) | ||
| # - Inngest: localhost:8288 | ||
| # - Server: localhost:3001 | ||
| # - Dashboard: localhost (via nginx) | ||
| # ============================================================================ | ||
|
|
||
| services: | ||
| # ─── Postgres ────────────────────────────────────────────────────────────── | ||
| postgres: | ||
| image: postgres:16-alpine | ||
| container_name: betterbase-postgres | ||
| restart: unless-stopped | ||
| environment: | ||
| POSTGRES_USER: betterbase | ||
| POSTGRES_USER: ${POSTGRES_USER:-betterbase} | ||
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-betterbase} | ||
| POSTGRES_DB: betterbase | ||
| POSTGRES_DB: ${POSTGRES_DB:-betterbase} | ||
| volumes: | ||
| - postgres_data:/var/lib/postgresql/data | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready -U betterbase"] | ||
| test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-betterbase}"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 5 | ||
| networks: | ||
| - betterbase-internal | ||
|
|
||
| # ─── MinIO (S3-compatible storage) ───────────────────────────────────────── | ||
| minio: | ||
| image: minio/minio:RELEASE.2024-01-16T16-07-38Z | ||
| image: minio/minio:latest | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Unpinned MinIO images may cause unexpected breakage.
Also applies to: 58-58 🤖 Prompt for AI Agents |
||
| container_name: betterbase-minio | ||
| restart: unless-stopped | ||
| command: server /data --console-address ":9001" | ||
| environment: | ||
| MINIO_ROOT_USER: ${STORAGE_ACCESS_KEY:-minioadmin} | ||
| MINIO_ROOT_PASSWORD: ${STORAGE_SECRET_KEY:-minioadmin} | ||
| MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin} | ||
| MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin} | ||
| volumes: | ||
| - minio_data:/data | ||
| healthcheck: | ||
|
|
@@ -39,41 +54,33 @@ services: | |
| networks: | ||
| - betterbase-internal | ||
|
|
||
| # ─── MinIO bucket init (runs once, exits) ────────────────────────────────── | ||
| minio-init: | ||
| image: minio/mc:RELEASE.2024-01-06T18-51-57Z | ||
| image: minio/mc:latest | ||
| container_name: betterbase-minio-init | ||
| depends_on: | ||
| minio: | ||
| condition: service_healthy | ||
| entrypoint: > | ||
| /bin/sh -c " | ||
| mc alias set local http://minio:9000 ${STORAGE_ACCESS_KEY:-minioadmin} ${STORAGE_SECRET_KEY:-minioadmin}; | ||
| mc alias set local http://minio:9000 ${MINIO_ROOT_USER:-minioadmin} ${MINIO_ROOT_PASSWORD:-minioadmin}; | ||
| mc mb --ignore-existing local/betterbase; | ||
| echo 'MinIO bucket initialized.'; | ||
| " | ||
| networks: | ||
| - betterbase-internal | ||
|
|
||
| # ─── Inngest (Durable Workflow Engine) ──────────────────────────────────── | ||
| inngest: | ||
| image: inngest/inngest:latest | ||
| image: inngest/inngest:v1.17.5 | ||
| container_name: betterbase-inngest | ||
| restart: unless-stopped | ||
| command: inngest start --host 0.0.0.0 --port 8288 | ||
| command: inngest dev --host 0.0.0.0 --port 8288 | ||
| environment: | ||
| INNGEST_LOG_LEVEL: ${INNGEST_LOG_LEVEL:-info} | ||
| volumes: | ||
| - inngest_data:/data | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "wget -qO- http://localhost:8288/health || exit 1"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 5 | ||
| networks: | ||
| - betterbase-internal | ||
|
|
||
| # ─── Betterbase Server ───────────────────────────────────────────────────── | ||
| betterbase-server: | ||
| build: | ||
| context: . | ||
|
|
@@ -88,64 +95,58 @@ services: | |
| minio-init: | ||
| condition: service_completed_successfully | ||
| inngest: | ||
| condition: service_healthy | ||
| condition: service_started | ||
| environment: | ||
| DATABASE_URL: postgresql://betterbase:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/betterbase | ||
| BETTERBASE_JWT_SECRET: ${BETTERBASE_JWT_SECRET:?JWT secret required - set BETTERBASE_JWT_SECRET in .env} | ||
| BETTERBASE_ADMIN_EMAIL: ${BETTERBASE_ADMIN_EMAIL:-} | ||
| BETTERBASE_ADMIN_PASSWORD: ${BETTERBASE_ADMIN_PASSWORD:-} | ||
| BETTERBASE_PUBLIC_URL: ${BETTERBASE_PUBLIC_URL:-http://localhost} | ||
| DATABASE_URL: postgresql://${POSTGRES_USER:-betterbase}:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/${POSTGRES_DB:-betterbase} | ||
| AUTH_SECRET: ${AUTH_SECRET:?JWT secret required - set AUTH_SECRET in .env} | ||
| AUTH_URL: ${AUTH_URL:-http://localhost:3000} | ||
| STORAGE_ENDPOINT: http://minio:9000 | ||
| STORAGE_ACCESS_KEY: ${STORAGE_ACCESS_KEY:-minioadmin} | ||
| STORAGE_SECRET_KEY: ${STORAGE_SECRET_KEY:-minioadmin} | ||
| STORAGE_ACCESS_KEY: ${MINIO_ROOT_USER:-minioadmin} | ||
| STORAGE_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-minioadmin} | ||
| STORAGE_BUCKET: betterbase | ||
| PORT: "3001" | ||
| NODE_ENV: production | ||
| CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost} | ||
| CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost} | ||
| INNGEST_BASE_URL: http://inngest:8288 | ||
| INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY} | ||
| INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY} | ||
| networks: | ||
| - betterbase-internal | ||
| INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY:-} | ||
| INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY:-} | ||
|
Comment on lines
99
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Environment variable names don't match server expectations. The server's
With current config, the server will either fail Zod validation (missing required Proposed fix to match server expectations environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-betterbase}:${POSTGRES_PASSWORD:-betterbase}@postgres:5432/${POSTGRES_DB:-betterbase}
- AUTH_SECRET: ${AUTH_SECRET:?JWT secret required - set AUTH_SECRET in .env}
- AUTH_URL: ${AUTH_URL:-http://localhost:3000}
+ BETTERBASE_JWT_SECRET: ${BETTERBASE_JWT_SECRET:?JWT secret required - set BETTERBASE_JWT_SECRET in .env}
+ BETTERBASE_PUBLIC_URL: ${BETTERBASE_PUBLIC_URL:-http://localhost:3000}
STORAGE_ENDPOINT: http://minio:9000
STORAGE_ACCESS_KEY: ${MINIO_ROOT_USER:-minioadmin}
STORAGE_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-minioadmin}
STORAGE_BUCKET: betterbase
PORT: "3001"
NODE_ENV: production
- CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost}
+ CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost}
INNGEST_BASE_URL: http://inngest:8288
INNGEST_SIGNING_KEY: ${INNGEST_SIGNING_KEY:-}
INNGEST_EVENT_KEY: ${INNGEST_EVENT_KEY:-}As per coding guidelines: "BETTERBASE_JWT_SECRET must be at least 32 chars — enforced by env.ts Zod schema." 🤖 Prompt for AI Agents |
||
| healthcheck: | ||
| test: ["CMD-SHELL", "wget -qO- http://localhost:3001/health || exit 1"] | ||
| interval: 10s | ||
| timeout: 5s | ||
| retries: 5 | ||
| networks: | ||
| - betterbase-internal | ||
|
|
||
| # ─── Dashboard ───────────────────────────────────────────────────────────── | ||
| betterbase-dashboard: | ||
| build: | ||
| context: . | ||
| dockerfile: apps/dashboard/Dockerfile # Dashboard Dockerfile — see SH-25 | ||
| args: | ||
| VITE_API_URL: ${BETTERBASE_PUBLIC_URL:-http://localhost} | ||
| dashboard: | ||
| image: nginx:alpine | ||
| container_name: betterbase-dashboard | ||
| restart: unless-stopped | ||
| volumes: | ||
| - ./apps/dashboard/dist:/usr/share/nginx/html:ro | ||
| depends_on: | ||
| betterbase-server: | ||
| condition: service_healthy | ||
| - betterbase-server | ||
| networks: | ||
| - betterbase-internal | ||
|
Comment on lines
+121
to
130
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dashboard service requires pre-built assets. The dashboard service mounts Consider documenting explicitly or adding a build step to the instructions. 🤖 Prompt for AI Agents |
||
|
|
||
| # ─── Nginx Reverse Proxy ─────────────────────────────────────────────────── | ||
| nginx: | ||
| image: nginx:alpine | ||
| container_name: betterbase-nginx | ||
| restart: unless-stopped | ||
| depends_on: | ||
| - betterbase-server | ||
| - betterbase-dashboard | ||
| - dashboard | ||
| ports: | ||
| - "${HTTP_PORT:-80}:80" | ||
| volumes: | ||
| - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro | ||
| networks: | ||
| - betterbase-internal | ||
| healthcheck: | ||
| test: ["CMD", "nginx", "-t"] | ||
| interval: 30s | ||
| timeout: 10s | ||
| retries: 3 | ||
| networks: | ||
| - betterbase-internal | ||
|
|
||
| volumes: | ||
| postgres_data: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DATABASE_URL password is hardcoded, not derived from POSTGRES_PASSWORD.
POSTGRES_PASSWORDis set toyour_secure_password_herebutDATABASE_URLhas the same literal string hardcoded. Users who changePOSTGRES_PASSWORDmay forget to updateDATABASE_URL, causing connection failures.Suggested improvement
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 12-12: [UnorderedKey] The POSTGRES_PASSWORD key should go before the POSTGRES_USER key
(UnorderedKey)
[warning] 13-13: [UnorderedKey] The POSTGRES_DB key should go before the POSTGRES_PASSWORD key
(UnorderedKey)
🤖 Prompt for AI Agents