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} />
+
+
+
+
+
@@ -1106,6 +1109,100 @@ function LevelSelect({
);
}
+// --- Leads (Vertriebs-Sicht des Projekts) -----------------------------------
+function LeadsSection({ projectId }: { projectId: string }) {
+ const utils = trpc.useUtils();
+ const q = trpc.lead.forProject.useQuery({ projectId });
+ const [adding, setAdding] = useState(false);
+ const [firma, setFirma] = useState('');
+ const create = trpc.lead.create.useMutation({
+ onSuccess: async () => {
+ await utils.lead.forProject.invalidate({ projectId });
+ await utils.lead.list.invalidate();
+ setFirma('');
+ setAdding(false);
+ },
+ });
+ const list = q.data ?? [];
+ return (
+
+
+
+ Leads{list.length > 0 && ({list.length})}
+
+
+
+ Alle Leads →
+
+ {!adding && (
+
+ )}
+
+
+
+ {list.length === 0 && !adding && (
+
+ Noch keine Leads mit diesem Projekt verknüpft.
+
+ )}
+ {list.map((l) => (
+
+
+
+ {l.firma}
+ {l.branche && {l.branche}}
+
+
+
+ {LEAD_STATUS_META[l.status as LeadStatus].label}
+
+ {l.score}/10
+
+
+ ))}
+ {adding && (
+
+ )}
+
+
+ );
+}
+
// --- 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;