From 19db774c4c3dcf442c27a9dfb9980b45e01939c5 Mon Sep 17 00:00:00 2001 From: DeeCee03 Date: Sat, 6 Jun 2026 16:08:59 +0200 Subject: [PATCH] =?UTF-8?q?feat(leads):=20Leads=20universell=20mit=20Proje?= =?UTF-8?q?kten=20verkn=C3=BCpfen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ein Projekt lebt in genau einem Heimat-Bereich und wird einmal angelegt; Leads bekommen eine optionale Verknüpfung dorthin (lead.projectId), egal in welchem Bereich das Projekt wohnt — kein redundantes Anlegen mehr. - Migration 0011: lead.project_id (FK → project, ON DELETE SET NULL). - Lead anlegen / CSV-Import / Lead-Detail: Projekt zuordnen; CSV ordnet alle importierten Leads einem Projekt zu. - Projektseite: neue "Leads"-Sektion (Vertriebs-Sicht des Projekts). - Vertrieb: "Projekte mit Vertriebsaktivität" — bereichsübergreifend alle Projekte mit verknüpften Leads (so erscheint ein Entwicklungsprojekt hier, WEIL es Leads hat). Rein interne Projekte ohne Leads tauchen nicht auf. - Lead-Liste/Detail zeigen das verknüpfte Projekt. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/api/src/routers/lead.ts | 29 +- apps/web/src/routes/bereich.tsx | 39 + apps/web/src/routes/lead.tsx | 26 + apps/web/src/routes/leads.tsx | 41 +- apps/web/src/routes/projekt.tsx | 97 + .../db/migrations/0011_lead_project_link.sql | 3 + .../db/migrations/meta/0011_snapshot.json | 3273 +++++++++++++++++ packages/db/migrations/meta/_journal.json | 7 + packages/db/src/schema.ts | 5 + packages/shared/src/schemas/lead.ts | 5 + 10 files changed, 3522 insertions(+), 3 deletions(-) create mode 100644 packages/db/migrations/0011_lead_project_link.sql create mode 100644 packages/db/migrations/meta/0011_snapshot.json diff --git a/apps/api/src/routers/lead.ts b/apps/api/src/routers/lead.ts index b652c76..d4742c8 100644 --- a/apps/api/src/routers/lead.ts +++ b/apps/api/src/routers/lead.ts @@ -1,6 +1,6 @@ import { TRPCError } from '@trpc/server'; import { asc, desc, eq, sql } from 'drizzle-orm'; -import { lead, leadContact, leadTouchpoint, deal, area, user } from '@cockpit/db'; +import { lead, leadContact, leadTouchpoint, deal, area, user, project } from '@cockpit/db'; import type { Db } from '@cockpit/db'; import { LeadSchemas } from '@cockpit/shared'; import { router, protectedProcedure } from '../trpc.js'; @@ -21,13 +21,28 @@ export const leadRouter = router({ .select({ lead: lead, ownerName: user.name, + projectName: project.name, }) .from(lead) .leftJoin(user, eq(user.id, lead.ownerUserId)) + .leftJoin(project, eq(project.id, lead.projectId)) .orderBy(desc(lead.updatedAt)); - return rows.map((r) => ({ ...r.lead, ownerName: r.ownerName })); + return rows.map((r) => ({ ...r.lead, ownerName: r.ownerName, projectName: r.projectName })); }), + // Leads, die einem Projekt zugeordnet sind (Vertriebs-Sicht im Projekt). + forProject: protectedProcedure + .input(LeadSchemas.leadsForProjectInput) + .query(async ({ ctx, input }) => { + const rows = await ctx.db + .select({ lead: lead, ownerName: user.name }) + .from(lead) + .leftJoin(user, eq(user.id, lead.ownerUserId)) + .where(eq(lead.projectId, input.projectId)) + .orderBy(desc(lead.score), desc(lead.updatedAt)); + return rows.map((r) => ({ ...r.lead, ownerName: r.ownerName })); + }), + byId: protectedProcedure.input(LeadSchemas.leadIdInput).query(async ({ ctx, input }) => { const l = (await ctx.db.select().from(lead).where(eq(lead.id, input.id)).limit(1))[0]; if (!l) throw new TRPCError({ code: 'NOT_FOUND', message: 'Lead nicht gefunden.' }); @@ -45,9 +60,17 @@ export const leadRouter = router({ .leftJoin(user, eq(user.id, leadTouchpoint.bearbeiterUserId)) .where(eq(leadTouchpoint.leadId, l.id)) .orderBy(desc(leadTouchpoint.datum), desc(leadTouchpoint.createdAt)); + const linkedProject = l.projectId + ? (await ctx.db + .select({ id: project.id, name: project.name }) + .from(project) + .where(eq(project.id, l.projectId)) + .limit(1))[0] ?? null + : null; return { lead: l, contacts, + project: linkedProject, touchpoints: touchpoints.map((t) => ({ ...t.touchpoint, bearbeiterName: t.bearbeiterName })), }; }), @@ -64,6 +87,7 @@ export const leadRouter = router({ status: input.status, score: input.score, ownerUserId: input.ownerUserId ?? null, + projectId: input.projectId ?? null, branche: input.branche ?? null, subSegment: input.subSegment ?? null, website: input.website ?? null, @@ -259,6 +283,7 @@ export const leadRouter = router({ firma, status: 'cold', score: 0, + projectId: input.projectId ?? null, branche: get(row, cells.branche) || null, website: get(row, cells.website) || null, quelle: get(row, cells.quelle) || null, diff --git a/apps/web/src/routes/bereich.tsx b/apps/web/src/routes/bereich.tsx index da68f0a..c6999fd 100644 --- a/apps/web/src/routes/bereich.tsx +++ b/apps/web/src/routes/bereich.tsx @@ -327,11 +327,50 @@ function VertriebDetail() { return (
+
); } +// Bereichsübergreifend: Projekte (egal aus welchem Bereich), die verknüpfte +// Leads haben — so taucht z. B. ein Entwicklungsprojekt hier auf, WEIL es +// Vertriebsaktivität hat, ohne redundant angelegt werden zu müssen. +function ProjekteMitLeads() { + const q = trpc.lead.list.useQuery(); + const leads = q.data ?? []; + const map = new Map(); + for (const l of leads) { + if (!l.projectId || !l.projectName) continue; + const e = map.get(l.projectId) ?? { id: l.projectId, name: l.projectName, total: 0, open: 0 }; + e.total++; + if (l.status !== 'won' && l.status !== 'lost') e.open++; + map.set(l.projectId, e); + } + const projects = Array.from(map.values()).sort((a, b) => b.open - a.open); + if (projects.length === 0) return null; + return ( +
+

Projekte mit Vertriebsaktivität

+
+ {projects.map((p) => ( + + + +

{p.name}

+ + {p.total} {p.total === 1 ? 'Lead' : 'Leads'} + {p.open > 0 && ` · ${p.open} offen`} + +
+
+ + ))} +
+
+ ); +} + function LeadsTeaser() { const q = trpc.lead.list.useQuery(); const leads = q.data ?? []; diff --git a/apps/web/src/routes/lead.tsx b/apps/web/src/routes/lead.tsx index c896618..2d839bf 100644 --- a/apps/web/src/routes/lead.tsx +++ b/apps/web/src/routes/lead.tsx @@ -184,6 +184,8 @@ function Header({ lead, onBack }: { lead: LeadDossier; onBack: () => void }) { }); const users = trpc.user.list.useQuery(); + const projectsQ = trpc.project.list.useQuery(); + const projects = (projectsQ.data ?? []).map((r) => ({ id: r.project.id, name: r.project.name })); const meta = LEAD_STATUS_META[lead.status as LeadStatus]; return ( @@ -307,6 +309,30 @@ function Header({ lead, onBack }: { lead: LeadDossier; onBack: () => void }) { ))} + + {promoteOpen && setPromoteOpen(false)} />} diff --git a/apps/web/src/routes/leads.tsx b/apps/web/src/routes/leads.tsx index 5900a1f..52172b6 100644 --- a/apps/web/src/routes/leads.tsx +++ b/apps/web/src/routes/leads.tsx @@ -81,6 +81,9 @@ export function LeadsRoute() { } function LeadImportDialog({ onClose }: { onClose: () => void }) { + const projectsQ = trpc.project.list.useQuery(); + const projects = (projectsQ.data ?? []).map((r) => ({ id: r.project.id, name: r.project.name })); + const [projectId, setProjectId] = useState(''); const [fileName, setFileName] = useState(''); const [csv, setCsv] = useState(''); const [result, setResult] = useState<{ @@ -124,6 +127,22 @@ function LeadImportDialog({ onClose }: { onClose: () => void }) {

+
{sub &&

{sub}

} + {lead.projectName && ( +

+ ↳ {lead.projectName} +

+ )}
{lead.ownerName ?? 'ohne Owner'} Score {lead.score}/10 @@ -217,12 +242,15 @@ function LeadCard({ function LeadCreateDialog({ onClose }: { onClose: () => void }) { const users = trpc.user.list.useQuery(); + const projectsQ = trpc.project.list.useQuery(); + const projects = (projectsQ.data ?? []).map((r) => ({ id: r.project.id, name: r.project.name })); const [firma, setFirma] = useState(''); const [branche, setBranche] = useState(''); const [subSegment, setSubSegment] = useState(''); const [website, setWebsite] = useState(''); const [quelle, setQuelle] = useState(''); const [ownerUserId, setOwnerUserId] = useState(''); + const [projectId, setProjectId] = useState(''); const [status, setStatus] = useState('cold'); const [score, setScore] = useState(0); @@ -245,6 +273,7 @@ function LeadCreateDialog({ onClose }: { onClose: () => void }) { website: website.trim() || undefined, quelle: quelle.trim() || undefined, ownerUserId: ownerUserId || undefined, + projectId: projectId || undefined, status, score, }); @@ -287,6 +316,16 @@ function LeadCreateDialog({ onClose }: { onClose: () => void }) { setQuelle(e.target.value)} className={inputCls} /> + + +
setFirma(e.target.value)} + placeholder="Firma / Lead-Name" + className={inputCls} + /> + + + + )} + + + ); +} + // --- Risiken & Chancen ------------------------------------------------------ function RisksSection({ projectId }: { projectId: string }) { const q = trpc.risk.forProject.useQuery({ projectId }); diff --git a/packages/db/migrations/0011_lead_project_link.sql b/packages/db/migrations/0011_lead_project_link.sql new file mode 100644 index 0000000..f7a8b2f --- /dev/null +++ b/packages/db/migrations/0011_lead_project_link.sql @@ -0,0 +1,3 @@ +ALTER TABLE "lead" ADD COLUMN "project_id" uuid;--> statement-breakpoint +ALTER TABLE "lead" ADD CONSTRAINT "lead_project_id_project_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."project"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "idx_lead_project" ON "lead" USING btree ("project_id"); \ No newline at end of file diff --git a/packages/db/migrations/meta/0011_snapshot.json b/packages/db/migrations/meta/0011_snapshot.json new file mode 100644 index 0000000..baceb8e --- /dev/null +++ b/packages/db/migrations/meta/0011_snapshot.json @@ -0,0 +1,3273 @@ +{ + "id": "889e7b03-a663-4313-b641-80e8ab7373cf", + "prevId": "e67fd875-96b6-47cd-be5a-e5bb25c625dd", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.absence_day": { + "name": "absence_day", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_absence_user_date": { + "name": "uniq_absence_user_date", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "absence_day_user_id_user_id_fk": { + "name": "absence_day_user_id_user_id_fk", + "tableFrom": "absence_day", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.area": { + "name": "area", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_area_slug": { + "name": "uniq_area_slug", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_event": { + "name": "audit_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_kind": { + "name": "entity_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_audit_event_actor": { + "name": "idx_audit_event_actor", + "columns": [ + { + "expression": "actor_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_audit_event_action": { + "name": "idx_audit_event_action", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_audit_event_entity": { + "name": "idx_audit_event_entity", + "columns": [ + { + "expression": "entity_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_event_actor_user_id_user_id_fk": { + "name": "audit_event_actor_user_id_user_id_fk", + "tableFrom": "audit_event", + "tableTo": "user", + "columnsFrom": [ + "actor_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.blocker": { + "name": "blocker", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "opened_by": { + "name": "opened_by", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "opened_at": { + "name": "opened_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resolved_by": { + "name": "resolved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "resolved_at": { + "name": "resolved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "resolution_text": { + "name": "resolution_text", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_blocker_area": { + "name": "idx_blocker_area", + "columns": [ + { + "expression": "area_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_blocker_project": { + "name": "idx_blocker_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_blocker_opened_at": { + "name": "idx_blocker_opened_at", + "columns": [ + { + "expression": "opened_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "blocker_owner_user_id_user_id_fk": { + "name": "blocker_owner_user_id_user_id_fk", + "tableFrom": "blocker", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "blocker_opened_by_user_id_fk": { + "name": "blocker_opened_by_user_id_fk", + "tableFrom": "blocker", + "tableTo": "user", + "columnsFrom": [ + "opened_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "blocker_resolved_by_user_id_fk": { + "name": "blocker_resolved_by_user_id_fk", + "tableFrom": "blocker", + "tableTo": "user", + "columnsFrom": [ + "resolved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.campaign": { + "name": "campaign", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "reach": { + "name": "reach", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_campaign_status": { + "name": "idx_campaign_status", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "campaign_area_id_area_id_fk": { + "name": "campaign_area_id_area_id_fk", + "tableFrom": "campaign", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "campaign_owner_user_id_user_id_fk": { + "name": "campaign_owner_user_id_user_id_fk", + "tableFrom": "campaign", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.change_entry": { + "name": "change_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "titel": { + "name": "titel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auswirkung": { + "name": "auswirkung", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "entscheidung": { + "name": "entscheidung", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'offen'" + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_change_entry_project": { + "name": "idx_change_entry_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "change_entry_project_id_project_id_fk": { + "name": "change_entry_project_id_project_id_fk", + "tableFrom": "change_entry", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "change_entry_created_by_user_id_fk": { + "name": "change_entry_created_by_user_id_fk", + "tableFrom": "change_entry", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.day_entry": { + "name": "day_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "checked_in_at": { + "name": "checked_in_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "reflected_at": { + "name": "reflected_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "reflection_text": { + "name": "reflection_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ampel": { + "name": "ampel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trend": { + "name": "trend", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blocker_id": { + "name": "blocker_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "edit_locked_at": { + "name": "edit_locked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_day_entry_user_date": { + "name": "uniq_day_entry_user_date", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_day_entry_date": { + "name": "idx_day_entry_date", + "columns": [ + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_day_entry_published_at": { + "name": "idx_day_entry_published_at", + "columns": [ + { + "expression": "published_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "day_entry_user_id_user_id_fk": { + "name": "day_entry_user_id_user_id_fk", + "tableFrom": "day_entry", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal": { + "name": "deal", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value_eur": { + "name": "value_eur", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "probability": { + "name": "probability", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 50 + }, + "stage": { + "name": "stage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entered_stage_at": { + "name": "entered_stage_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "won_at": { + "name": "won_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "won_value_eur": { + "name": "won_value_eur", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_stage": { + "name": "idx_deal_stage", + "columns": [ + { + "expression": "stage", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_owner": { + "name": "idx_deal_owner", + "columns": [ + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_area_id_area_id_fk": { + "name": "deal_area_id_area_id_fk", + "tableFrom": "deal", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "deal_owner_user_id_user_id_fk": { + "name": "deal_owner_user_id_user_id_fk", + "tableFrom": "deal", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gtm_step": { + "name": "gtm_step", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "product": { + "name": "product", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_gtm_product": { + "name": "idx_gtm_product", + "columns": [ + { + "expression": "product", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "gtm_step_owner_user_id_user_id_fk": { + "name": "gtm_step_owner_user_id_user_id_fk", + "tableFrom": "gtm_step", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead": { + "name": "lead", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "firma": { + "name": "firma", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'cold'" + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "branche": { + "name": "branche", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sub_segment": { + "name": "sub_segment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "standorte": { + "name": "standorte", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mitarbeiterzahl": { + "name": "mitarbeiterzahl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "umsatz": { + "name": "umsatz", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quelle": { + "name": "quelle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pain_point": { + "name": "pain_point", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_quo_kosten": { + "name": "status_quo_kosten", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bestehende_loesung": { + "name": "bestehende_loesung", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wechselgrund": { + "name": "wechselgrund", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "persoenlicher_erfolg": { + "name": "persoenlicher_erfolg", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "budget_indikation": { + "name": "budget_indikation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "entscheidungshorizont": { + "name": "entscheidungshorizont", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "compelling_event": { + "name": "compelling_event", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mitbewerber": { + "name": "mitbewerber", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buying_center": { + "name": "buying_center", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "beschaffungsweg": { + "name": "beschaffungsweg", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kommunikationsstil": { + "name": "kommunikationsstil", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vorlieben": { + "name": "vorlieben", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hot_buttons": { + "name": "hot_buttons", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "no_gos": { + "name": "no_gos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "druckpunkte": { + "name": "druckpunkte", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "anker": { + "name": "anker", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vertrauenslevel": { + "name": "vertrauenslevel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "nutzen_hypothese": { + "name": "nutzen_hypothese", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "differenzierer": { + "name": "differenzierer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "naechster_schritt": { + "name": "naechster_schritt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "naechster_schritt_datum": { + "name": "naechster_schritt_datum", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "risiken": { + "name": "risiken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_b": { + "name": "plan_b", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "offene_fragen": { + "name": "offene_fragen", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "anhaenge": { + "name": "anhaenge", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "promoted_deal_id": { + "name": "promoted_deal_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_lead_status": { + "name": "idx_lead_status", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_lead_owner": { + "name": "idx_lead_owner", + "columns": [ + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_lead_project": { + "name": "idx_lead_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lead_area_id_area_id_fk": { + "name": "lead_area_id_area_id_fk", + "tableFrom": "lead", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "lead_project_id_project_id_fk": { + "name": "lead_project_id_project_id_fk", + "tableFrom": "lead", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_owner_user_id_user_id_fk": { + "name": "lead_owner_user_id_user_id_fk", + "tableFrom": "lead", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_promoted_deal_id_deal_id_fk": { + "name": "lead_promoted_deal_id_deal_id_fk", + "tableFrom": "lead", + "tableTo": "deal", + "columnsFrom": [ + "promoted_deal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_created_by_user_id_fk": { + "name": "lead_created_by_user_id_fk", + "tableFrom": "lead", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead_contact": { + "name": "lead_contact", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "lead_id": { + "name": "lead_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rolle": { + "name": "rolle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "funktion": { + "name": "funktion", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telefon": { + "name": "telefon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linkedin": { + "name": "linkedin", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "im_buying_center_seit": { + "name": "im_buying_center_seit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sprache": { + "name": "sprache", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_lead_contact_lead": { + "name": "idx_lead_contact_lead", + "columns": [ + { + "expression": "lead_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lead_contact_lead_id_lead_id_fk": { + "name": "lead_contact_lead_id_lead_id_fk", + "tableFrom": "lead_contact", + "tableTo": "lead", + "columnsFrom": [ + "lead_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead_handover": { + "name": "lead_handover", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "campaign_id": { + "name": "campaign_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "deal_id": { + "name": "deal_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "uebergeben_am": { + "name": "uebergeben_am", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "uebergeben_von": { + "name": "uebergeben_von", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "lead_handover_campaign_id_campaign_id_fk": { + "name": "lead_handover_campaign_id_campaign_id_fk", + "tableFrom": "lead_handover", + "tableTo": "campaign", + "columnsFrom": [ + "campaign_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_handover_deal_id_deal_id_fk": { + "name": "lead_handover_deal_id_deal_id_fk", + "tableFrom": "lead_handover", + "tableTo": "deal", + "columnsFrom": [ + "deal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_handover_uebergeben_von_user_id_fk": { + "name": "lead_handover_uebergeben_von_user_id_fk", + "tableFrom": "lead_handover", + "tableTo": "user", + "columnsFrom": [ + "uebergeben_von" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead_touchpoint": { + "name": "lead_touchpoint", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "lead_id": { + "name": "lead_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "datum": { + "name": "datum", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "kanal": { + "name": "kanal", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bearbeiter_user_id": { + "name": "bearbeiter_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "inhalt": { + "name": "inhalt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "follow_up_bis": { + "name": "follow_up_bis", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_lead_touchpoint_lead": { + "name": "idx_lead_touchpoint_lead", + "columns": [ + { + "expression": "lead_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_lead_touchpoint_followup": { + "name": "idx_lead_touchpoint_followup", + "columns": [ + { + "expression": "follow_up_bis", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lead_touchpoint_lead_id_lead_id_fk": { + "name": "lead_touchpoint_lead_id_lead_id_fk", + "tableFrom": "lead_touchpoint", + "tableTo": "lead", + "columnsFrom": [ + "lead_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "lead_touchpoint_bearbeiter_user_id_user_id_fk": { + "name": "lead_touchpoint_bearbeiter_user_id_user_id_fk", + "tableFrom": "lead_touchpoint", + "tableTo": "user", + "columnsFrom": [ + "bearbeiter_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.milestone": { + "name": "milestone", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "due": { + "name": "due", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ergebnis": { + "name": "ergebnis", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kundennutzen": { + "name": "kundennutzen", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_milestone_project": { + "name": "idx_milestone_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "milestone_project_id_project_id_fk": { + "name": "milestone_project_id_project_id_fk", + "tableFrom": "milestone", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.phase_gate": { + "name": "phase_gate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ergebnis_erreicht": { + "name": "ergebnis_erreicht", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "notiz": { + "name": "notiz", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_phase_gate_project": { + "name": "idx_phase_gate_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "phase_gate_project_id_project_id_fk": { + "name": "phase_gate_project_id_project_id_fk", + "tableFrom": "phase_gate", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "phase_gate_reviewed_by_user_id_fk": { + "name": "phase_gate_reviewed_by_user_id_fk", + "tableFrom": "phase_gate", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "maxime": { + "name": "maxime", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ziel": { + "name": "ziel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nicht_ziele": { + "name": "nicht_ziele", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "liefergegenstaende": { + "name": "liefergegenstaende", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "zieldreieck_flex": { + "name": "zieldreieck_flex", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "verantwortliche_user_id": { + "name": "verantwortliche_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "arbeitsmodus": { + "name": "arbeitsmodus", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "modus": { + "name": "modus", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'standard'" + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'definition'" + }, + "outline_steckbrief_url": { + "name": "outline_steckbrief_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "steckbrief_freigegeben": { + "name": "steckbrief_freigegeben", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "plane_project_url": { + "name": "plane_project_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "risikoliste_url": { + "name": "risikoliste_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dod_text": { + "name": "dod_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "deadline": { + "name": "deadline", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "status_cache": { + "name": "status_cache", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trend_cache": { + "name": "trend_cache", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pflicht_minimum_state": { + "name": "pflicht_minimum_state", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "archiviert": { + "name": "archiviert", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "archiviert_am": { + "name": "archiviert_am", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "lessons_learned_url": { + "name": "lessons_learned_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "abschlussvermerk": { + "name": "abschlussvermerk", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_project_area": { + "name": "idx_project_area", + "columns": [ + { + "expression": "area_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_project_archived": { + "name": "idx_project_archived", + "columns": [ + { + "expression": "archiviert", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_area_id_area_id_fk": { + "name": "project_area_id_area_id_fk", + "tableFrom": "project", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "project_verantwortliche_user_id_user_id_fk": { + "name": "project_verantwortliche_user_id_user_id_fk", + "tableFrom": "project", + "tableTo": "user", + "columnsFrom": [ + "verantwortliche_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "project_created_by_user_id_fk": { + "name": "project_created_by_user_id_fk", + "tableFrom": "project", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_status": { + "name": "project_status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "ampel": { + "name": "ampel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "trend": { + "name": "trend", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "extern_sichtbar": { + "name": "extern_sichtbar", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_project_status_project": { + "name": "idx_project_status_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_status_project_id_project_id_fk": { + "name": "project_status_project_id_project_id_fk", + "tableFrom": "project_status", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_status_created_by_user_id_fk": { + "name": "project_status_created_by_user_id_fk", + "tableFrom": "project_status", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.risk": { + "name": "risk", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'risiko'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wahrscheinlichkeit": { + "name": "wahrscheinlichkeit", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "auswirkung": { + "name": "auswirkung", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "herkunft": { + "name": "herkunft", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showstopper": { + "name": "showstopper", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "massnahme": { + "name": "massnahme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "strategie": { + "name": "strategie", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'offen'" + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_risk_project": { + "name": "idx_risk_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_risk_showstopper": { + "name": "idx_risk_showstopper", + "columns": [ + { + "expression": "showstopper", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "risk_project_id_project_id_fk": { + "name": "risk_project_id_project_id_fk", + "tableFrom": "risk", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "risk_owner_user_id_user_id_fk": { + "name": "risk_owner_user_id_user_id_fk", + "tableFrom": "risk", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "risk_created_by_user_id_fk": { + "name": "risk_created_by_user_id_fk", + "tableFrom": "risk", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_session_user_id": { + "name": "idx_session_user_id", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_session_expires_at": { + "name": "idx_session_expires_at", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.stakeholder": { + "name": "stakeholder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rolle": { + "name": "rolle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "interesse": { + "name": "interesse", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "einfluss": { + "name": "einfluss", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "haltung": { + "name": "haltung", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'neutral'" + }, + "beduerfnis": { + "name": "beduerfnis", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "notiz": { + "name": "notiz", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_stakeholder_project": { + "name": "idx_stakeholder_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "stakeholder_project_id_project_id_fk": { + "name": "stakeholder_project_id_project_id_fk", + "tableFrom": "stakeholder", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.time_entry": { + "name": "time_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "day_entry_id": { + "name": "day_entry_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "todo_id": { + "name": "todo_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "bezug_kind": { + "name": "bezug_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bezug_id": { + "name": "bezug_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'focus'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "duration_seconds": { + "name": "duration_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_time_entry_user_start": { + "name": "idx_time_entry_user_start", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "uniq_time_entry_user_active": { + "name": "uniq_time_entry_user_active", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"time_entry\".\"ended_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_time_entry_todo": { + "name": "idx_time_entry_todo", + "columns": [ + { + "expression": "todo_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "time_entry_user_id_user_id_fk": { + "name": "time_entry_user_id_user_id_fk", + "tableFrom": "time_entry", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "time_entry_day_entry_id_day_entry_id_fk": { + "name": "time_entry_day_entry_id_day_entry_id_fk", + "tableFrom": "time_entry", + "tableTo": "day_entry", + "columnsFrom": [ + "day_entry_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "time_entry_todo_id_todo_id_fk": { + "name": "time_entry_todo_id_todo_id_fk", + "tableFrom": "time_entry", + "tableTo": "todo", + "columnsFrom": [ + "todo_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.todo": { + "name": "todo", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "day_entry_id": { + "name": "day_entry_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "bezug_kind": { + "name": "bezug_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bezug_id": { + "name": "bezug_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "drop_reason": { + "name": "drop_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "carried_over": { + "name": "carried_over", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "dropped_at": { + "name": "dropped_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_todo_day_entry_id": { + "name": "idx_todo_day_entry_id", + "columns": [ + { + "expression": "day_entry_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_todo_user_date": { + "name": "idx_todo_user_date", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_todo_user_status_carry": { + "name": "idx_todo_user_status_carry", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "carried_over", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "todo_day_entry_id_day_entry_id_fk": { + "name": "todo_day_entry_id_day_entry_id_fk", + "tableFrom": "todo", + "tableTo": "day_entry", + "columnsFrom": [ + "day_entry_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "todo_user_id_user_id_fk": { + "name": "todo_user_id_user_id_fk", + "tableFrom": "todo", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "authentik_sub": { + "name": "authentik_sub", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "default_area_id": { + "name": "default_area_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "abwesend_bis": { + "name": "abwesend_bis", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_user_authentik_sub": { + "name": "uniq_user_authentik_sub", + "columns": [ + { + "expression": "authentik_sub", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "uniq_user_email": { + "name": "uniq_user_email", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 09091c4..a37d425 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -78,6 +78,13 @@ "when": 1780672129310, "tag": "0010_leitfaden_phases", "breakpoints": true + }, + { + "idx": 11, + "version": "7", + "when": 1780754557002, + "tag": "0011_lead_project_link", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts index a5baf0f..5614d30 100644 --- a/packages/db/src/schema.ts +++ b/packages/db/src/schema.ts @@ -465,6 +465,10 @@ export const lead = pgTable( areaId: uuid('area_id') .notNull() .references(() => area.id, { onDelete: 'restrict' }), + // Optionale Verknüpfung zum (universellen) Projekt — egal in welchem Bereich + // dieses wohnt. So sind „HiveGrid-Leads" mit dem HiveGrid-Projekt verbunden, + // ohne dass das Projekt im Vertrieb redundant angelegt werden muss. + projectId: uuid('project_id').references(() => project.id, { onDelete: 'set null' }), // 1. Stammdaten firma: text('firma').notNull(), status: text('status', { enum: ['cold', 'warm', 'hot', 'won', 'lost'] }) @@ -525,6 +529,7 @@ export const lead = pgTable( (t) => ({ idxStatus: index('idx_lead_status').on(t.status), idxOwner: index('idx_lead_owner').on(t.ownerUserId), + idxProject: index('idx_lead_project').on(t.projectId), }), ); diff --git a/packages/shared/src/schemas/lead.ts b/packages/shared/src/schemas/lead.ts index 136c868..b110472 100644 --- a/packages/shared/src/schemas/lead.ts +++ b/packages/shared/src/schemas/lead.ts @@ -39,6 +39,7 @@ const leadCoreFields = { status: leadStatusSchema, score: z.number().int().min(0).max(10), ownerUserId: z.string().uuid().nullable(), + projectId: z.string().uuid().nullable(), branche: z.string().max(200).nullable(), subSegment: z.string().max(200).nullable(), standorte: z.string().max(500).nullable(), @@ -80,6 +81,7 @@ export const createLeadInput = z.object({ status: leadStatusSchema.default('cold'), score: z.number().int().min(0).max(10).default(0), ownerUserId: z.string().uuid().optional(), + projectId: z.string().uuid().optional(), branche: z.string().max(200).optional(), subSegment: z.string().max(200).optional(), website: z.string().max(500).optional(), @@ -87,6 +89,8 @@ export const createLeadInput = z.object({ }); export type CreateLeadInput = z.infer; +export const leadsForProjectInput = z.object({ projectId: z.string().uuid() }); + // Update: id + beliebige Teilmenge der Kernfelder (partial patch). export const updateLeadInput = z .object({ id: z.string().uuid() }) @@ -139,5 +143,6 @@ export type PromoteToDealInput = z.infer; // CSV-Import: rohe CSV-Datei wird serverseitig geparst (header-basiert). export const importLeadsCsvInput = z.object({ csv: z.string().min(1).max(2_000_000), + projectId: z.string().uuid().optional(), // alle importierten Leads diesem Projekt zuordnen }); export type ImportLeadsCsvInput = z.infer;