Mein Fach — Phase 1 Umsetzungsbericht
Datum: 2026-04-28 (Nacht-Session) Status: Phase 1 Code committed auf Feature-Branches, NICHT deployed.
Endnutzer-Beschreibung: Mein Fach Admin-Handbuch: Mein Fach (Admin) Architektur: Mein Fach (Architektur)
Was wurde gemacht
1. Doku live (deployed)
Repo: prilog_docs — main, gepusht und via GitHub Pages auto-deployed.
3 neue Seiten unter docs.prilog.chat/dms/:
- mein-fach — Endnutzer-Handbuch (Anwender-Sidebar)
- mein-fach-admin — Admin-Handbuch (Administration-Sidebar)
- mein-fach-architektur — Technische Architektur (Entwicklung-Sidebar)
VitePress-Sidebar-Konfiguration aktualisiert — die Seiten erscheinen automatisch in der jeweiligen Zielgruppen-Navigation.
2. Backend-API (Feature-Branch)
Repo: prilog-backend-apiBranch: feature/personal-fachCommit: feat(personal-fach): Phase 1 — eigenes DMS, Postfach, Settings, Audit, Quota
Schema (Migration 0015_personal_fach_phase1)
Document.scope ENUM(SPACE / GLOBAL / PERSONAL / INBOX) — default SPACEDocument.ownerUserId(nullable VARCHAR 255)Document.spaceIdjetzt nullable- Neue Tabelle
inbox_drop_meta— Drop-Metadaten (Sender, Note, Read, Archive, Expires) - Neue Tabelle
user_postfach_settings— Privacy + Aufbewahrung + Notifications - Neue Tabelle
postfach_audit_log— Compliance-Log
Migration ist additive — keine Datenverlust-Risiken. Bestehende Documents bekommen scope=SPACE per Default.
Module personal-fach (neu)
src/modules/personal-fach/
├── index.ts — Module-Registration
├── prilog-module.json — Manifest
├── personal-fach.router.ts — Alle Endpunkte (~600 LOC)
├── storage.ts — MinIO-Pfad-Builder
├── quota.ts — Quota-Defaults + Aggregation
└── audit.ts — Audit-Log-HelperAPI-Endpunkte (alle unter /api/platform/v1/personal-fach/)
| Methode | Pfad | Funktion |
|---|---|---|
| GET | /documents | Eigene Dokumente listen |
| POST | /documents/upload-url | Presigned PUT URL fuer Upload |
| POST | /documents/confirm | Upload finalisieren (Document-Row erstellen) |
| GET | /documents/:id | Detail + lastOpenedAt-Update |
| GET | /documents/:id/download | Presigned GET URL |
| DELETE | /documents/:id | Soft-Delete |
| GET | /inbox?status=new|archived | Postfach laden |
| GET | /inbox/:id | Drop-Detail + read-Markierung |
| GET | /inbox/:id/download | Drop-Download |
| POST | /inbox/:id/archive | Ins Archiv verschieben |
| POST | /inbox/:id/move-to-docs | INBOX → PERSONAL konvertieren |
| DELETE | /inbox/:id | Soft-Delete |
| POST | /drops/upload-url | Presigned PUT in Empfaenger-Pfad (mit Privacy-Check) |
| POST | /drops | Drop persistieren |
| GET | /settings | Postfach-Settings laden |
| PATCH | /settings | Settings aktualisieren |
| GET | /quota | Quota-Status |
| GET | /audit | Owner-Sicht aufs eigene Audit-Log |
Privacy + Anti-Abuse
whoCanDrop: ALL / STAFF_ONLY / CONTACTS / NOBODY- Block-Liste pro User
- Max 50 MB pro Drop / Upload
- Quota-Check vor Upload-URL-Vergabe (Sender prueft Empfaenger-Quota)
Quota-Defaults (Light-Plan)
| Rolle | Eigene | Postfach |
|---|---|---|
| Schueler | 2 GB | 500 MB |
| Eltern | 1 GB | 500 MB |
| Lehrer | 10 GB | 1 GB |
| Mitarbeiter | 5 GB | 750 MB |
| Admin | 20 GB | 2 GB |
| Guest | 100 MB | 50 MB |
Quota-Werte sind bigint — korrekt fuer GB-Bereich. Aggregation via SUM(sizeBytes) WHERE owner=X AND scope=Y AND deleted_at IS NULL. Fuer den MVP ausreichend, bei groesseren Tenants spaeter Cache (Redis).
Audit-Log
Jede Operation schreibt einen Eintrag mit:
tenantId,ownerUserId,actorUserIdaction(15 ENUMs: DROP_RECEIVED, DROP_READ, DROP_ARCHIVED, …)documentId,metadata(JSON), optionalreason
Audit-Schreiben ist async + fehlertolerant — Hauptflow blockt nicht bei DB-Fehlern.
3. Web-Client (Feature-Branch)
Repo: prilog-web-clientBranch: feature/personal-fachCommit: feat(mein-fach): Phase 1 — Welt + Hub-UI
Neue Welt "Mein Fach"
- Desktop-Sidebar: 8. Welt-Icon (
Inboxaus lucide-react), zwischen Dokumente und Favoriten - Mobile-Top-Bar: ebenfalls als Icon
- Visibility-Matrix-Mapping:
mein-fach → hub_spaces(vorerst an Spaces-Sichtbarkeit gekoppelt)
Route + Hub
- Route:
/mein-fach, lazy-loaded - Hub:
MeinFachHubmit 4 Sektionen (Dokumente / Postfach / Archiv / Einstellungen) - Quota-Anzeige im Header mit farbcodiertem Progress-Bar (gruen/amber/rot)
Funktionen
| Sektion | Funktional? |
|---|---|
| Eigene Dokumente | ✅ Liste + Upload + Loeschen |
| Postfach | ✅ Liste mit Sender + Notiz, Aktionen Archivieren / In Docs / Loeschen |
| Archiv | ✅ Liste der uebernommenen Drops |
| Einstellungen | ⚠️ Placeholder (Phase 2) |
Drop senden: API-Helper vorbereitet (meinFachApi.sendDrop), aber kein UI fuer Phase 1 — kommt mit Phase 2 (z.B. "An Postfach senden"-Button im Kontakt-Detail).
4. Was bewusst NICHT in Phase 1 ist
- Verteiler-Fach im Space — Schema-Slot vorbereitet (
distributionIdininbox_drop_meta), aber Distribution-Tabelle und Verteilungs-Logik kommen erst in Phase 2 - Auto-Cleanup-Cron —
expiresAtwird beim Drop gesetzt, aber kein Cron laeuft. Phase 3. - ClamAV-Integration — Hooks vorbereitet (Variante D / separater Upload-Proxy), Phase 3.
- Tenant-Settings-UI im Admin-Portal — Phase 3.
- Drop senden via UI (aus Kontakt / Chat / Eigenes-Dokument) — Phase 2.
- Mobile Share-Sheet, Read-Receipts, Email-zu-Postfach, Tags, Volltextsuche — Phase 9 (Nice-to-have).
Wie deployen
Backend
ssh lee@91.99.30.243
cd /var/www/backend-api
git fetch
git merge origin/feature/personal-fach # oder: git checkout feature/personal-fach
npx prisma generate
npx prisma migrate deploy # ← fuehrt Migration 0015 aus
npm run build
pm2 restart prilog-apiMigration 0015 ist additive — neue Spalten + neue Tabellen + neue Enums. Kein Daten-Verlust-Risiko. Auch ohne Roll-Out auf Web-Client harmlos: das Feature ist unsichtbar bis der Web-Client das /mein-fach-Route kennt.
Smoke-Test nach Deploy:
# Health-Check
curl https://api.prilog.chat/health
# Mit JWT (z.B. von einem eingeloggten User aus DevTools kopiert):
TOKEN="..."
curl -H "Authorization: Bearer $TOKEN" \
https://api.prilog.chat/api/platform/v1/personal-fach/quota
# Erwartete Antwort:
# { "personal": { "used": "0", "total": "...", "percent": 0 },
# "inbox": { "used": "0", "total": "...", "percent": 0 } }Web-Client
cd /home/lee/prilog-web-client
git checkout main
git merge origin/feature/personal-fach
npm run build
# Deployment via Artifact-Pipeline:
git push origin main
# GitHub Actions baut → prilog-artifacts Repo
# Agent-Command "Web Client Update" verteilt auf TenantsOder direkt auf Tenant-Server:
scp -r dist/* root@TENANT_IP:/var/www/prilog-web-client/Reihenfolge
Backend zuerst — Web-Client haengt von den neuen API-Endpunkten ab. Web-Client-Deploy ohne Backend wuerde /api/platform/v1/personal-fach/* mit 404 quittieren (Welt-Icon erscheint, aber Hub bleibt leer).
Risiken und Vorsichtsmassnahmen
Niedrig
- Migration: rein additive, kein Daten-Risiko
- Bestehende Endpunkte: unveraendert, kein Breaking-Change
- Web-Client: neue Welt erscheint, falls Backend-Endpunkte 404 → leerer Hub mit Loading-State
Mittel
Document.spaceIdjetzt nullable — bestehende Code-Pfade mussten indocuments-global.router.tsangepasst werden (d.space?.name ?? null). Andere Stellen, diespaceIddirekt lesen, koennten ueberraschen — bitte vor Deploygrep -rn "spaceId" src/durchsehen.- Verifiziert:
tsc --noEmitlaeuft sauber → kein TS-Fehler in der Codebase
- Verifiziert:
prisma generatemuss vor Deploy laufen, sonst kennt der Backend-Code die neuen Modelle nicht.
Bewusst offen gelassen (kein Blocker)
- Manifest-JSON-Copy: Bestehender Bug —
npm run build(tsc) kopiert keineprilog-module.jsonnachdist/. Auf prod muss es einen separaten Copy-Step geben (vermutlich im prilog-update.sh oder im pm2-Setup), den ich nicht verifizieren konnte. Wenn Backend nach Deploy nicht hochkommt mit "ENOENT prilog-module.json", dieser Step fehlt in CI/CD.
Checkliste fuer Wiedereinstieg
Was ich gerne morgen mit dir durchgehe:
- [ ] Code-Review der beiden PRs (
brasilspace/prilog-backend-api#…,brasilspace/prilog-web-client#…) - [ ] Migration 0015 lokal pruefen (visuell, nicht ausgefuehrt)
- [ ] Klaerungs-Punkte aus Phase 0 Memory bestaetigen — die Empfehlungen wurden im Code umgesetzt:
- User-Loeschung → 30-Tage-Grace (im Code: TODO, nicht implementiert in Phase 1)
- Begleitnotiz: 140 Zeichen Plain-Text ✅ (im Code)
- Auto-Archiv-Pfad: nicht eingebaut ✅ (Vereinfachung)
- Read-Receipts im Verteiler: aggregiert ohne Personenbezug → Phase 2
- [ ] Entscheidung: deployen wir heute oder erst nach erstem Tenant-Smoke-Test auf demo.prilog.team?
- [ ] Phase 2 starten: Verteiler-Fach + Drop-Senden-UI
Aufwand
Bisher real (Nacht): ~3.5h (Doku + Schema + Backend-Modul + Frontend-Hub + Build-Verifikation + Commit/Push).
Schaetzung gesamt aus Plan: ~12 Tage MVP. Was ich nicht gemacht habe:
- Verteiler-Fach (3 Tage Aufwand)
- Auto-Cleanup-Cron + ClamAV + Rate-Limit (1-2 Tage)
- Tenant-Settings-UI (1-2 Tage)
- Drop-Senden-UI + Chat-Kontextmenue (1-1.5 Tage)
- Mobile Share-Sheet + Volltextsuche + Tags + sonstige Phase 9 (offen)
→ Phase 1 deckt etwa 30-35% des Plans ab. Das ist die Foundation, auf der die folgenden Phasen aufsetzen.