- Administrator -> Module -> Kategorien: anlegen, umbenennen, sortieren, Eintraege zuordnen und sortieren, loeschen mit Zielauswahl
- Marktplatz-Filter folgen der Kategorienreihenfolge, Kategorieseite und Modulliste zeigen gespeicherte Namen
- Formular fuer eigene Module bietet alle Kategorien der Organisation an
- Texte de/en, CHANGELOG, Handbuch Administration und Anwender
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Verwaltungs-Endpunkte nur fuer Administratoren, statische Routen vor :key
- Loeschen verschiebt alle Eintraege inkl. persoenlicher eigener Module in einer Transaktion, ohne Ziel 409
- /modules, /modules/catalog und /module-grants/matrix liefern wirksame Kategorie und Reihenfolge
- eigene Module pruefen die Kategorie gegen die Organisation (400 bei unbekannter)
- Zugriffsinventar nachgezogen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Tabellen ModuleCategory und ModuleCategoryPlacement mit Zeilenschutz, Spalte CustomModule.sortOrder
- Dienst legt den Grundbestand beim ersten Lesen an, legt die wirksame Kategorie ueber Modullisten
- GET /module-categories, PATCH :key (nur Administratoren), /modules/active liefert wirksame Kategorie
- Seitenleiste ordnet Gruppen und Eintraege nach Kategorienspeicher, zeigt umbenannte Namen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Endpunkt für letzte Übergänge der abonnierten Clouds, globaler Melder im Portalrahmen (Desktop: Windows-Benachrichtigung)
- Anleitung für Anwender und Administration, Changelog
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Wiederholungsauftrag jede Minute für Clouds mit einem Fehlschlag älter als fünf Minuten
- Neue Adresse setzt den Prüfstand zurück, der gemeldete Zustand bleibt
- Kachel: Hinweis Prüfung fehlgeschlagen, Fehlercodes als lesbarer Text mit Tooltip
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Glocke je Kachel (persönlich, Benutzen-Ebene), Tabelle NextcloudAlertSubscription mit RLS
- Zwei-Fehlschläge-Regel und gemeldeter Zustand auf der Zeile, Anspruch vor dem Mailversand
- Mail (nur Deutsch) über MailService, bis zu drei Versuche, Zugriff beim Senden erneut geprüft
- Fehlercodes in der Mail als lesbarer Hinweis
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Kachel mit Zählern und roten/gelben Clouds, nur mit Modulzugriff sichtbar (geteilte Widget-Typen, Modulzuordnung, Katalog)
- Anleitung für Anwender und Administratoren, Eintrag im Changelog
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Ändern, Entfernen, Logo-Upload und -Abruf, Sammelprüfung nur mit Verwalten
- Stündlicher Auftrag beim Start registriert, Prüfung je Cloud an ihren Mandanten gebunden
- Sortierung nach Kundenname, Status, Version und Support-Ende, je Benutzer gemerkt
- Formular zum Anlegen und Bearbeiten, Zugriffsinventar angepasst
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- NextcloudInstance mit Zeilenschutz, Migration 20261002150000
- Bewertung (Ampel) als reine Funktion, status.php-Abruf mit Grenzen, endoflife.date-Zwischenspeicher
- API: Liste mit Bewertung, Anlegen und Einzelprüfung nur mit Verwalten
- Modulseite mit Kacheln, Registrierung in Seitenleiste, Marktplatz und Symbolen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Matrix und Benutzerdetails liefern und zeigen die Stufe, Auswahlfeld Benutzen/Verwalten
- Gruppen mit Verwalten sind in den Benutzerdetails markiert
- Administrationshandbuch, Anwenderanleitung und Changelog beschreiben die Stufen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Prisma-Modelle HandelswareDatevConfig und HandelswareKonto mit Zeilenschutz (Migration 20261002130000)
- XLSX lesen (B1 Kopf, A/B ab Zeile 2, Zahl oder deutscher Text), Konten zuordnen, TXT erzeugen
- neue Konten werden nur beim Export in einer mandantengebundenen Transaktion gespeichert (409 bei geaenderter Liste)
- Konten-CSV Import (alles ersetzen) und Export mit Schutz vor Formeleinschleusung
- Einstellungen nur fuer Administratoren, statische Routen vor accounts/:id
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- neue Seitenleisten-Kategorie accounting (Finanzbuchhaltung / Financial accounting)
- CSV (UTF-8, UTF-8 mit BOM, Windows-1252) pruefen, Vorschau mit Zeilenfehlern, DATEV-Lohn-ASCII-Export
- Beraternummer, Mandantennummer, Lohnart je Mandant als Admin-Einstellung (KantineDatevConfig mit Zeilenschutz), anfangs leer
- hochgeladene Daten werden nicht gespeichert; Download per Blob (auch im Desktop-Client)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Neue Felder loginHintDirectory/loginHintLocal (Platzhalter, Pflicht, max. 1000),
Migration 20260930170000 (nullable, leer = Standard aus @tessera/shared).
Knopf Passwort festlegen und Gueltigkeitshinweis bleiben fest; local-no-link
wird nie erzeugt und bleibt fest. Vorschau springt beim Bearbeiten auf die
passende Kontoart. Lokal im Browser nachgewiesen.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Administrator -> Willkommensmail: Betreff, Ueberschrift, Einleitung, Abschluss je
Mandant (Tabelle WelcomeMailTemplate, RLS je Mandant, Migration 20260930150000);
Platzhalter {{name}} {{vorname}} {{benutzername}} {{email}} {{adresse}} {{firma}},
unbekannte -> 400 bzw. Hinweis beim Tippen; Werte escaped, Vorlage reiner Text.
Live-Vorschau per API gerendert, Testmail an die eigene Adresse ohne Token,
Zuruecksetzen auf Standard. Feste Bausteine (Kopf, Zugangsdaten, Anmeldehinweis,
Knoepfe, Fusszeile) bleiben immer drin.
Kopf: Wellenzelle dunkel statt weiss, Streifen 600x40, Inhalt 24 px naeher –
keine weisse Luecke, wenn OWA das CID-Bild nicht zeigt.
Lokal nachgewiesen: Hinweis/Sperre bei {{xyz}}, Speichern, Testmail (Link nur
/login), echte Mail mit eigener Vorlage und 7-Tage-Link.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
POST /users/:id/welcome-mail (gleiche Rechte wie Bearbeiten, jederzeit sendbar),
GET /users/welcome-mail/status; HTML-Mail (Tabellenlayout, Inline-Stile,
Kopfbild als CID-PNG aus assets/mail/welcome-header.svg, erzeugt mit
scripts/render-mail-header.mjs) plus Textfassung. Verzeichniskonten: Hinweis
auf Windows-Passwort; lokale Konten: Link Passwort festlegen (7 Tage, einmalig).
Neue Spalte User.welcomeMailSentAt (Migration 20260930120000). Benutzerliste:
Spalte Letzte Anmeldung, Zeilenaktionen als Symbole. Dockerfile kopiert
apps/api/assets. Lokal per MailHog nachgewiesen.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Je Reiter wird die Flaeche des ersten Desktop-Bildschirms als __canvas im
Layout-JSON gespeichert (ohne API/DB-Aenderung, GRID_VERSION bleibt 3).
Das Raster rendert in Leinwandbreite und wird per transform: scale(min(bw/cw, bh/ch))
eingepasst, Schrift eingeschlossen, ohne Scrollen; unter 768 px wie bisher.
Ziehen/Groesse aendern unter Skalierung ueber eine eigene Positionsstrategie
(createScaledStrategy aus react-grid-layout 2.2.3 rechnet den Rasterversatz falsch).
Im Browser nachgewiesen: 1920x1080 -> 1366x768 (Faktor 0,66), Ziehen +200 px
folgt der Maus, 700 px ohne Skalierung.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PMG kennt keine API-Token (Proxmox-Bugzilla 5849, offen); Schritt-fuer-Schritt
fuer Oberflaeche und Kommandozeile, Rolle an Benutzer UND Token.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Layout mit neuerer Rasterversion wird nie gespeichert, Bearbeiten gesperrt mit Hinweis
- Kalender minW 11 (~260 px bei lg), Breiten je Breakpoint auf Spaltenzahl begrenzt
- optimistische Ruecksetzung nur, wenn noch der gesetzte Wert steht
- Titel-Schalter mit fester Beschriftung + aria-pressed
- Hintergrund-Dialog: Fokus rein/zurueck, Tab bleibt im Dialog
- Loeschen eines Bildes setzt eine darauf zeigende Hintergrund-Wahl zurueck
- Uebersetzungen und CHANGELOG
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- E-Mail-Planer: Anspruch vor dem Senden (genau eine Mail je Faelligkeit, hoechstens 3 Versuche), Systemlesen nur fuer die Kandidatenabfrage
- MailService.sendReminderEmail (Berliner Zeit, nur Text), GET /reminders/email-status, Haken im Formular mit Erklaerung
- Zugriffsklassifikation und Erlaubnisliste fuer forSystem nachgezogen, Aenderungsliste und Anwenderanleitung
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- API: Aendern (409 wenn faellig), Spaeter erinnern (409 wenn nicht faellig, setzt E-Mail-Spur zurueck), Loeschen; fremde Kennungen 404
- Kachel: faellige Zeilen hervorgehoben mit Erledigt und drei Spaeter-Optionen, kuenftige mit Bearbeiten und Loeschen
- Zeit-Hilfen (morgen zur gleichen Uhrzeit), Zugriffsklassifikation nachgemessen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Reminder-Tabelle mit Zeilenschutz (Mandant+Benutzer, Systemlesen fuer den E-Mail-Planer), API reminders (Liste, Anlegen)
- Kachel "Erinnerungen", globaler Melder im Portalrahmen (Browser und Desktop, je Faelligkeit einmal)
- Desktop: Laufzeit-Berechtigung fuer Benachrichtigungen nur fuer die gespeicherte Server-Adresse
- Zugriffsklassifikation nachgemessen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CUSTOM_MODULE_CATEGORIES = MODULE_CATEGORIES + custom-modules; API prueft
dagegen, das Formular bietet sie an. Die Seitenleiste zeigt die Gruppe wie
jede Kategorie nur mit Eintrag und stellt sie immer ans Ende. Nutzerwunsch
29.09.; ohne Migration (category ist Freitext mit IsIn-Pruefung).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Die Zentrierung der belegten Spalten (Design Mosaik, Runde 3) liess
Widgets nach dem Bearbeiten springen, z. B. ein einzelnes Widget oben
links in die Seitenmitte (Nutzer, live 29.09.). Auf Wunsch ersatzlos
entfernt: Ansicht = Bearbeitungsraster. centeringOffset, breakpointFor
und die ungenutzte Prop onInsetChange entfallen.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- ownerUserId (NULL = gemeinsam, sonst persoenlich) mit Zeilenschutz nach Muster SearchProvider
- GET nur gemeinsame + eigene, fremde persoenliche Eintraege 404
- POST fuer jeden Benutzer, shared nur fuer Administratoren (403)
- PATCH/DELETE: persoenlich nur Besitzer, gemeinsam nur Administrator
- Zugriffsklassifikation nachgemessen: 61/223/6
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Hover-Anheben samt Schatten ersatzlos entfernt (Wunsch des Nutzers:
Kacheln statisch, unabhaengig von Maus/Touch). Einblenden beim Laden
bleibt. CHANGELOG und Anwender-Anleitung angepasst.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Tabelle CustomModule mit Zeilenschutz (tenant_isolation_policy), Migration 20260929120000
- API /custom-modules: Lesen für jeden Angemeldeten, Schreiben nur Administrator, nur https ohne Zugangsdaten
- Seitenleiste zeigt eigene Module unter ihrer Kategorie, Rahmen-Seite mit Sandbox und „In neuem Tab öffnen“
- MODULE_CATEGORIES als gemeinsame Liste, Zugriffsklassifikation nachgemessen fortgeschrieben
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Spalte User.dashboardBackground (JSONB) samt Migration
- PATCH /users/me/dashboard-background, geprueft mit parseDashboardBackground aus @tessera/shared (Allowlist, UUID-Bildkennung)
- getMe liefert dashboardBackground normalisiert neben accentColor
- Web liest die Wahl aus dem Auth-Store, speichert ueber die Server-Aktion, alte localStorage-Wahl wird einmalig uebernommen
- Hinweistext: gilt auf jedem Geraet
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- CHANGELOG Unveroeffentlicht -> Neu
- Anwenderhandbuch: Fenster nach einem Versionswechsel
- Entwicklerdoku: erweiterte Importregel fuer @/lib/changelog, Versionsquelle,
Endpunkte, Spalte, Folge fuer die Freigabe
- Kopfkommentare changelog.ts und next.config.ts angepasst
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Migration 20260924120000_dashboard_image_drop_data: Schutzpruefung
(bricht ab, solange eine Zeile ohne storagePath existiert; row_security
aus, damit ein Eigentuemer ohne BYPASSRLS nicht still 0 Zeilen sieht),
dann NOT NULL, DROP COLUMN data, DROP POLICY system_read_policy
- Dienst: Bootstrap-Umzug samt forSystem() und Selbstheilung aus data
entfernt; Upload vergibt die UUID selbst, Zeile gleich mit Pfad
- FORSYSTEM_ALLOWED_CALL_SITES, Tests, Zugriffsklassifikation (per
Gate-Schleife gemessen: 61/213/6) nachgezogen
- Betriebshandbuch Kap. 4: Hinweis und Wiederherstellungsweg bei Abbruch
- Todo 2026-09-22 nach completed/
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- FavoriteLink: neue Spalten uploadedIconMime/iconVersion (Migration 20260923160000)
- favorite-icon-files.ts: Erkennung PNG/JPEG/GIF/WebP/ICO/SVG, Pfadbildung ohne
Byte aus der Anfrage im Pfad (T-LRR-01), best-effort Dateientfernung
- FavoritesService: uploadIcon/removeUploadedIcon, Vorrang der hochgeladenen
Datei in getIconBytes, Abrufprobe fuer eine neue iconUrl (422 statt stiller
Speicherung), iconVersion-Erhoehung bei jeder Aenderung der Symbolquelle
- FavoritesController: POST/DELETE /favorites/:id/icon, Cache-Control private
- T-LRR-07 (Restrisiko aus dem Plan-Threat-Model geschlossen, ueber den Plan
hinaus): DashboardService.removeWidget/deleteDashboard raeumen jetzt die
Symboldateien der per Datenbank-Kaskade mitgeloeschten Favoriten auf
(best effort, nie blockierend)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- docs/anleitung-anwender.md: neuer Abschnitt "Proxmox" (Modulzahl vier
auf fuenf korrigiert) — was das Modul zeigt, Server anlegen, NUR-LESE-
Rolle je Produkt, PMG nur Benutzer/Passwort, Zertifikatspruefungs-
Schalter, "Verbindung testen", "unbekannt", D-01 ausdruecklich
festgehalten. Plan nannte "docs/anwenderhandbuch.md" (existiert nicht
im Repo) — echter Dateiname ist docs/anleitung-anwender.md, dort
angewendet (Rule 3, blockierender Pfadfehler)
- docs/anleitung-entwicklung.md: proxmox als Vorlage fuer ein Modul mit
Fremdsystem-Zugaengen und Hintergrundabfrage verlinkt, undici-
Dispatcher-Falle als Merksatz ergaenzt (war noch nicht dokumentiert)
- docs/mandantentrennung-zugriffsklassifikation.md: Bereichsuebersicht
und Summenzeile fuer Aufgabe 5 nachgezogen (war nach Aufgabe 5 noch
offen) — proxmox jetzt 0/11/1, Summe 61/208/7, mit der Gate-Schleife
nachgemessen
Endstand aller Tore gegen die Ausgangswerte des Plans:
- api-Tests: 1311 (Ausgangswert 1240, Ziel >=1240)
- web-Tests: 708 (Ausgangswert 693, Ziel >=693)
- type-check: 4/4
- lint: 5/5
- Biome-Warnungen apps/web: 53 (Ausgangswert 53, exakt unveraendert)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- proxmox-scheduler.service.ts: ein Cron-Auftrag je aktivem Mandant
(proxmox-poll:<tenantId>), onApplicationBootstrap (nicht onModuleInit,
Tender-Muster), Abfrageintervall = kleinstes pollIntervalMin der
aktiven Server, ein fehlgeschlagener Server bricht die Tick-Schleife
nicht ab, refreshTenant() zieht nach jedem Speichern sofort nach
- proxmox.service.ts: loadActiveServersForScheduler() als einziger
forSystem()-Aufruf des Moduls (Erlaubnisliste in
rls-access-inventory.spec.ts), testConnection() schreibt nicht ins
Zwischenlager, pollServer() bekommt eine Zehn-Sekunden-Sperre (T-DHH-06)
- proxmox.controller.ts: POST servers/:id/test, create() zieht den
Planer nach dem Anlegen sofort nach
- Zugriffsklassifikation: proxmoxServer wechselt auf system-gebunden
(Startpfad des Planers), proxmoxServerStatus bleibt gebunden
Tore: api 1306/1306 (>=1240), type-check 4/4, rls-access-inventory
und rls-coverage gruen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs/anleitung-anwender.md: neuer Absatz "Mehrere Dashboards (Reiter)" im
Dashboard-Abschnitt, Alltagssprache - mehrere Dashboards nebeneinander,
Ziehen legt den Standard fest, Anlegen/Umbenennen/Loeschen im
Bearbeitungsmodus, der letzte Reiter bleibt.
CHANGELOG.md: ein Stichpunkt unter "Unveroeffentlicht" > "Neu" - was der
Benutzer sieht, mit dem ausdruecklichen Hinweis, dass vorhandene Kacheln
unveraendert auf dem ersten Reiter liegen bleiben.
docs/mandantentrennung-zugriffsklassifikation.md: Endstand nach Task 2
nachgerechnet (nicht aus Task 1 abgeschrieben) - Bereich dashboard 24->28
gebunden (Task 2 bringt vier weitere `tenantPrisma.dashboard.`-Rohtreffer:
createDashboard/renameDashboard/deleteDashboard), Summe 193->197. Die
Begruendungsspalte des Paares dashboard.service.ts/dashboard nennt jetzt
auch Task 2 (withTenantTransaction fuer deleteDashboard/reorderDashboards,
Muster favorites.service.ts/reorder). Paarzahl (75) unveraendert - Task 2
fuegt keine neuen (Datei,Modell)-Paare hinzu, nur weitere Rohtreffer
bestehender Paare.
Alle Tore nachgemessen: api 1240 Tests in 77 Dateien gruen (>= 1202/77),
web 693 Tests in 82 Dateien gruen (>= 661), type-check 4/4, lint 5/5 mit
genau 53 Warnungen in web, `prisma migrate diff` weiterhin ohne Unterschied.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neues Modell Dashboard (D-01/D-02/D-09): position statt Standard-Feld,
kein Unique auf (userId, position) - Umsortieren schreibt spaeter alle
Positionen einer Transaktion neu. WidgetInstance/DashboardLayout haengen
jetzt am Reiter statt am Benutzer (DashboardLayout.dashboardId @unique
ersetzt userId @unique).
Migration 20260923120000_dashboard_tabs: Zeilenschutz mit Mandant- UND
Benutzerdimension (Form 20260911120000/20260921120000), Bestands-
uebernahme fuer jeden Benutzer mit Kacheln oder Anordnung VOR den
Fremdschluesseln (D-03) - gemessen: 0 Kacheln/Anordnungen ohne Reiter,
genau 2 Reiter auf Position 0.
dashboard.service.ts: listDashboards() (Transaktionssperre gegen
doppelte Erstanlage, T-AD9-07), Riegel assertOwnedDashboard() (fail-
closed gegen fremde Reiter, T-AD9-01/02/03) - getLayout/saveLayout/
getWidgets/addWidget laufen jetzt ueber dashboardId statt userId.
GET /dashboard/tabs neu; die vier bestehenden Wege reichen die Reiter-
Kennung durch. Verhalten fuer den Benutzer unveraendert (ein Reiter,
wie bisher) - Task 2 ergaenzt Anlegen/Umbenennen/Loeschen/Umsortieren.
dashboard.service.spec.ts: 43 Tests (31 alte unveraendert + 12 neue fuer
Reiter-Anlage, -Reihenfolge und den Fremdreiter-Riegel bei allen vier
Wegen). Zugriffsklassifikation nachgerechnet: 75 Paare (+1), Bereich
dashboard 21->24 gebunden.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- eine Kachel ohne Bauteil (entfernter Typ oder gesperrtes Modul) zeigt
statt des rohen Typnamens den Satz `widgets.unavailable`, zentriert und
grau; Schluessel in de.json und en.json
- Entwicklerdoku: neuer Abschnitt "Eine Kachel zum Modul" im
Modul-Walkthrough — die drei verbliebenen Stellen und was eine Kachel
mit moduleSlug automatisch tut
- Changelog unter "Unveroeffentlicht - Geaendert"
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Changelog unter Unveroeffentlicht -> Geaendert: Bilder liegen im
Dateibereich, vorhandene ziehen beim ersten Start automatisch um
- Betriebsanleitung Kap. 6: user-files nennt die Bilderrahmen-Bilder und
haelt fest, dass pg_dump allein sie nicht mehr enthaelt
- Todo fuer Stufe 2 (DROP data, storagePath NOT NULL) mit Vorbedingung,
Migrationsname und den Nacharbeiten an Spec und Klassifikation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Bytes liegen unter user-files/dashboard-images/<userId>/<id>.<ext>, die
Zeile haelt nur noch storagePath (Muster User.avatarPath)
- Dateiname immer servergeneriert: UUID der Zeile + Endung aus dem
ERKANNTEN Mime-Typ, originalName kommt in keinem Pfad vor (T-HK4-01)
- Migration 20260922120000: storagePath dazu, data wird NULLbar, kein DROP
(zweistufig, T-HK4-03); system_read_policy fuer den Umzug
- onApplicationBootstrap zieht Altbestand automatisch um: systemgebunden
lesen, je Zeile mandantengebunden schreiben (Muster DKV-Planer)
- Upload nimmt die Zeile bei fehlgeschlagenem Schreiben zurueck, Loeschen
entfernt die Datei mit, fehlende Datei -> 404 (T-HK4-04)
- 11 neue Dienst-Tests gegen ein echtes Temp-Verzeichnis (kein fs-Mock)
- Zugriffsklassifikation: Stand system-gebunden, Zahlen nachgemessen
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Changelog: Stichpunkt direkt nach dem XFrame-Stichpunkt unter Unveroeffentlicht -> Neu
- Anwenderhandbuch: je ein Satz in der Widget-Tabellenzeile und im Absatz "Dashboard > Widgets"
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- CHANGELOG: Stichpunkt als erster unter "Unveroeffentlicht -> Neu"
- Anwenderhandbuch: Zeile in der Widget-Tabelle, erweiterter Satz zu den
Widget-Einstellungen, Absatz-Zusatz unter "Dashboard > Widgets"
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- CHANGELOG.md: erster Stichpunkt unter Unveroeffentlicht -> Neu
- docs/anleitung-anwender.md: Zeile in der Widget-Tabelle, Absatz zur
Bildverwaltung unter Dashboard > Widgets
- umlaut-dictionary.ts: „Webadresse“ und „Bildausschnitt“ als korrektes
Deutsch auf die Erlaubnisliste des Umlaut-Waechters (der volle Web-Testlauf
hatte die beiden neuen ss-Woerter aus de.json gemeldet)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Prisma-Modell DashboardImage (bytea) mit Migration 20260921120000: Tabelle,
Indizes, RLS ENABLE/FORCE und tenant_isolation_policy mit Benutzerdimension
- dashboard-image-rules.ts: detectImageMime ueber Magic Bytes (PNG/JPEG/GIF/
WebP), Grenzen 5 MiB je Datei und 30 je Benutzer
- DashboardImagesService: list/upload/getBytes/remove, je Methode
forTenant(prisma, tenantId, userId); Besitz = Mandant UND Benutzer, sonst 404
- DashboardImagesController unter dashboard/images: GET, POST (FileInterceptor
image, 5 MiB, eine Datei), GET :id mit Content-Type aus dem erkannten Typ,
Cache-Control private, nosniff, Content-Disposition inline ohne Dateinamen,
CSP sandbox; DELETE :id
- CreateWidgetDto kennt 'picture-frame'
- Klassifikationsdokument: neues Paar dashboard-images.service.ts/
dashboardImage; Bereichs- und Summenzeilen nachgemessen (dashboard 12->18,
settings 3->4 und bug-reports waren in der Summe nie mitgezaehlt)
- Befund: Prisma-Bytes verlangt Uint8Array<ArrayBuffer>, multers Buffer wird
ohne Zusicherung abgelehnt - Kopie per new Uint8Array(buffer) statt Cast
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Der Lint-Abschnitt trug noch den Zwischenstand aus Aufgabe 1 (754/633/121).
Jetzt der tatsaechliche Endstand nach allen drei Aufgaben, beide Ausnahmen
weiterhin begruendet, plus die namentlich benannten Folgeaufgaben: fuenf
zurueckgestellte a11y-Regeln, die bewusst nicht angewendete
noUselessSwitchCase-Fundstelle, und die vier gemeldeten D-03-Symptomfunde.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J