feat(04-01): multi-project schema migration — projects, settings, FK pivot
- schema.ts: add projects table, settings kv table, slug on clients; migrate 6 FK from client_id to project_id (phases, payments, documents, notes, time_entries, quote_items); update all relations and TypeScript types - admin-queries.ts: fix getAllClientsWithPayments + getClientFullDetail to aggregate through projects; add getAllProjectsWithPayments, getProjectFullDetail, getClientWithProjects, ClientWithProjects type - settings.ts: new file — getSetting, updateSetting, getTargetHourlyRate, SETTINGS_KEYS - Fix all downstream files: actions.ts, quote-actions.ts, new/actions.ts, timer-actions.ts, approve/route.ts, comment/route.ts, TimerCell.tsx, analytics-queries.ts, client-view.ts, seed.ts - DB migration applied to Coolify Postgres (all test data cleared, schema rebuilt) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+23
-10
@@ -1,6 +1,7 @@
|
||||
import { db } from '@/db';
|
||||
import {
|
||||
clients,
|
||||
projects,
|
||||
phases,
|
||||
tasks,
|
||||
deliverables,
|
||||
@@ -29,12 +30,24 @@ async function seed() {
|
||||
|
||||
console.log(`✓ Client created: ${client.name} (ID: ${client.id})`);
|
||||
|
||||
// Create a default project for the client (all work items are project-scoped)
|
||||
const [project] = await db
|
||||
.insert(projects)
|
||||
.values({
|
||||
client_id: client.id,
|
||||
name: client.brand_name,
|
||||
accepted_total: '5000.00',
|
||||
})
|
||||
.returning();
|
||||
|
||||
console.log(`✓ Project created: ${project.name} (ID: ${project.id})`);
|
||||
|
||||
const [phase1, phase2, phase3] = await db
|
||||
.insert(phases)
|
||||
.values([
|
||||
{ client_id: client.id, title: 'Discovery & Strategy', sort_order: 1, status: 'done' },
|
||||
{ client_id: client.id, title: 'Design & Messaging', sort_order: 2, status: 'active' },
|
||||
{ client_id: client.id, title: 'Implementation & Launch', sort_order: 3, status: 'upcoming' },
|
||||
{ project_id: project.id, title: 'Discovery & Strategy', sort_order: 1, status: 'done' },
|
||||
{ project_id: project.id, title: 'Design & Messaging', sort_order: 2, status: 'active' },
|
||||
{ project_id: project.id, title: 'Implementation & Launch', sort_order: 3, status: 'upcoming' },
|
||||
])
|
||||
.returning();
|
||||
|
||||
@@ -68,8 +81,8 @@ async function seed() {
|
||||
await db
|
||||
.insert(payments)
|
||||
.values([
|
||||
{ client_id: client.id, label: 'Acconto 50%', amount: '2500.00', status: 'saldato', paid_at: new Date('2026-04-01') },
|
||||
{ client_id: client.id, label: 'Saldo 50%', amount: '2500.00', status: 'inviata', paid_at: null },
|
||||
{ project_id: project.id, label: 'Acconto 50%', amount: '2500.00', status: 'saldato', paid_at: new Date('2026-04-01') },
|
||||
{ project_id: project.id, label: 'Saldo 50%', amount: '2500.00', status: 'inviata', paid_at: null },
|
||||
]);
|
||||
|
||||
console.log('✓ Payments created (2 total)');
|
||||
@@ -77,8 +90,8 @@ async function seed() {
|
||||
await db
|
||||
.insert(documents)
|
||||
.values([
|
||||
{ client_id: client.id, label: 'Brand Guidelines PDF', url: 'https://example.com/brand-guidelines.pdf' },
|
||||
{ client_id: client.id, label: 'Design Mockups Figma', url: 'https://www.figma.com/file/example' },
|
||||
{ project_id: project.id, label: 'Brand Guidelines PDF', url: 'https://example.com/brand-guidelines.pdf' },
|
||||
{ project_id: project.id, label: 'Design Mockups Figma', url: 'https://www.figma.com/file/example' },
|
||||
]);
|
||||
|
||||
console.log('✓ Documents created (2 total)');
|
||||
@@ -86,15 +99,15 @@ async function seed() {
|
||||
await db
|
||||
.insert(notes)
|
||||
.values([
|
||||
{ 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') },
|
||||
{ client_id: client.id, body: 'Phase 1 approved. Moving forward with design phase. Stakeholders excited about direction.', created_at: new Date('2026-04-22') },
|
||||
{ project_id: project.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') },
|
||||
{ project_id: project.id, body: 'Phase 1 approved. Moving forward with design phase. Stakeholders excited about direction.', created_at: new Date('2026-04-22') },
|
||||
]);
|
||||
|
||||
console.log('✓ Notes created (2 total)');
|
||||
|
||||
console.log('\n✨ Seed complete!\n');
|
||||
console.log('📎 Shareable client link:');
|
||||
console.log(` http://localhost:3000/c/${clientToken}\n`);
|
||||
console.log(` http://localhost:3000/client/${clientToken}\n`);
|
||||
console.log('This link is unique and secret. Send it to the client via Slack or email.\n');
|
||||
|
||||
process.exit(0);
|
||||
|
||||
Reference in New Issue
Block a user