feat(opportunities): Phasen des Vermittlungsprozesses, Kanban zuerst, Zahlen im Menue

Drei Dinge:

- Die Phasen sind jetzt die des Vermittlungsprozesses: Neu, Beworben,
  Erstgespraech Berater, Kundenvorstellung, Interview Kunde, Zusage, Beauftragt,
  Absage. Offen ist alles bis einschliesslich Zusage - dort ist der Einsatz
  bestaetigt, die Beauftragung steht aber noch aus. migrateOpportunityStages()
  stellt bestehende Datenbanken um und setzt alle vorhandenen Opportunities auf
  "Neu": in welcher der neuen Phasen ein Projekt steckt, sagt der alte Trichter
  nicht (so mit dem Nutzer entschieden).

  Der Datenbankwert heisst 'Erstgespraech Berater' ohne Umlaut - Projektkonvention
  fuer Datenbankwerte. Angezeigt wird er ueber STAGE_LABELS; dazu gibt es
  STAGE_HINTS mit der Erlaeuterung je Phase als Titelhinweis an Auswahl, Badge
  und Spaltenkopf.

- Kanban ist die erste Ansicht der Opportunities. Die Pipeline ist die
  Arbeitsansicht, Kachel und Liste sind zum Nachschauen.

- Hinter "Archiv", beiden "Papierkorb"-Punkten und "Unpassend" steht die Anzahl,
  wie schon bei "Aus Mails". Die Zahlen kommen aus einem eigenen Endpunkt
  (/api/badges), weil sie alle ins Menue gehoeren und zusammen kommen sollen;
  Inhalte laedt weiter jede Ansicht selbst. Der Scanner liegt in einer eigenen
  Datenbank und kann fehlen - sein Zaehler ist dann null und die Leiste zeigt
  dort einfach keine Zahl. Der Aufruf haengt bewusst hinter den Daten und nicht
  im Promise.all: faellt er aus, bleibt das Menue ohne Zahlen statt die Ansicht
  mit einem Fehler.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-08-18 14:34:41 +02:00
co-authored by Claude Opus 5
parent 1ac0e2d2c7
commit 42639c65fa
17 changed files with 313 additions and 55 deletions
+27 -8
View File
@@ -204,20 +204,39 @@ export type LeadViewMode = 'grid' | 'list' | 'network';
// ---------- Opportunities ----------
/** Phasen der Vertriebspipeline, in dieser Reihenfolge. */
/**
* Phasen des Vermittlungsprozesses, in dieser Reihenfolge - vom identifizierten
* Projekt bis zur Beauftragung, plus die Absage am Ende.
*
* "Erstgespraech Berater" steht bewusst ohne Umlaut: der Wert liegt so in der
* Datenbank (Projektkonvention fuer Datenbankwerte). Gelesen wird er ueber
* STAGE_LABELS in opportunityUi.tsx.
*/
export const OPPORTUNITY_STAGES = [
'Neu',
'Qualifizierung',
'Angebot',
'Verhandlung',
'Gewonnen',
'Verloren',
'Beworben',
'Erstgespraech Berater',
'Kundenvorstellung',
'Interview Kunde',
'Zusage',
'Beauftragt',
'Absage',
] as const;
export type OpportunityStage = (typeof OPPORTUNITY_STAGES)[number];
/** Phasen, in denen die Chance noch offen ist. */
export const OPEN_STAGES: OpportunityStage[] = ['Neu', 'Qualifizierung', 'Angebot', 'Verhandlung'];
/**
* Phasen, in denen die Chance noch offen ist - alles bis auf das Ende. "Zusage"
* gehoert dazu: der Einsatz ist bestaetigt, die Beauftragung steht aber noch aus.
*/
export const OPEN_STAGES: OpportunityStage[] = [
'Neu',
'Beworben',
'Erstgespraech Berater',
'Kundenvorstellung',
'Interview Kunde',
'Zusage',
];
export interface OpportunityContact {
lead_id: number;