feat(leads): Leads universell mit Projekten verknüpfen
ci / quality (push) Failing after 44s
ci / build (push) Has been skipped
deploy / deploy (push) Successful in 54s

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) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 4.8 committed 2026-06-06 16:08:59 +02:00
1 parent 68480c1eb1
commit 19db774c4c
10 files changed
+3522 -3

No files matched your search

+5
View File
@@ -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<typeof createLeadInput>;
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<typeof promoteToDealInput>;
// 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<typeof importLeadsCsvInput>;