--- phase: 03-agent-portal-shell plan: 01 subsystem: database tags: [drizzle, postgres, pgEnum, next-auth, middleware, routing] # Dependency graph requires: - phase: 01-foundation provides: Drizzle schema.ts with users table, auth.config.ts authorized callback, middleware.ts with /agent matcher provides: - clients and documents tables in PostgreSQL with document_status enum - Drizzle migration 0001_watery_blindfold.sql - /portal/:path* protected via middleware matcher and auth.config.ts authorized callback - Post-login redirect lands on /portal/dashboard - /agent/dashboard silently forwards to /portal/dashboard affects: [03-02, 03-03, 03-04, all Phase 3 plans — clients/documents tables and /portal routing are foundations] # Tech tracking tech-stack: added: [pgEnum from drizzle-orm/pg-core] patterns: [pgEnum defined before referencing table, documentStatusEnum as named export, portal route protection mirrors agent route pattern in authorized callback] key-files: created: - teressa-copeland-homes/drizzle/0001_watery_blindfold.sql - teressa-copeland-homes/drizzle/meta/0001_snapshot.json modified: - teressa-copeland-homes/src/lib/db/schema.ts - teressa-copeland-homes/middleware.ts - teressa-copeland-homes/src/lib/auth.config.ts - teressa-copeland-homes/src/app/agent/(protected)/dashboard/page.tsx key-decisions: - "documentStatusEnum exported before documents table — pgEnum must be declared before the table that references it or drizzle-kit may omit the CREATE TYPE statement" - "portal route protection mirrors existing /agent pattern in authorized callback — isPortalRoute check added alongside isAgentRoute, both redirect unauthenticated to /agent/login" - "Post-login redirect changed from /agent/dashboard to /portal/dashboard — agent portal lives at /portal prefix going forward" - "DATABASE_URL not loaded from .env.local by drizzle-kit (uses dotenv/config which reads .env) — migration run with explicit env var; .env.local is sufficient for Next.js dev server" patterns-established: - "pgEnum: export enum constant before the table that uses it in schema.ts" - "Route protection: add new route prefix to both middleware.ts matcher array AND auth.config.ts authorized callback isPortalRoute check" requirements-completed: [CLIENT-01, CLIENT-02, CLIENT-03, DASH-01, DASH-02] # Metrics duration: 3min completed: 2026-03-19 --- # Phase 3 Plan 01: Agent Portal Shell — Data & Routing Foundation Summary **Drizzle schema extended with clients + documents tables (document_status pgEnum), migration applied to local PostgreSQL, and /portal/* routes protected via middleware + auth.config.ts with post-login redirect updated to /portal/dashboard** ## Performance - **Duration:** 3 min - **Started:** 2026-03-19T22:16:34Z - **Completed:** 2026-03-19T22:19:00Z - **Tasks:** 2 - **Files modified:** 6 ## Accomplishments - Added `clients` and `documents` tables to Drizzle schema with `documentStatusEnum` (Draft, Sent, Viewed, Signed), generated and applied migration successfully - Extended middleware.ts matcher and auth.config.ts authorized callback to protect all `/portal/*` routes — unauthenticated requests redirect to `/agent/login` - Updated post-login redirect from `/agent/dashboard` to `/portal/dashboard`, and replaced the old agent dashboard stub with a forward to `/portal/dashboard` ## Task Commits Each task was committed atomically: 1. **Task 1: Extend Drizzle schema with clients and documents tables** - `f8f8b8f` (feat) 2. **Task 2: Update middleware and auth config to protect /portal routes** - `00f9c7c` (feat) **Plan metadata:** (pending docs commit) ## Files Created/Modified - `teressa-copeland-homes/src/lib/db/schema.ts` - Added pgEnum import, documentStatusEnum, clients table, documents table with FK to clients - `teressa-copeland-homes/drizzle/0001_watery_blindfold.sql` - Migration: CREATE TYPE document_status AS ENUM, CREATE TABLE clients, CREATE TABLE documents with FK constraint - `teressa-copeland-homes/drizzle/meta/0001_snapshot.json` - Drizzle schema snapshot for migration tracking - `teressa-copeland-homes/middleware.ts` - Added "/portal/:path*" to matcher array alongside "/agent/:path*" - `teressa-copeland-homes/src/lib/auth.config.ts` - Added isPortalRoute check in authorized callback; updated post-login redirect to /portal/dashboard - `teressa-copeland-homes/src/app/agent/(protected)/dashboard/page.tsx` - Replaced session-check stub with redirect("/portal/dashboard") ## Decisions Made - `documentStatusEnum` exported before `documents` table in schema.ts — pgEnum must precede the table that references it or drizzle-kit generate may silently omit the CREATE TYPE statement from the migration. - `DATABASE_URL` not auto-loaded from `.env.local` by drizzle-kit (dotenv/config reads `.env` not `.env.local`) — migration was run with explicit `DATABASE_URL=...` env prefix. The Next.js dev server reads `.env.local` correctly so no change needed there. - Portal route protection mirrors the existing `/agent` pattern exactly: new `isPortalRoute` variable, redirect to `/agent/login` on unauthenticated access. ## Deviations from Plan None - plan executed exactly as written. ## Issues Encountered - drizzle-kit `db:migrate` initially failed with "url: undefined" because it uses `dotenv/config` which reads `.env`, not `.env.local`. Resolved by passing `DATABASE_URL` as an explicit env variable prefix to the npm run command. This is a known behavior difference between Next.js (reads .env.local) and drizzle-kit (reads .env). ## User Setup Required None - no external service configuration required. Database is local Docker PostgreSQL already running. ## Next Phase Readiness - `clients` and `documents` tables are live in PostgreSQL; Phase 3 plans 02-04 can reference them immediately - `/portal/*` route protection is active — any new pages added under `/portal/` are automatically protected - Post-login redirect lands on `/portal/dashboard` — ready for the dashboard page to be built in plan 03-02 - No blockers for subsequent Phase 3 plans --- *Phase: 03-agent-portal-shell* *Completed: 2026-03-19* ## Self-Check: PASSED All files verified present. All commits verified in git log.