8.1 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 14-postgresql-migration | 02 | execute | 1 |
|
true |
|
|
Purpose: Provides the database infrastructure for local dev (DB-05) and production. Must exist before anyone runs the app against real Postgres. Output: docker-compose.dev.yml (new), docker-compose.yml (rewritten for Postgres), Dockerfile (updated), entrypoint.sh (updated)
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/14-postgresql-migration/14-CONTEXT.md @.planning/phases/14-postgresql-migration/14-RESEARCH.md@Dockerfile @entrypoint.sh
Task 1: Create Docker Compose files for dev and production docker-compose.dev.yml, docker-compose.yml docker-compose.yml, Dockerfile, entrypoint.sh **Step 1: Create `docker-compose.dev.yml`** per D-10 and D-11: ```yaml services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: gearbox POSTGRES_PASSWORD: gearbox POSTGRES_DB: gearbox ports: - "5432:5432" volumes: - pgdata-dev:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U gearbox"] interval: 5s timeout: 3s retries: 5volumes: pgdata-dev:
This is a development-only file. The app itself runs locally via `bun run dev` against this Postgres instance using `DATABASE_URL=postgresql://gearbox:gearbox@localhost:5432/gearbox`.
**Step 2: Rewrite `docker-compose.yml`** for production per D-10:
```yaml
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: gearbox
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: gearbox
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gearbox"]
interval: 10s
timeout: 5s
retries: 5
app:
image: gearbox:latest
environment:
DATABASE_URL: postgresql://gearbox:${POSTGRES_PASSWORD}@postgres:5432/gearbox
GEARBOX_URL: ${GEARBOX_URL}
ports:
- "3000:3000"
depends_on:
postgres:
condition: service_healthy
volumes:
- uploads:/app/uploads
volumes:
pgdata:
uploads:
Key changes from current docker-compose.yml:
- Remove any SQLite volume mounts (data/, gearbox.db references)
- Add postgres service with healthcheck
- App service uses DATABASE_URL env var per D-12
- App depends_on postgres with service_healthy condition
- POSTGRES_PASSWORD is externalized (not hardcoded in production)
grep -q "postgres:16-alpine" docker-compose.dev.yml && grep -q "postgres:16-alpine" docker-compose.yml && grep -q "POSTGRES_PASSWORD" docker-compose.yml && grep -q "DATABASE_URL" docker-compose.yml && echo "PASS" || echo "FAIL"
<acceptance_criteria>
- docker-compose.dev.yml exists and contains
image: postgres:16-alpine - docker-compose.dev.yml contains
POSTGRES_USER: gearboxandPOSTGRES_PASSWORD: gearboxandPOSTGRES_DB: gearbox - docker-compose.dev.yml contains
ports:with"5432:5432" - docker-compose.dev.yml contains a healthcheck with
pg_isready -U gearbox - docker-compose.yml contains
image: postgres:16-alpine - docker-compose.yml contains
DATABASE_URL: postgresql://gearbox:${POSTGRES_PASSWORD}@postgres:5432/gearbox - docker-compose.yml contains
depends_on:withcondition: service_healthy - docker-compose.yml does NOT contain
gearbox.dborDATABASE_PATHorsqlite</acceptance_criteria> Docker Compose dev file provides local Postgres. Production compose includes Postgres with healthcheck and app service with DATABASE_URL.
- docker-compose.dev.yml exists and contains
The current Dockerfile installs python3 make g++ for native SQLite bindings (better-sqlite3). These are no longer needed since postgres.js is pure JavaScript.
FROM oven/bun:1 AS deps
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
FROM deps AS build
COPY . .
RUN bun run build
FROM oven/bun:1-slim AS production
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist/client ./dist/client
COPY src/server ./src/server
COPY src/db ./src/db
COPY src/shared ./src/shared
COPY drizzle.config.ts package.json ./
COPY drizzle-pg ./drizzle-pg
COPY entrypoint.sh ./
RUN chmod +x entrypoint.sh && mkdir -p uploads
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD bun -e "fetch('http://localhost:3000/api/health').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))"
ENTRYPOINT ["./entrypoint.sh"]
Key changes:
- Remove
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*from deps stage (no native bindings needed) - Change
COPY drizzle ./drizzletoCOPY drizzle-pg ./drizzle-pg - Remove
mkdir -p data(no SQLite data directory needed)
Step 2: Update entrypoint.sh — no changes needed (it already runs bun run src/db/migrate.ts which has been rewritten to use postgres-js migrator in Plan 01). Verify it still reads:
#!/bin/sh
set -e
bun run src/db/migrate.ts
exec bun run src/server/index.ts
<success_criteria> Docker Compose dev file provides PostgreSQL 16 for local development. Production compose includes Postgres + app with proper dependency chain. Dockerfile is lean (no native build tools) and copies PostgreSQL migrations. </success_criteria>
After completion, create `.planning/phases/14-postgresql-migration/14-02-SUMMARY.md`