docs(17): create phase plan for Docker deployment
Two plans in 2 waves: - Plan 01 (Wave 1): standalone output, DB pool limit, remove @vercel/blob, health endpoint - Plan 02 (Wave 2): Dockerfile, docker-compose.yml, .dockerignore, .env.production.example Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
170
.planning/phases/17-docker-deployment/17-01-PLAN.md
Normal file
170
.planning/phases/17-docker-deployment/17-01-PLAN.md
Normal file
@@ -0,0 +1,170 @@
|
||||
---
|
||||
phase: 17-docker-deployment
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- teressa-copeland-homes/next.config.ts
|
||||
- teressa-copeland-homes/src/lib/db/index.ts
|
||||
- teressa-copeland-homes/package.json
|
||||
- teressa-copeland-homes/src/app/api/health/route.ts
|
||||
autonomous: true
|
||||
requirements: [DEPLOY-01, DEPLOY-02, DEPLOY-04]
|
||||
must_haves:
|
||||
truths:
|
||||
- "next.config.ts has output: 'standalone' so Next.js produces a self-contained server.js"
|
||||
- "Database connection pool is limited to 5 connections to avoid Neon free tier exhaustion"
|
||||
- "@vercel/blob is removed from dependencies (dead dependency)"
|
||||
- "GET /api/health returns 200 with db connectivity check"
|
||||
artifacts:
|
||||
- path: "teressa-copeland-homes/next.config.ts"
|
||||
provides: "Standalone output config"
|
||||
contains: "output: 'standalone'"
|
||||
- path: "teressa-copeland-homes/src/lib/db/index.ts"
|
||||
provides: "Pool-limited database client"
|
||||
contains: "max: 5"
|
||||
- path: "teressa-copeland-homes/src/app/api/health/route.ts"
|
||||
provides: "Health check endpoint"
|
||||
exports: ["GET"]
|
||||
key_links:
|
||||
- from: "teressa-copeland-homes/src/app/api/health/route.ts"
|
||||
to: "teressa-copeland-homes/src/lib/db/index.ts"
|
||||
via: "db import for SELECT 1"
|
||||
pattern: "import.*db.*from"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Prepare the application codebase for Docker deployment by making four targeted code changes: enable standalone output, limit the database connection pool, remove the dead @vercel/blob dependency, and add a health check endpoint.
|
||||
|
||||
Purpose: These changes are prerequisites for the Dockerfile and docker-compose.yml (Plan 02). Standalone output is required for the three-stage Docker build. Pool limiting prevents Neon connection exhaustion. The health endpoint enables Docker's HEALTHCHECK directive.
|
||||
|
||||
Output: Modified next.config.ts, db/index.ts, package.json; new /api/health route
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/17-docker-deployment/17-CONTEXT.md
|
||||
|
||||
@teressa-copeland-homes/next.config.ts
|
||||
@teressa-copeland-homes/src/lib/db/index.ts
|
||||
@teressa-copeland-homes/package.json
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Enable standalone output, limit DB pool, remove @vercel/blob</name>
|
||||
<files>teressa-copeland-homes/next.config.ts, teressa-copeland-homes/src/lib/db/index.ts, teressa-copeland-homes/package.json</files>
|
||||
<read_first>
|
||||
- teressa-copeland-homes/next.config.ts
|
||||
- teressa-copeland-homes/src/lib/db/index.ts
|
||||
- teressa-copeland-homes/package.json
|
||||
</read_first>
|
||||
<action>
|
||||
1. **next.config.ts** (per D-05): Add `output: 'standalone'` to the NextConfig object. Keep existing `transpilePackages` and `serverExternalPackages` intact. Result:
|
||||
```typescript
|
||||
const nextConfig: NextConfig = {
|
||||
output: 'standalone',
|
||||
transpilePackages: ['react-pdf', 'pdfjs-dist'],
|
||||
serverExternalPackages: ['@napi-rs/canvas'],
|
||||
};
|
||||
```
|
||||
|
||||
2. **src/lib/db/index.ts** (per D-08): Change `postgres(url)` to `postgres(url, { max: 5 })` in the `createDb` function. This limits the connection pool to 5 connections, leaving headroom on Neon's free tier (10 max). Change line 12 from:
|
||||
```typescript
|
||||
const client = postgres(url);
|
||||
```
|
||||
to:
|
||||
```typescript
|
||||
const client = postgres(url, { max: 5 });
|
||||
```
|
||||
|
||||
3. **package.json** (per D-09): Remove `@vercel/blob` from dependencies. Run `npm uninstall @vercel/blob` from the `teressa-copeland-homes` directory. This removes the dead dependency that is imported nowhere in the codebase. Verify no import of `@vercel/blob` exists in src/ after removal.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /Users/ccopeland/temp/red/teressa-copeland-homes && grep -q "output: 'standalone'" next.config.ts && grep -q "max: 5" src/lib/db/index.ts && ! grep -q "@vercel/blob" package.json && echo "PASS"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `grep "output: 'standalone'" teressa-copeland-homes/next.config.ts` returns a match
|
||||
- `grep "max: 5" teressa-copeland-homes/src/lib/db/index.ts` returns a match
|
||||
- `grep "@vercel/blob" teressa-copeland-homes/package.json` returns NO match
|
||||
- `grep -r "@vercel/blob" teressa-copeland-homes/src/` returns NO match
|
||||
- `transpilePackages` and `serverExternalPackages` still present in next.config.ts
|
||||
</acceptance_criteria>
|
||||
<done>next.config.ts has standalone output, db pool is limited to 5, @vercel/blob removed from package.json</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Create /api/health endpoint with DB connectivity check</name>
|
||||
<files>teressa-copeland-homes/src/app/api/health/route.ts</files>
|
||||
<read_first>
|
||||
- teressa-copeland-homes/src/lib/db/index.ts
|
||||
- teressa-copeland-homes/src/lib/db/schema.ts (first 20 lines, for import pattern)
|
||||
</read_first>
|
||||
<action>
|
||||
Create `src/app/api/health/route.ts` (per D-10). This is a public endpoint (no auth) that:
|
||||
- Runs `SELECT 1` via the Drizzle db client using `db.execute(sql\`SELECT 1\`)`
|
||||
- Returns `{ ok: true, db: 'connected' }` with status 200 on success
|
||||
- Returns `{ ok: false, error: message }` with status 503 on failure
|
||||
- Wraps the DB call in try/catch
|
||||
|
||||
Full file content:
|
||||
```typescript
|
||||
import { db } from '@/lib/db';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
await db.execute(sql`SELECT 1`);
|
||||
return Response.json({ ok: true, db: 'connected' });
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : 'Unknown error';
|
||||
return Response.json({ ok: false, error: message }, { status: 503 });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
No auth check — this endpoint is intentionally public so Docker HEALTHCHECK can reach it without credentials.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /Users/ccopeland/temp/red/teressa-copeland-homes && test -f src/app/api/health/route.ts && grep -q "SELECT 1" src/app/api/health/route.ts && grep -q "export async function GET" src/app/api/health/route.ts && echo "PASS"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- File exists at `teressa-copeland-homes/src/app/api/health/route.ts`
|
||||
- File exports a GET function
|
||||
- File contains `SELECT 1` database check
|
||||
- File returns `{ ok: true, db: 'connected' }` on success
|
||||
- File returns status 503 on failure
|
||||
- No auth import or session check present
|
||||
</acceptance_criteria>
|
||||
<done>GET /api/health endpoint exists, runs SELECT 1 via Drizzle, returns 200/503 based on DB reachability</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
All code changes compile:
|
||||
```bash
|
||||
cd teressa-copeland-homes && npx tsc --noEmit
|
||||
```
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- next.config.ts has `output: 'standalone'` alongside existing config
|
||||
- db/index.ts creates postgres client with `{ max: 5 }`
|
||||
- @vercel/blob removed from package.json dependencies
|
||||
- /api/health route exists and checks DB connectivity
|
||||
- `npx tsc --noEmit` passes
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/17-docker-deployment/17-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user