---
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"

---

<objective>
**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.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/research/ARCHITECTURE.md (Data Model section)
@.planning/phases/01-foundation-client-dashboard/01-CONTEXT.md (D-13)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create scripts/seed.ts to insert first real client with all data</name>
  <files>
    scripts/seed.ts
  </files>
  <read_first>
    src/db/schema.ts (all table definitions)
    src/db/index.ts (db client)
  </read_first>
  <action>
    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
  </action>
  <verify>
    <automated>test -f scripts/seed.ts && echo "Seed script exists"</automated>
    <automated>grep -q "import.*nanoid" scripts/seed.ts && echo "nanoid imported"</automated>
    <automated>grep -q "db.insert" scripts/seed.ts && echo "Insert statements present"</automated>
    <automated>grep -q "clientToken" scripts/seed.ts && echo "Token generation present"</automated>
    <automated>grep -q "http://localhost:3000/c/" scripts/seed.ts && echo "URL printed"</automated>
  </verify>
  <acceptance_criteria>
    - `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
  </acceptance_criteria>
</task>

<task type="auto">
  <name>Task 2: Test seed script execution and verify data is inserted into database</name>
  <files>
    None (execution only)
  </files>
  <read_first>
    scripts/seed.ts
    .env.local
  </read_first>
  <action>
    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)
  </action>
  <verify>
    <automated>npx tsx scripts/seed.ts 2>&1 | grep -q "Seed complete" && echo "Seed script succeeded" || echo "Seed script failed"</automated>
    <automated>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"</automated>
  </verify>
  <acceptance_criteria>
    - 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
  </acceptance_criteria>
</task>

<task type="auto">
  <name>Task 3: Test end-to-end: Open seeded client link in browser and verify dashboard renders</name>
  <files>
    None (verification only)
  </files>
  <read_first>
    None
  </read_first>
  <action>
    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
  </action>
  <verify>
    <automated>curl -s http://localhost:3000/c/invalid | grep -q "404\|not found" && echo "Invalid token returns 404" || echo "404 check inconclusive"</automated>
  </verify>
  <acceptance_criteria>
    - 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
  </acceptance_criteria>
</task>

<task type="auto">
  <name>Task 4: Configure DNS CNAME for welcomeclient.iamcavalli.net → Vercel DNS</name>
  <files>
    None (external DNS configuration)
  </files>
  <read_first>
    .planning/phases/01-foundation-client-dashboard/01-CONTEXT.md (D-03)
  </read_first>
  <action>
    **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
  </action>
  <verify>
    <automated>dig welcomeclient.iamcavalli.net +short 2>/dev/null | grep -q "vercel-dns.com" && echo "DNS CNAME configured" || echo "DNS CNAME not yet live"</automated>
  </verify>
  <acceptance_criteria>
    - 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)
  </acceptance_criteria>
</task>

</tasks>

<threat_model>
## 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 |

</threat_model>

<verification>
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
</verification>

<success_criteria>
- 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)
</success_criteria>

<output>
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.
</output>
