feat(projekt): Anheftungen per Drag & Drop zwischen Unterreitern verschieben

Pin-Zeilen in der Ordneransicht sind draggable, die Reiter sind Ablageziele.
Ein Drop schickt PATCH /api/projects/:id/pins/:pinId {tab_id}; movePin schreibt
project_pins.tab_id um. Verschoben wird nur die Referenz.

- Zielebene hat die Aufnahme schon: Quell-Pin loeschen statt an UNIQUE uniq_pin
  scheitern (merged:true)
- Zielreiter serverseitig gegen den Ordner pruefen, sonst 404
- .ptab-n braucht pointer-events:none, sonst flackert die Ablagemarkierung

Verifiziert gegen die laufende App inkl. 404- und Merge-Faellen; Testdaten
zurueckgesetzt. Doku: Kapitel 10 + Changelog.
This commit is contained in:
2026-08-14 14:52:14 +02:00
parent 2be938c91b
commit 3d628b4b96
6 changed files with 1842 additions and 1678 deletions
+33
View File
@@ -3,6 +3,39 @@
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
Was, Warum, betroffene Dateien/Backups).
## 2026-08-14 — Angeheftete Aufnahmen per Drag & Drop zwischen Unterreitern verschieben
**Wunsch:** eine im Projekt abgelegte Aufnahme sollte sich innerhalb des Ordners umhängen lassen, z. B. von
`DFG/Projektleiter Runden` nach `DFG/INF-Projektboard`. Bisher ging das nur über Lösen + neu Anheften,
also zwei Dialoge für eine Bewegung.
**Umsetzung:** die Pin-Zeilen in der Ordneransicht sind `draggable`, die Reiter der Reiterleiste sind
Ablageziele (`bindPinDrag` in `main.js`). Ein Drop schickt `PATCH /api/projects/:id/pins/:pinId {tab_id}`;
`db.movePin` schreibt `project_pins.tab_id` um. Verschoben wird ausschließlich die Referenz — an der
Aufnahme, ihrer Analyse oder ihren übrigen Anheftungen ändert sich nichts.
Drei Punkte, die beim Bauen aufgefallen sind:
- Hängt die Aufnahme auf der Zielebene bereits, würde das `UPDATE` an `UNIQUE uniq_pin` scheitern.
`movePin` löscht dann den Quell-Pin (**Zusammenführen statt Fehler**) und meldet `{merged:true}`.
- Der Zielreiter wird serverseitig gegen den Ordner geprüft (`project_tabs.project_id`), sonst könnte ein
veralteter Browser-Tab einen Pin in ein fremdes Projekt schieben → sonst 404.
- `.ptab-n` (Zähler im Reiter) braucht `pointer-events: none`, sonst feuert beim Überfahren des Zählers
ein `dragleave` und die Ablagemarkierung flackert.
**Verifiziert** direkt gegen die laufende App (Ordner „DFG", Pin #12): Verschieben Reiter 2 → 3 → 2 jeweils
`{"moved":true}` und `tab_id` in der DB entsprechend; fremder Reiter (999) und fremdes Projekt (2) je
`404 {"error":"Anheftung oder Zielreiter nicht gefunden"}`; gleicher Reiter `{"moved":false}` ohne
Schreibzugriff; Zusammenführen getestet mit Aufnahme #109 (zwei Pins → einer). Testdaten danach auf den
Ausgangsstand zurückgesetzt. `vite build` sauber, `systemctl restart callrec` erst nach Prüfung auf
`analysis_status='pending'` (keine laufende Analyse, keine laufende Aufnahme).
Dateien: `app/db.js` (`movePin`), `app/server.js` (`PATCH …/pins/:pinId`), `app/web/src/main.js`
(`bindPinDrag`, `draggable` an der Pin-Zeile, Hinweistext in der Ebenen-Kopfzeile),
`app/web/src/style.css` (`.ptab.drop`, `.item.rec.dragging`, `.ptab-n`).
Board-Backups: `.bak-movepin` (db.js, server.js, web/src/main.js, web/src/style.css, web/dist).
Kapitel 10 (neuer Abschnitt „Verschieben per Drag & Drop" + Sequenzdiagramm + API-Tabelle).
## 2026-08-10 — Recorder überlebt das Neuladen (GUI holt den Zustand vom Server)
**Symptom:** während einer laufenden Aufnahme klickte der Nutzer in eine andere Aufnahme; danach stand der