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:
@@ -4,7 +4,7 @@ import { redirect } from "next/navigation";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { z } from "zod";
|
||||
import { db } from "@/db";
|
||||
import { clients, payments } from "@/db/schema";
|
||||
import { clients, projects, payments } from "@/db/schema";
|
||||
|
||||
const createClientSchema = z.object({
|
||||
name: z.string().min(1, "Nome richiesto"),
|
||||
@@ -21,7 +21,6 @@ export async function createClient(formData: FormData) {
|
||||
|
||||
const parsed = createClientSchema.safeParse(raw);
|
||||
if (!parsed.success) {
|
||||
// In v1 return errors as thrown string — form displays validation inline
|
||||
throw new Error(
|
||||
parsed.error.issues.map((i) => i.message).join(", ")
|
||||
);
|
||||
@@ -35,19 +34,27 @@ export async function createClient(formData: FormData) {
|
||||
brand_name: parsed.data.brand_name,
|
||||
brief: parsed.data.brief,
|
||||
})
|
||||
.returning({ id: clients.id, token: clients.token });
|
||||
.returning({ id: clients.id, token: clients.token, brand_name: clients.brand_name });
|
||||
|
||||
// Always create two payment stubs per client — Acconto 50% and Saldo 50%
|
||||
// Amounts default to 0 until admin sets accepted_total; admin updates separately
|
||||
// Create a default project for the client — all work items are project-scoped
|
||||
const [newProject] = await db
|
||||
.insert(projects)
|
||||
.values({
|
||||
client_id: newClient.id,
|
||||
name: newClient.brand_name,
|
||||
})
|
||||
.returning({ id: projects.id });
|
||||
|
||||
// Always create two payment stubs per project — Acconto 50% and Saldo 50%
|
||||
await db.insert(payments).values([
|
||||
{
|
||||
client_id: newClient.id,
|
||||
project_id: newProject.id,
|
||||
label: "Acconto 50%",
|
||||
amount: "0",
|
||||
status: "da_saldare",
|
||||
},
|
||||
{
|
||||
client_id: newClient.id,
|
||||
project_id: newProject.id,
|
||||
label: "Saldo 50%",
|
||||
amount: "0",
|
||||
status: "da_saldare",
|
||||
|
||||
Reference in New Issue
Block a user