feat(opportunities): Papierkorb statt endgueltigem Loeschen
Das Loeschsymbol gab es in der Kachelansicht schon, es war aber bis zum
Ueberfahren durchsichtig - ein Knopf, den man nur findet, wenn man ihn kennt.
Jetzt ist er sichtbar, in der Liste ebenso, und die Pipeline-Karte hat ihn
ueberhaupt zum ersten Mal.
Geloescht wird nicht mehr endgueltig: DELETE setzt deleted_at, die Zeile bleibt.
An einer Opportunity haengen Ansprechpartner, Verlauf und Mailzuordnungen, und
ein Fehlklick soll das nicht kosten. Der Papierkorb ist ein Unterpunkt unter
Opportunities und zeigt, wann und von wem geloescht wurde und wie lange der
Eintrag noch liegt. Zurueckholen darf, wer auch loeschen darf; das Leeren jeder
Angemeldete - was dort liegt, hat schon jemand mit den noetigen Rechten
weggeworfen. Beides fragt vorher nach.
Nach 90 Tagen raeumt das Backend selbst auf, beim Abruf der Liste und hoechstens
einmal pro Stunde je Prozess - dasselbe Muster wie in der Akquise. Ein eigener
Zeitplan waere eine weitere Stelle, die ausfallen kann, und die Abfragen filtern
Faelliges ohnehin heraus.
Im Papierkorb liegende Opportunities sind aus allen Listen, Summen und
Zuordnungsdialogen heraus und lassen sich nicht bearbeiten (409) - erst
zurueckholen, dann aendern.
Nebenbei: der Header bekommt seinen Titel jetzt ueber viewTitle(). Der
Ansichtsname musste eindeutig sein ("Opportunity-Papierkorb", weil die Mails
schon einen Papierkorb haben), angezeigt wird beides als "Papierkorb".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2717462c3a
commit
1ac0e2d2c7
@@ -71,6 +71,7 @@ erDiagram
|
||||
date last_interaction_at
|
||||
varchar next_step
|
||||
int owner_id FK
|
||||
datetime deleted_at "Papierkorb; nach 90 Tagen weg"
|
||||
}
|
||||
crm_opportunity_contacts {
|
||||
int opportunity_id PK,FK
|
||||
@@ -109,7 +110,7 @@ erDiagram
|
||||
}
|
||||
```
|
||||
|
||||
Sechs Eigenheiten, die man kennen muss:
|
||||
Sieben Eigenheiten, die man kennen muss:
|
||||
|
||||
- **`crm_leads` führt zwei Bestände.** `mail_pool = 0` ist der gepflegte
|
||||
Kontaktbestand, `mail_pool = 1` der Vorbereich „Aus Mails" mit den Funden des
|
||||
@@ -126,6 +127,12 @@ Sechs Eigenheiten, die man kennen muss:
|
||||
- **`avatar` ist eine Data-URL in der Datenbank.** Der Browser verkleinert jedes
|
||||
Bild vor dem Upload auf 256 px (`src/lib/imageCompress.ts`), aus 2,9 MB werden
|
||||
wenige Kilobyte.
|
||||
- **Gelöschte Opportunities bleiben stehen.** `crm_opportunities.deleted_at`
|
||||
setzt sie in den Papierkorb; alle Abfragen blenden sie aus. An einer
|
||||
Opportunity hängen Ansprechpartner, Verlauf und Mailzuordnungen - ein Fehlklick
|
||||
soll das nicht kosten. Endgültig entfernt sie erst das Leeren des Papierkorbs
|
||||
oder der Ablauf von 90 Tagen; dann räumen `crm_opportunity_contacts` und
|
||||
`crm_mail_links` per CASCADE mit auf.
|
||||
- **Die Dropdowns der Akquise stehen in einer Tabelle, nicht in drei.**
|
||||
`crm_acquisition_options` unterscheidet die Listen über die Spalte `field`. Die
|
||||
Felder verhalten sich gleich, also ist jede weitere Liste ein Wert im ENUM
|
||||
|
||||
@@ -35,7 +35,9 @@ die Scanner-Einstellungen. Alles andere ist für beide Rollen gleich.
|
||||
│ Akquise ▾ │ │
|
||||
│ Eingang │ │
|
||||
│ Archiv │ │
|
||||
│ Opportunities├──────────────────────────────────────────┤
|
||||
│ Opportuni…▾ │───────────────────────────────────────────┤
|
||||
│ Alle │ │
|
||||
│ Papierkorb │ │
|
||||
│ Interviews │ │
|
||||
│ Kontakte ▾ │ Inhalt │
|
||||
│ Alle Kont. │ │
|
||||
@@ -201,6 +203,26 @@ verlässt.
|
||||
**Administrator**. Wer keines davon ist, bekommt eine Fehlermeldung - das prüft
|
||||
der Server, nicht nur die Oberfläche.
|
||||
|
||||
### Löschen und Papierkorb
|
||||
|
||||
Das **Papierkorbsymbol** an der Kachel, in der Listenzeile und auf der
|
||||
Pipeline-Karte legt eine Opportunity in den **Papierkorb** - den Unterpunkt unter
|
||||
*Opportunities*. Vorher fragt eine Warnung nach.
|
||||
|
||||
Im Papierkorb steht, wann und von wem gelöscht wurde und wie lange der Eintrag
|
||||
noch liegt:
|
||||
|
||||
* **Wiederherstellen** holt die Opportunity zurück - mit Ansprechpartnern,
|
||||
Verlauf und Mailzuordnungen.
|
||||
* **Papierkorb leeren** entfernt alles darin **endgültig**, ebenfalls nach einer
|
||||
Warnung. Dabei gehen die Zuordnungen der Ansprechpartner und der Mails
|
||||
verloren; die Kontakte selbst und die Mails bleiben erhalten.
|
||||
* Ohne Zutun wird ein Eintrag **nach 90 Tagen** endgültig gelöscht.
|
||||
|
||||
Solange eine Opportunity im Papierkorb liegt, erscheint sie in keiner Liste, in
|
||||
keiner Summe und in keinem Zuordnungsdialog - und sie lässt sich nicht
|
||||
bearbeiten. Erst zurückholen, dann ändern.
|
||||
|
||||
Auf dem Tablet oder ohne Lust auf Ziehen: die Phase lässt sich auch über das
|
||||
Auswahlfeld direkt auf der Karte ändern.
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Alle unter `router.use(requireAuth)`.
|
||||
| `leads.js` | `GET /`, `POST /`, `PATCH /:id`, `DELETE /:id`; Vorbereich: `GET /mail-pool/sources`, `POST /mail-pool/promote`, `POST /:id/promote` | jeder Angemeldete |
|
||||
| `connections.js` | `GET /`, `POST /`, `PATCH /:id`, `DELETE /:id` | jeder Angemeldete |
|
||||
| `events.js` | `GET /`, `POST /`, `PATCH /:id`, `DELETE /:id` | anlegen jeder; ändern/löschen nur Ersteller oder Admin |
|
||||
| `opportunities.js` | `GET /`, `POST /`, `PATCH /:id`, `DELETE /:id` | ändern/löschen nur Ersteller, Zuständiger oder Admin |
|
||||
| `opportunities.js` | `GET /?trash=true`, `POST /`, `PATCH /:id`, `DELETE /:id` (Papierkorb), `POST /:id/restore`, `POST /trash/empty` | ändern, löschen und wiederherstellen nur Ersteller, Zuständiger oder Admin; Leeren jeder Angemeldete |
|
||||
| `acquisitions.js` | `GET /?view=eingang\|archiv\|alle`, `POST /`, `PATCH /:id`, `DELETE /:id`, `POST /:id/opportunity`; Auswahllisten: `GET/POST /options`, `PATCH/DELETE /options/:id` | Einträge ändern/löschen nur Ersteller oder Admin; Auswahllisten jeder Angemeldete |
|
||||
| `mail.js` | `GET /status`, `/messages`, `/messages/:id`, `/candidates`; `POST /messages/:id/links`, `/messages/:id/restore`, `/candidates/:id/adopt`, `/candidates/:id/reject`, `/trash/empty`; `DELETE /links/:id`, `/messages/:id`; `requireAdmin`: `GET/POST /settings`, `POST /test`, `POST /sync` | lesen, zuordnen und löschen jeder; einrichten Admin |
|
||||
|
||||
@@ -265,6 +265,7 @@ Warum genau diese Konstanten festgelegt sind, steht in
|
||||
|
||||
| Datei | Inhalt |
|
||||
| --- | --- |
|
||||
| `components/opportunities/OpportunityTrash.tsx` | Papierkorb der Opportunities: wiederherstellen, leeren, Restlaufzeit je Eintrag |
|
||||
| `components/acquisition/Acquisitions.tsx` | Akquise und Archiv (`view`); Suche, Sortierung, Übernahme, Löschen |
|
||||
| `components/acquisition/AcquisitionForm.tsx` | Eingabe über der Liste; behält Datum, Anbieter, Kanal und Berater für den nächsten Eintrag |
|
||||
| `components/acquisition/AcquisitionTable.tsx` | die Liste; `safeLink()` lässt nur http(s) zum Link werden |
|
||||
@@ -290,7 +291,8 @@ nicht auseinanderlaufen:
|
||||
|
||||
| Export | Zweck |
|
||||
| --- | --- |
|
||||
| `ViewState`, `SettingsTab`, `ADMIN_SETTINGS_TABS`, `SCANNER_VIEWS`, `MAIL_VIEWS`, `ACQUISITION_VIEWS`, `CONTACT_VIEWS` | Ansichten, Reiter und aufklappbare Gruppen |
|
||||
| `ViewState`, `SettingsTab`, `ADMIN_SETTINGS_TABS`, `SCANNER_VIEWS`, `MAIL_VIEWS`, `ACQUISITION_VIEWS`, `OPPORTUNITY_VIEWS`, `CONTACT_VIEWS` | Ansichten, Reiter und aufklappbare Gruppen |
|
||||
| `VIEW_TITLES`, `viewTitle()` | abweichende Beschriftung, wo der Ansichtsname nur intern eindeutig sein muss (`Opportunity-Papierkorb` → Papierkorb) |
|
||||
| `MAIL_LEAD_SOURCE`, `LeadOriginFilter` | Herkunft „Mail" in `Lead.source` und ihr Filter |
|
||||
| `USER_COLORS`, `userColor()` | Farbe gesetzt, sonst stabil aus der Benutzer-Id |
|
||||
| `opportunityVolume()`, `weightedVolume()`, `formatEuro()` | Festpreis, sonst Tagessatz x Personentage; gewichtet; formatiert |
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ Quelltext.
|
||||
| **Akquise** | Eingang für gefundene Projekte, bevor daraus eine Opportunity wird. Tabelle `crm_acquisitions`. Nach 14 Tagen im **Archiv**, nach 90 Tagen gelöscht. |
|
||||
| **Auswahllisten** (Akquise) | Inhalte der Dropdowns *Von*, *Kanal*, *Berater*. Tabelle `crm_acquisition_options`, gepflegt unter *Einstellungen → Akquise*. *Anbieter* ist Freitext mit Vorschlägen. |
|
||||
| **Art** (eines Kontakts) | Recruiter, Partner oder Endkunde. Spalte `crm_leads.kind`; hieß bis 18.08.2026 „Status" mit den Werten Neu .. Verloren. |
|
||||
| **Papierkorb** | Im CRM gelöschte Mails. Umkehrbar, bis er geleert wird. Im Postfach crm@perinco.de bleiben die Mails in jedem Fall; der Abgleich holt gelöschte nicht wieder herein. |
|
||||
| **Papierkorb** (Mails) | Im CRM gelöschte Mails. Umkehrbar, bis er geleert wird. Im Postfach crm@perinco.de bleiben die Mails in jedem Fall; der Abgleich holt gelöschte nicht wieder herein. |
|
||||
| **Papierkorb** (Opportunities) | Gelöschte Opportunities, `crm_opportunities.deleted_at`. Wiederherstellbar; endgültig weg nach 90 Tagen oder beim Leeren. |
|
||||
| **Phase** / Stage | Fortschritt einer Opportunity: Neu, Qualifizierung, Angebot, Verhandlung, Gewonnen, Verloren. |
|
||||
| **Pipeline** | Zwei Bedeutungen, je nach Zusammenhang: die Kanban-Ansicht der Opportunities **oder** der Suchlauf des Scanners (`services/pipeline.js`). |
|
||||
| **Projekt** | Ein von einer Börse gescrapter Auftrag. Tabelle `projects`, Aufbewahrung 7 Tage. |
|
||||
|
||||
Reference in New Issue
Block a user