--- phase: "01-foundation-client-dashboard" plan: 05 type: execute wave: 3 depends_on: - "01-01" - "01-02" - "01-03" - "01-04" files_modified: - scripts/seed.ts - .env.local autonomous: true requirements: - DASH-01 - DASH-02 - DASH-03 - DASH-04 - DASH-07 - DASH-08 - DASH-09 - DASH-10 must_haves: truths: - "Seed script exists and contains TypeScript seed logic" - "Script inserts one complete test client with all related data (phases, tasks, deliverables, payments, documents, notes)" - "Client token is generated via nanoid (21 chars, cryptographically secure)" - "Seed script prints shareable URL to console: http://localhost:3000/c/[token]" - "Script can be run via: npx tsx scripts/seed.ts" - "DNS CNAME is configured: welcomeclient.iamcavalli.net → vercel DNS" - "DNS propagation is verified (can be checked via `dig` or online tool)" artifacts: - path: "scripts/seed.ts" provides: "Seed script that inserts first real client with all data" min_lines: 100 contains: "import.*nanoid" - path: ".env.local (updated)" provides: "Updated with VERCEL_URL or custom domain setting" contains: "DATABASE_URL" key_links: - from: "scripts/seed.ts" to: "src/db/schema" via: "drizzle db.insert()" pattern: "db.insert\\(" - from: "nanoid token" to: "client URL" via: "http://localhost:3000/c/[token]" pattern: "nanoid" --- **Seed Script + DNS Configuration:** Create a TypeScript seed script that populates the database with one complete test client (including phases, tasks, deliverables, payments, documents, and notes), generates a secret token via nanoid, and prints a shareable dashboard URL. Configure DNS CNAME for welcomeclient.iamcavalli.net to Vercel and verify propagation. Purpose: Enable end-to-end testing with real data. One developer can run the seed script and immediately open a working client dashboard. DNS configuration allows the project to be accessed via the production domain. Output: Executable seed script + verified DNS CNAME + shareable client link for testing Phase 1. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/research/ARCHITECTURE.md (Data Model section) @.planning/phases/01-foundation-client-dashboard/01-CONTEXT.md (D-13) Task 1: Create scripts/seed.ts to insert first real client with all data scripts/seed.ts src/db/schema.ts (all table definitions) src/db/index.ts (db client) Create `scripts/seed.ts`: ```typescript /** * Seed Script — Inserts first test client with complete project data * Run: npx tsx scripts/seed.ts */ import { db } from '@/db'; import { clients, phases, tasks, deliverables, payments, documents, notes, } from '@/db/schema'; import { nanoid } from 'nanoid'; async function seed() { console.log('🌱 Seeding database...\n'); try { // 1. Create client const clientToken = nanoid(); const [client] = await db .insert(clients) .values({ id: nanoid(), name: 'Test Client Inc.', brand_name: 'TestBrand', brief: 'A comprehensive personal branding overhaul, positioning our company as a premium consultancy in the digital transformation space.', token: clientToken, accepted_total: '5000.00', created_at: new Date(), }) .returning(); console.log( 'āœ“ Client created: ' + client.name + ' (ID: ' + client.id + ')' ); // 2. Create phases const [phase1, phase2, phase3] = await db .insert(phases) .values([ { id: nanoid(), client_id: client.id, title: 'Discovery & Strategy', sort_order: 1, status: 'done', }, { id: nanoid(), client_id: client.id, title: 'Design & Messaging', sort_order: 2, status: 'active', }, { id: nanoid(), client_id: client.id, title: 'Implementation & Launch', sort_order: 3, status: 'upcoming', }, ]) .returning(); console.log('āœ“ Phases created (3 total)'); // 3. Create tasks const [task1, task2, task3, task4, task5, task6] = await db .insert(tasks) .values([ { id: nanoid(), phase_id: phase1.id, title: 'Stakeholder interviews', description: 'In-depth conversations with leadership team', sort_order: 1, status: 'done', }, { id: nanoid(), phase_id: phase1.id, title: 'Competitive analysis', description: 'Research top 10 competitors in the space', sort_order: 2, status: 'done', }, { id: nanoid(), phase_id: phase2.id, title: 'Brand positioning document', description: 'Write and refine the core positioning statement', sort_order: 1, status: 'in_progress', }, { id: nanoid(), phase_id: phase2.id, title: 'Visual identity design', description: 'Logo, color palette, typography', sort_order: 2, status: 'in_progress', }, { id: nanoid(), phase_id: phase3.id, title: 'Website build & launch', description: 'Design and develop new company website', sort_order: 1, status: 'todo', }, { id: nanoid(), phase_id: phase3.id, title: 'Social media rollout', description: 'Launch branded social media accounts', sort_order: 2, status: 'todo', }, ]) .returning(); console.log('āœ“ Tasks created (6 total)'); // 4. Create deliverables await db .insert(deliverables) .values([ { id: nanoid(), task_id: task1.id, title: 'Interview notes & synthesis', url: 'https://docs.google.com/document/d/1example', status: 'approved', approved_at: new Date('2026-04-15'), }, { id: nanoid(), task_id: task2.id, title: 'Competitive landscape report', url: 'https://docs.google.com/presentation/d/1example', status: 'approved', approved_at: new Date('2026-04-20'), }, { id: nanoid(), task_id: task3.id, title: 'Brand positioning document (draft)', url: 'https://docs.google.com/document/d/2example', status: 'submitted', approved_at: null, }, { id: nanoid(), task_id: task4.id, title: 'Logo concepts (3 variations)', url: 'https://www.figma.com/file/example', status: 'pending', approved_at: null, }, ]) .returning(); console.log('āœ“ Deliverables created (4 total)'); // 5. Create payments await db .insert(payments) .values([ { id: nanoid(), client_id: client.id, label: 'Acconto 50%', amount: '2500.00', status: 'saldato', paid_at: new Date('2026-04-01'), }, { id: nanoid(), client_id: client.id, label: 'Saldo 50%', amount: '2500.00', status: 'inviata', paid_at: null, }, ]) .returning(); console.log('āœ“ Payments created (2 total)'); // 6. Create documents await db .insert(documents) .values([ { id: nanoid(), client_id: client.id, label: 'Brand Guidelines PDF', url: 'https://example.com/brand-guidelines.pdf', created_at: new Date(), }, { id: nanoid(), client_id: client.id, label: 'Design Mockups Figma', url: 'https://www.figma.com/file/example', created_at: new Date(), }, ]) .returning(); console.log('āœ“ Documents created (2 total)'); // 7. Create notes await db .insert(notes) .values([ { id: nanoid(), client_id: client.id, body: 'Initial strategy session completed. Key insight: positioning needs to emphasize tech expertise and creative thinking balance.', created_at: new Date('2026-04-10'), }, { id: nanoid(), client_id: client.id, body: 'Phase 1 approved. Moving forward with design phase. Stakeholders excited about direction.', created_at: new Date('2026-04-22'), }, ]) .returning(); console.log('āœ“ Notes created (2 total)'); // Print shareable URL console.log('\n✨ Seed complete!\n'); console.log('šŸ“Ž Shareable client link:'); console.log( ` http://localhost:3000/c/${clientToken}\n` ); console.log( 'This link is unique and secret. Send it to the client via Slack or email.\n' ); } catch (error) { console.error('āŒ Seed failed:', error); process.exit(1); } } seed(); ``` Key points: - Uses nanoid for token generation (21 chars, cryptographically secure) - Inserts complete hierarchical data: 1 client → 3 phases → 6 tasks → 4 deliverables + 2 payments + 2 documents + 2 notes - Mix of statuses: phase 1 done, phase 2 active, phase 3 upcoming; tasks have various completion states - Deliverables show different statuses: approved (with timestamp), submitted, pending - Payments: one paid, one sent but unpaid - Notes: 2 decision log entries - Prints shareable URL to console test -f scripts/seed.ts && echo "Seed script exists" grep -q "import.*nanoid" scripts/seed.ts && echo "nanoid imported" grep -q "db.insert" scripts/seed.ts && echo "Insert statements present" grep -q "clientToken" scripts/seed.ts && echo "Token generation present" grep -q "http://localhost:3000/c/" scripts/seed.ts && echo "URL printed" - `scripts/seed.ts` exists as TypeScript file - Script imports nanoid and db client - Creates one complete client with all related data (phases, tasks, deliverables, payments, documents, notes) - Prints shareable URL to console - Can be executed via `npx tsx scripts/seed.ts` without errors Task 2: Test seed script execution and verify data is inserted into database None (execution only) scripts/seed.ts .env.local Run the seed script: ``` npx tsx scripts/seed.ts ``` Expected output: ``` 🌱 Seeding database... āœ“ Client created: Test Client Inc. (ID: xxx...) āœ“ Phases created (3 total) āœ“ Tasks created (6 total) āœ“ Deliverables created (4 total) āœ“ Payments created (2 total) āœ“ Documents created (2 total) āœ“ Notes created (2 total) ✨ Seed complete! šŸ“Ž Shareable client link: http://localhost:3000/c/[token] This link is unique and secret. Send it to the client via Slack or email. ``` If the script fails: - Verify DATABASE_URL is set and correct - Verify Postgres on Coolify is accessible - Check that schema exists (run `npx drizzle-kit introspect` to confirm) npx tsx scripts/seed.ts 2>&1 | grep -q "Seed complete" && echo "Seed script succeeded" || echo "Seed script failed" npx tsx scripts/seed.ts 2>&1 | grep -oE "http://localhost:3000/c/[a-zA-Z0-9_-]+" | head -1 > /tmp/client_url.txt && test -s /tmp/client_url.txt && echo "Client URL generated" || echo "Client URL not found" - Seed script executes without errors - Output shows all entity types created (client, phases, tasks, deliverables, payments, documents, notes) - Shareable URL is printed to console - Data is inserted into Postgres on Coolify Task 3: Test end-to-end: Open seeded client link in browser and verify dashboard renders None (verification only) None Start dev server: ``` npm run dev ``` Open the seeded client link in browser: - Copy the URL from seed script output (e.g., http://localhost:3000/c/xyz123) - Visit in browser - Verify dashboard renders with: - āœ“ Client brand name displayed prominently - āœ“ iamcavalli logo in corner - āœ“ Global progress bar showing % completion - āœ“ All 3 phases visible with status badges (done/active/upcoming) - āœ“ Each phase shows progress bar and task count - āœ“ Tasks nested under phases with status icons - āœ“ Deliverables shown under tasks (with Approved badge if applicable) - āœ“ Payment section shows accepted_total (€5000.00) and 2 payment rows - āœ“ Payment amounts are NOT visible (only status: saldato, inviata) - āœ“ Document section shows clickable links - āœ“ Notes section shows decision log entries Test edge cases: - Invalid token (http://localhost:3000/c/invalid) → should return 404 - Page refresh → data should persist (no client-side state loss) - Mobile view (use DevTools mobile emulator) → layout should be responsive curl -s http://localhost:3000/c/invalid | grep -q "404\|not found" && echo "Invalid token returns 404" || echo "404 check inconclusive" - Seeded client link opens without errors - Dashboard renders with client data - All sections visible: header, progress, phases, tasks, deliverables, payments, documents, notes - Invalid token returns 404 - Layout is responsive on mobile Task 4: Configure DNS CNAME for welcomeclient.iamcavalli.net → Vercel DNS None (external DNS configuration) .planning/phases/01-foundation-client-dashboard/01-CONTEXT.md (D-03) **DNS Configuration Steps:** 1. Log into your domain registrar (where iamcavalli.net is registered) 2. Navigate to DNS settings for iamcavalli.net 3. Create a new CNAME record: - **Name:** welcomeclient - **Type:** CNAME - **Value:** cname.vercel-dns.com - **TTL:** 3600 (or default) 4. Save the record 5. Verify propagation (may take 15 minutes to 2 hours): ``` dig welcomeclient.iamcavalli.net ``` You should see: ``` welcomeclient.iamcavalli.net. 3600 IN CNAME cname.vercel-dns.com. ``` Or use an online tool: https://mxtoolbox.com/cname.aspx **Vercel Configuration:** 1. Go to Vercel dashboard → Project Settings → Domains 2. Add domain: `welcomeclient.iamcavalli.net` 3. Vercel will show the CNAME record to configure (should match above) 4. Click "Add" and wait for verification (usually immediate after DNS propagates) **After DNS is live:** - You can access the dashboard via https://welcomeclient.iamcavalli.net/c/[token] - DNS is bidirectional: localhost:3000 still works for dev dig welcomeclient.iamcavalli.net +short 2>/dev/null | grep -q "vercel-dns.com" && echo "DNS CNAME configured" || echo "DNS CNAME not yet live" - CNAME record is created at registrar: welcomeclient → cname.vercel-dns.com - Vercel project has the domain added and verified - `dig` shows the CNAME record pointing to Vercel DNS - Domain is accessible via browser (may take time to propagate) ## Trust Boundaries | Boundary | Description | |----------|-------------| | Client browser → Secret link | Token is in URL; HTTPS encrypts transit; never log token in server logs | | Token generation | nanoid is cryptographically secure (126 bits entropy); non-enumerable | | DNS configuration | CNAME points to Vercel; Vercel controls SSL/TLS for domain | ## STRIDE Threat Register | Threat ID | Category | Component | Disposition | Mitigation Plan | |-----------|----------|-----------|-------------|-----------------| | T-05-001 | Information Disclosure | Token in seed output | mitigate | URL is printed to console; developer must not commit or share the seed output; regenerate token in Phase 2 if compromised | | T-05-002 | Information Disclosure | HTTPS for domain | mitigate | Vercel automatically provisions SSL/TLS for custom domain; all traffic to welcomeclient.iamcavalli.net is encrypted | | T-05-003 | Denial of Service | Seed script re-run | accept | Running seed script multiple times creates duplicate clients (same test data); acceptable for dev; Phase 2 adds admin UI to manage clients | After plan execution: 1. Run `npx tsx scripts/seed.ts` → output shows "Seed complete!" 2. Copy the printed URL and visit in browser 3. Verify dashboard renders with seeded data 4. Test invalid token → 404 5. Verify DNS CNAME is live: `dig welcomeclient.iamcavalli.net` 6. (Optional) Visit https://welcomeclient.iamcavalli.net/c/[token] once DNS propagates - Seed script exists and inserts complete test data - One client with 3 phases, 6 tasks, 4 deliverables, 2 payments, 2 documents, 2 notes - Dashboard renders with seeded data via shareable link - Invalid tokens return 404 - DNS CNAME is configured and verified - Phase 1 is complete and ready for production (Phase 2 will add auth and CRUD) After completion, create `.planning/phases/01-foundation-client-dashboard/01-05-SUMMARY.md` Also update `.planning/ROADMAP.md` to mark Phase 1 complete and set up Phase 2 planning.