feat(01-02): [BLOCKING] drizzle-kit push — schema live on Postgres

- Connected to postgresql://178.104.27.55:5432/clienthub
- 10 tables created: clients, phases, tasks, deliverables, comments,
  payments, documents, notes, service_catalog, quote_items
- UNIQUE constraint on clients.token active at DB level
- All FK constraints and CASCADE rules applied
- Verified via information_schema.tables query
This commit is contained in:
Simone Cavalli
2026-05-13 22:47:51 +02:00
parent a6ec599188
commit abcbb5224e
2 changed files with 208 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
import { relations } from "drizzle-orm/relations";
import { clients, notes, payments, phases, quoteItems, serviceCatalog, documents, tasks, deliverables } from "./schema";
export const notesRelations = relations(notes, ({one}) => ({
client: one(clients, {
fields: [notes.clientId],
references: [clients.id]
}),
}));
export const clientsRelations = relations(clients, ({many}) => ({
notes: many(notes),
payments: many(payments),
phases: many(phases),
quoteItems: many(quoteItems),
documents: many(documents),
}));
export const paymentsRelations = relations(payments, ({one}) => ({
client: one(clients, {
fields: [payments.clientId],
references: [clients.id]
}),
}));
export const phasesRelations = relations(phases, ({one, many}) => ({
client: one(clients, {
fields: [phases.clientId],
references: [clients.id]
}),
tasks: many(tasks),
}));
export const quoteItemsRelations = relations(quoteItems, ({one}) => ({
client: one(clients, {
fields: [quoteItems.clientId],
references: [clients.id]
}),
serviceCatalog: one(serviceCatalog, {
fields: [quoteItems.serviceId],
references: [serviceCatalog.id]
}),
}));
export const serviceCatalogRelations = relations(serviceCatalog, ({many}) => ({
quoteItems: many(quoteItems),
}));
export const documentsRelations = relations(documents, ({one}) => ({
client: one(clients, {
fields: [documents.clientId],
references: [clients.id]
}),
}));
export const tasksRelations = relations(tasks, ({one, many}) => ({
phase: one(phases, {
fields: [tasks.phaseId],
references: [phases.id]
}),
deliverables: many(deliverables),
}));
export const deliverablesRelations = relations(deliverables, ({one}) => ({
task: one(tasks, {
fields: [deliverables.taskId],
references: [tasks.id]
}),
}));
+139
View File
@@ -0,0 +1,139 @@
import { pgTable, foreignKey, text, timestamp, unique, numeric, integer, boolean } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm"
export const notes = pgTable("notes", {
id: text().primaryKey().notNull(),
clientId: text("client_id").notNull(),
body: text().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
}, (table) => [
foreignKey({
columns: [table.clientId],
foreignColumns: [clients.id],
name: "notes_client_id_clients_id_fk"
}).onDelete("cascade"),
]);
export const comments = pgTable("comments", {
id: text().primaryKey().notNull(),
entityType: text("entity_type").notNull(),
entityId: text("entity_id").notNull(),
author: text().notNull(),
body: text().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
});
export const clients = pgTable("clients", {
id: text().primaryKey().notNull(),
name: text().notNull(),
brandName: text("brand_name").notNull(),
brief: text().notNull(),
token: text().notNull(),
acceptedTotal: numeric("accepted_total", { precision: 10, scale: 2 }).default('0'),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
}, (table) => [
unique("clients_token_unique").on(table.token),
]);
export const payments = pgTable("payments", {
id: text().primaryKey().notNull(),
clientId: text("client_id").notNull(),
label: text().notNull(),
amount: numeric({ precision: 10, scale: 2 }).notNull(),
status: text().default('da_saldare').notNull(),
paidAt: timestamp("paid_at", { withTimezone: true, mode: 'string' }),
}, (table) => [
foreignKey({
columns: [table.clientId],
foreignColumns: [clients.id],
name: "payments_client_id_clients_id_fk"
}).onDelete("cascade"),
]);
export const phases = pgTable("phases", {
id: text().primaryKey().notNull(),
clientId: text("client_id").notNull(),
title: text().notNull(),
sortOrder: integer("sort_order").default(0).notNull(),
status: text().default('upcoming').notNull(),
}, (table) => [
foreignKey({
columns: [table.clientId],
foreignColumns: [clients.id],
name: "phases_client_id_clients_id_fk"
}).onDelete("cascade"),
]);
export const quoteItems = pgTable("quote_items", {
id: text().primaryKey().notNull(),
clientId: text("client_id").notNull(),
serviceId: text("service_id").notNull(),
quantity: numeric({ precision: 10, scale: 2 }).notNull(),
unitPrice: numeric("unit_price", { precision: 10, scale: 2 }).notNull(),
subtotal: numeric({ precision: 10, scale: 2 }).notNull(),
}, (table) => [
foreignKey({
columns: [table.clientId],
foreignColumns: [clients.id],
name: "quote_items_client_id_clients_id_fk"
}).onDelete("cascade"),
foreignKey({
columns: [table.serviceId],
foreignColumns: [serviceCatalog.id],
name: "quote_items_service_id_service_catalog_id_fk"
}).onDelete("restrict"),
]);
export const serviceCatalog = pgTable("service_catalog", {
id: text().primaryKey().notNull(),
name: text().notNull(),
description: text(),
unitPrice: numeric("unit_price", { precision: 10, scale: 2 }).notNull(),
active: boolean().default(true).notNull(),
});
export const documents = pgTable("documents", {
id: text().primaryKey().notNull(),
clientId: text("client_id").notNull(),
label: text().notNull(),
url: text().notNull(),
createdAt: timestamp("created_at", { withTimezone: true, mode: 'string' }).defaultNow().notNull(),
}, (table) => [
foreignKey({
columns: [table.clientId],
foreignColumns: [clients.id],
name: "documents_client_id_clients_id_fk"
}).onDelete("cascade"),
]);
export const tasks = pgTable("tasks", {
id: text().primaryKey().notNull(),
phaseId: text("phase_id").notNull(),
title: text().notNull(),
description: text(),
status: text().default('todo').notNull(),
sortOrder: integer("sort_order").default(0).notNull(),
}, (table) => [
foreignKey({
columns: [table.phaseId],
foreignColumns: [phases.id],
name: "tasks_phase_id_phases_id_fk"
}).onDelete("cascade"),
]);
export const deliverables = pgTable("deliverables", {
id: text().primaryKey().notNull(),
taskId: text("task_id").notNull(),
title: text().notNull(),
url: text(),
status: text().default('pending').notNull(),
approvedAt: timestamp("approved_at", { withTimezone: true, mode: 'string' }),
}, (table) => [
foreignKey({
columns: [table.taskId],
foreignColumns: [tasks.id],
name: "deliverables_task_id_tasks_id_fk"
}).onDelete("cascade"),
]);