diff --git a/docs/02-datenmodell.md b/docs/02-datenmodell.md
index b7cf93a..b369c42 100644
--- a/docs/02-datenmodell.md
+++ b/docs/02-datenmodell.md
@@ -168,6 +168,12 @@ Acht Eigenheiten, die man kennen muss:
Zustand der Opportunity abgeleitet (Papierkorb oder weg), nicht gespeichert:
wird sie zurückgeholt, verschwindet der Eintrag von selbst wieder. Die Regeln
dafür stehen in `server/src/acquisitionRules.js`.
+ Aus derselben Logik folgt, was **Wiederherstellen** (`POST /:id/restore`) tut:
+ Es setzt `found_at` auf heute und leert `converted_at` samt `opportunity_id` -
+ ohne das Zurücksetzen von `converted_at` bliebe ein Rückfaller im Archiv
+ stehen, gleich welches Datum er trägt. Ein Kennzeichen
+ „wiederhergestellt" gibt es nicht; es wäre der Zustand, den diese Tabelle
+ gerade nicht führt.
### Postfach crm@perinco.de
diff --git a/docs/05-frontend.md b/docs/05-frontend.md
index 453f155..cf0532b 100644
--- a/docs/05-frontend.md
+++ b/docs/05-frontend.md
@@ -13,6 +13,7 @@ flowchart TD
K --> AQ["Akquise"]
AQ --> AQ1["Eingang Funde der letzten 14 Tage"]
AQ --> AQ2["Archiv älter; nach 90 Tagen gelöscht"]
+ AQ2 -. "Wiederherstellen (Funddatum = heute)" .-> AQ1
K --> O["Opportunities"]
K --> C["Interviews"]
K --> L["Kontakte"]
diff --git a/docs/07-anleitung-benutzer.md b/docs/07-anleitung-benutzer.md
index d985b3b..bfd55c4 100644
--- a/docs/07-anleitung-benutzer.md
+++ b/docs/07-anleitung-benutzer.md
@@ -183,7 +183,7 @@ wird geleert - für das nächste Projekt aus derselben Quelle.
| **Projekttitel** | mit Link anklickbar (neuer Tab); darunter klein Endkunde, Tagessatz bzw. Festpreis und Personentage |
| **Berater** | für wen |
| **Opportunity** | ein Klick macht daraus eine Opportunity in der Phase *Erstgespräch Berater* |
-| Stift / Papierkorb | bearbeiten (füllt das Formular oben) und löschen |
+| Pfeil / Stift / Papierkorb | zurück in die Akquise (nur im Archiv), bearbeiten (füllt das Formular oben) und löschen |
Die Spaltenköpfe sortieren, die Suche geht über Titel, Anbieter, Berater,
Endkunde, Beschreibung und Notizen.
@@ -191,7 +191,8 @@ Endkunde, Beschreibung und Notizen.
### Was von selbst passiert
* Nach **14 Tagen** rutscht ein Eintrag ins **Archiv**. Dort lässt er sich weiter
- bearbeiten und jederzeit übernehmen.
+ bearbeiten und jederzeit übernehmen - der Stift klappt das Formular auch im
+ Archiv auf.
* Nach **90 Tagen** wird er **gelöscht**. Wer ein Projekt behalten will,
übernimmt es als Opportunity.
* Wird ein Eintrag **übernommen**, verschwindet er aus Eingang und Archiv - er
@@ -207,6 +208,27 @@ Endkunde, Beschreibung und Notizen.
Verschoben wird dabei nichts: Eingang und Archiv sind dieselbe Liste, nur nach
dem Funddatum geteilt. Es gibt also keinen Zustand, der klemmen kann.
+### Zurück in die Akquise
+
+Der **Pfeil** in der Archivliste holt einen Eintrag zurück in den Eingang - für
+ein Projekt, das doch noch aktuell ist, oder für eine Bewerbung, die nach dem
+Löschen ihrer Opportunity von vorn beginnt. Der Eintrag bekommt dabei das
+**heutige Datum**; damit zählen die 14 Tage bis zum Archiv und die 90 Tage bis
+zum Löschen wieder von vorn.
+
+> **Zur Statistik:** Das neue Funddatum verschiebt die Bewerbung auch im
+> Dashboard in den heutigen Zeitraum - sie ist dort keine Bewerbung von damals
+> mehr.
+
+Bei einem **Rückfaller** (die Bewerbung war schon eine Opportunity) fragt das CRM
+nach: mit dem Wiederherstellen fällt der Verweis auf die gelöschte Opportunity
+weg. Der Eintrag ist danach wieder ein gewöhnlicher Fund - liegt die Opportunity
+noch im Papierkorb und wird sie zurückgeholt, steht sie ab dann *neben* dem
+Eintrag statt an seiner Stelle.
+
+Ein Eintrag, dessen Opportunity noch lebt, lässt sich nicht wiederherstellen -
+er steht ohnehin in keiner der beiden Listen.
+
### Aus dem Eintrag wird eine Opportunity
Der Knopf **Opportunity** legt sie sofort an: Phase *Erstgespräch Berater*, 10 % Wahrscheinlichkeit,
diff --git a/docs/08-anleitung-entwickler.md b/docs/08-anleitung-entwickler.md
index 9ab9a7e..292a1e2 100644
--- a/docs/08-anleitung-entwickler.md
+++ b/docs/08-anleitung-entwickler.md
@@ -219,8 +219,9 @@ Browser-Download.
* **Gemeinsame Klassen** statt kopierter Utility-Ketten: `inputClass`,
`labelClass` aus `components/leads/leadUi.tsx`, dazu `cardClass`,
`primaryButtonClass` aus `components/scanner/scannerUi.tsx`.
-* **Meldungen als Toast**, Löschabfragen über `ConfirmDialog` - nie `alert()`
- oder `confirm()`.
+* **Meldungen als Toast**, Rückfragen über `ConfirmDialog` - nie `alert()`
+ oder `confirm()`. Rot (`tone="danger"`, Standard) nur, wenn etwas verloren
+ geht; sonst `tone="neutral"`, damit die Farbe ihre Bedeutung behält.
* **Rechte immer doppelt**: Oberfläche blendet aus, Backend antwortet mit 403.
## Deployment
diff --git a/docs/09-quellcode.md b/docs/09-quellcode.md
index 6130082..a8c4035 100644
--- a/docs/09-quellcode.md
+++ b/docs/09-quellcode.md
@@ -92,7 +92,7 @@ Alle unter `router.use(requireAuth)`.
| `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 /?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 |
+| `acquisitions.js` | `GET /?view=eingang\|archiv\|alle`, `POST /`, `PATCH /:id`, `DELETE /:id`, `POST /:id/opportunity`, `POST /:id/restore`; Auswahllisten: `GET/POST /options`, `PATCH/DELETE /options/:id` | Einträge ändern/löschen/wiederherstellen nur Ersteller oder Admin; Auswahllisten jeder Angemeldete. `/restore` setzt `found_at` auf heute und leert `converted_at`/`opportunity_id` - sonst hält die Übernahme den Eintrag im Archiv fest; bei lebender Opportunity antwortet es 409 |
| `badges.js` | `GET /` | Zahlen für die Seitenleiste: Akquise-Archiv, beide Papierkörbe, verworfene Scanner-Treffer. Der Scanner-Zähler ist `null`, wenn dessen Datenbank fehlt |
| `acquisitionRules.js` (kein Router) | Fristen und die SQL-Bedingungen `IS_OPEN`, `IN_ARCHIVE`, `NOT_DUE`, `OPPORTUNITY_GONE`. Geteilt von Liste, Zählern, Aufräumlauf und Menüzahl - zwei Kopien derselben Regel sind einmal auseinandergelaufen |
| `dashboard.js` | `GET /?from=&to=&bucket=tag\|monat\|quartal\|jahr` | drei Reihen über der Zeit plus Bewerbungen je Berater. Liest Akquise **und** `crm_acquisition_history`; Termine und Phasenlisten stehen bewusst nicht drin - die lädt die App ohnehin |
@@ -272,9 +272,9 @@ Warum genau diese Konstanten festgelegt sind, steht in
| `components/opportunities/opportunityUi.tsx` | `STAGE_LABELS` (Anzeige, mit Umlaut), `STAGE_HINTS` (Erläuterung als Titelhinweis), `STAGE_STYLES`, `STAGE_COLORS`, `StageBadge` |
| `components/dashboard/Dashboard.tsx` | Startansicht: Zeitraumwahl, vier Kennzahlen, Verlauf, Berater, Termine, „Beim Kunden". `buildAxis()` erzeugt auch leere Abschnitte |
| `components/dashboard/dashboardUi.tsx` | `useCountUp()` (Zahl läuft hoch, respektiert `prefers-reduced-motion`), `StatCard`, `SeriesChart`, `BarList`, `Panel` - von Hand statt Diagrammbibliothek |
-| `components/acquisition/Acquisitions.tsx` | Akquise und Archiv (`view`); Suche, Sortierung, Übernahme, Löschen |
+| `components/acquisition/Acquisitions.tsx` | Akquise und Archiv (`view`); Suche, Sortierung, Übernahme, Löschen, Wiederherstellen. Das Formular steht im Archiv nur beim Bearbeiten - ohne diesen Zweig blieb der Stift dort ohne Wirkung |
| `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 |
+| `components/acquisition/AcquisitionTable.tsx` | die Liste; `safeLink()` lässt nur http(s) zum Link werden. Der Pfeil zum Wiederherstellen erscheint nur, wenn `onRestore` gesetzt ist - im Eingang gibt es nichts wiederherzustellen |
| `components/acquisition/acquisitionUi.tsx` | `fieldClass` (abgesetzte Felder) und `OptionSelect` - zeigt einen Wert, der nicht mehr in der Liste steht, als solchen; `alwaysOffer` hält den eigenen Namen für *Von* immer wählbar. *Anbieter* nutzt es nicht: Freitext mit `