Phase 01: Foundation - 5 plan(s) in 4 wave(s) - 2 parallel (wave 2: auth + tenant provisioning), 3 sequential - Ready for execution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
219 lines
8.3 KiB
Markdown
219 lines
8.3 KiB
Markdown
---
|
|
phase: 01-foundation
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- docker-compose.yml
|
|
- Dockerfile
|
|
- .dockerignore
|
|
- .env.example
|
|
- .env
|
|
- package.json
|
|
- tsconfig.json
|
|
- next.config.ts
|
|
- tailwind.config.ts
|
|
- postcss.config.mjs
|
|
- prisma/schema.prisma
|
|
- src/app/layout.tsx
|
|
- src/app/page.tsx
|
|
- src/app/globals.css
|
|
- src/lib/prisma.ts
|
|
- vitest.config.ts
|
|
- src/lib/__tests__/setup.test.ts
|
|
autonomous: true
|
|
|
|
must_haves:
|
|
truths:
|
|
- "Running docker compose up starts PostgreSQL 16, Redis 7, and the Next.js dev server with zero manual steps"
|
|
- "Prisma can connect to the Dockerized PostgreSQL and run migrations"
|
|
- "vitest runs and passes at least one smoke test"
|
|
- "The Next.js app renders at localhost:3000"
|
|
artifacts:
|
|
- path: "docker-compose.yml"
|
|
provides: "PostgreSQL, Redis, and app service definitions"
|
|
contains: "postgres"
|
|
- path: "prisma/schema.prisma"
|
|
provides: "Base Tenant and User models with RLS-ready tenant_id"
|
|
contains: "model Tenant"
|
|
- path: "src/lib/prisma.ts"
|
|
provides: "Singleton Prisma client"
|
|
exports: ["prisma"]
|
|
- path: "vitest.config.ts"
|
|
provides: "Test runner configuration"
|
|
contains: "vitest"
|
|
key_links:
|
|
- from: "docker-compose.yml"
|
|
to: "prisma/schema.prisma"
|
|
via: "DATABASE_URL env var"
|
|
pattern: "DATABASE_URL"
|
|
- from: "src/lib/prisma.ts"
|
|
to: "prisma/schema.prisma"
|
|
via: "PrismaClient import"
|
|
pattern: "PrismaClient"
|
|
---
|
|
|
|
<objective>
|
|
Scaffold the entire NetForge project from scratch: Next.js 15 with App Router, TypeScript, Tailwind CSS, Prisma ORM with PostgreSQL, Redis, Docker Compose for local dev, and Vitest for testing.
|
|
|
|
Purpose: Every subsequent plan depends on this foundation existing. Nothing can be built without the project scaffold, database connection, and dev environment.
|
|
Output: A running dockerized development environment with base schema and test infrastructure.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@C:\Users\KevinAsprec\.claude/get-shit-done/workflows/execute-plan.md
|
|
@C:\Users\KevinAsprec\.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/01-foundation/01-CONTEXT.md
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create Next.js project with Docker Compose dev environment</name>
|
|
<files>
|
|
docker-compose.yml
|
|
Dockerfile
|
|
.dockerignore
|
|
.env.example
|
|
.env
|
|
package.json
|
|
tsconfig.json
|
|
next.config.ts
|
|
tailwind.config.ts
|
|
postcss.config.mjs
|
|
src/app/layout.tsx
|
|
src/app/page.tsx
|
|
src/app/globals.css
|
|
</files>
|
|
<action>
|
|
Initialize a Next.js 15 project with App Router, TypeScript, and Tailwind CSS using `npx create-next-app@latest . --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"` (answer yes to all prompts or use flags to avoid interactive mode).
|
|
|
|
Create `docker-compose.yml` with three services:
|
|
1. **db**: PostgreSQL 16 image, port 5432, volume for data persistence, POSTGRES_USER=netforge, POSTGRES_PASSWORD=netforge_dev, POSTGRES_DB=netforge_dev
|
|
2. **redis**: Redis 7 image, port 6379
|
|
3. **app**: Builds from Dockerfile, port 3000, depends_on db and redis, mounts source code as volume for hot reload, environment variables from .env
|
|
|
|
Create a `Dockerfile` for development (Node 20 alpine, installs deps, runs `npm run dev`).
|
|
|
|
Create `.env.example` and `.env` with:
|
|
- DATABASE_URL=postgresql://netforge:netforge_dev@db:5432/netforge_dev
|
|
- REDIS_URL=redis://redis:6379
|
|
- NEXTAUTH_SECRET=dev-secret-change-in-production
|
|
- NEXTAUTH_URL=http://localhost:3000
|
|
|
|
Create `.dockerignore` excluding node_modules, .next, .git.
|
|
|
|
Update `src/app/page.tsx` to render a simple "NetForge" heading so we can verify the app loads.
|
|
|
|
IMPORTANT: Also create a local DATABASE_URL variant in .env for running Prisma commands from the host (outside Docker):
|
|
- DATABASE_URL_LOCAL=postgresql://netforge:netforge_dev@localhost:5432/netforge_dev
|
|
Add a note in .env.example explaining when to use each.
|
|
</action>
|
|
<verify>
|
|
Run `docker compose up -d` and verify all three services start. Run `docker compose ps` to confirm all services are healthy/running. Visit http://localhost:3000 and confirm the page loads.
|
|
</verify>
|
|
<done>All three Docker services (db, redis, app) start successfully. Next.js app serves at localhost:3000.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Prisma schema with base models and Vitest setup</name>
|
|
<files>
|
|
prisma/schema.prisma
|
|
src/lib/prisma.ts
|
|
vitest.config.ts
|
|
src/lib/__tests__/setup.test.ts
|
|
package.json
|
|
</files>
|
|
<action>
|
|
Install Prisma: `npm install prisma @prisma/client` and `npm install -D vitest @vitejs/plugin-react`.
|
|
|
|
Create `prisma/schema.prisma` with PostgreSQL provider and the following base models:
|
|
|
|
**Tenant** model:
|
|
- id: String @id @default(uuid())
|
|
- name: String (business name)
|
|
- slug: String @unique (URL-friendly identifier, auto-generated from name)
|
|
- ownerEmail: String
|
|
- status: TenantStatus enum (ACTIVE, SUSPENDED, PENDING_SUSPENSION)
|
|
- suspendedAt: DateTime? (when suspension was triggered)
|
|
- gracePeriodEndsAt: DateTime? (when service actually stops — 7 day grace period)
|
|
- createdAt: DateTime @default(now())
|
|
- updatedAt: DateTime @updatedAt
|
|
- users: User[]
|
|
|
|
**User** model:
|
|
- id: String @id @default(uuid())
|
|
- email: String
|
|
- passwordHash: String
|
|
- firstName: String
|
|
- lastName: String
|
|
- tenantId: String? (nullable for super-admins who are not tenant-scoped)
|
|
- tenant: Tenant? @relation
|
|
- roles: Role[] (array of enum values — multi-role support)
|
|
- isActive: Boolean @default(true)
|
|
- isSuperAdmin: Boolean @default(false)
|
|
- createdAt: DateTime @default(now())
|
|
- updatedAt: DateTime @updatedAt
|
|
- @@unique([email, tenantId]) — email unique within tenant
|
|
- @@index([tenantId])
|
|
|
|
**Role** enum: ADMIN, OFFICE_STAFF, COLLECTOR, TECHNICIAN, CLIENT
|
|
|
|
**TenantStatus** enum: ACTIVE, SUSPENDED, PENDING_SUSPENSION
|
|
|
|
IMPORTANT: Add a comment block at the top of schema.prisma noting that tenant_id is included on all tenant-scoped models for RLS. Future models (Subscriber, Invoice, etc.) MUST include tenantId.
|
|
|
|
Create `src/lib/prisma.ts` — singleton PrismaClient pattern (check for existing instance on globalThis in dev to avoid hot-reload connection exhaustion).
|
|
|
|
Create `vitest.config.ts` with:
|
|
- resolve alias for @/* pointing to src/*
|
|
- test.globals: true
|
|
- test.environment: 'node'
|
|
|
|
Create `src/lib/__tests__/setup.test.ts` — a smoke test that imports prisma client and asserts it's defined (does NOT need DB connection, just verifies the import chain works).
|
|
|
|
Run `npx prisma generate` to generate the Prisma client.
|
|
Run `npx prisma db push` to sync the schema to the Dockerized PostgreSQL (use DATABASE_URL_LOCAL if running from host, or exec into app container).
|
|
|
|
Add to package.json scripts:
|
|
- "test": "vitest run"
|
|
- "test:watch": "vitest"
|
|
- "db:push": "prisma db push"
|
|
- "db:generate": "prisma generate"
|
|
- "db:studio": "prisma studio"
|
|
</action>
|
|
<verify>
|
|
Run `npx vitest run` — the smoke test passes. Run `npx prisma db push` — schema syncs without errors. Run `npx prisma studio` briefly to confirm Tenant and User tables exist in the database.
|
|
</verify>
|
|
<done>Prisma schema with Tenant and User models is synced to PostgreSQL. Vitest runs and passes the smoke test. PrismaClient singleton is importable from @/lib/prisma.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
1. `docker compose up -d` starts all services without errors
|
|
2. `docker compose ps` shows db, redis, and app running
|
|
3. http://localhost:3000 renders the Next.js app
|
|
4. `npx prisma db push` succeeds (schema matches DB)
|
|
5. `npx vitest run` passes all tests
|
|
6. `npx prisma studio` shows Tenant and User tables
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Docker Compose starts PostgreSQL 16, Redis 7, and Next.js 15 dev server with one command
|
|
- Prisma schema has Tenant and User models with RLS-ready tenantId field
|
|
- Vitest is configured and runs at least one passing test
|
|
- All environment variables are documented in .env.example
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/01-foundation/01-01-SUMMARY.md`
|
|
</output>
|