Skip to content

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 SPACE
  • Document.ownerUserId (nullable VARCHAR 255)
  • Document.spaceId jetzt 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-Helper

API-Endpunkte (alle unter /api/platform/v1/personal-fach/)

MethodePfadFunktion
GET/documentsEigene Dokumente listen
POST/documents/upload-urlPresigned PUT URL fuer Upload
POST/documents/confirmUpload finalisieren (Document-Row erstellen)
GET/documents/:idDetail + lastOpenedAt-Update
GET/documents/:id/downloadPresigned GET URL
DELETE/documents/:idSoft-Delete
GET/inbox?status=new|archivedPostfach laden
GET/inbox/:idDrop-Detail + read-Markierung
GET/inbox/:id/downloadDrop-Download
POST/inbox/:id/archiveIns Archiv verschieben
POST/inbox/:id/move-to-docsINBOX → PERSONAL konvertieren
DELETE/inbox/:idSoft-Delete
POST/drops/upload-urlPresigned PUT in Empfaenger-Pfad (mit Privacy-Check)
POST/dropsDrop persistieren
GET/settingsPostfach-Settings laden
PATCH/settingsSettings aktualisieren
GET/quotaQuota-Status
GET/auditOwner-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)

RolleEigenePostfach
Schueler2 GB500 MB
Eltern1 GB500 MB
Lehrer10 GB1 GB
Mitarbeiter5 GB750 MB
Admin20 GB2 GB
Guest100 MB50 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, actorUserId
  • action (15 ENUMs: DROP_RECEIVED, DROP_READ, DROP_ARCHIVED, …)
  • documentId, metadata (JSON), optional reason

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 (Inbox aus 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: MeinFachHub mit 4 Sektionen (Dokumente / Postfach / Archiv / Einstellungen)
  • Quota-Anzeige im Header mit farbcodiertem Progress-Bar (gruen/amber/rot)

Funktionen

SektionFunktional?
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 (distributionId in inbox_drop_meta), aber Distribution-Tabelle und Verteilungs-Logik kommen erst in Phase 2
  • Auto-Cleanup-CronexpiresAt wird 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

bash
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-api

Migration 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:

bash
# 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

bash
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 Tenants

Oder direkt auf Tenant-Server:

bash
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.spaceId jetzt nullable — bestehende Code-Pfade mussten in documents-global.router.ts angepasst werden (d.space?.name ?? null). Andere Stellen, die spaceId direkt lesen, koennten ueberraschen — bitte vor Deploy grep -rn "spaceId" src/ durchsehen.
    • Verifiziert: tsc --noEmit laeuft sauber → kein TS-Fehler in der Codebase
  • prisma generate muss 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 keine prilog-module.json nach dist/. 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.