--- phase: 261008-who-eigene-module-beim-start-vorladen plan: 01 subsystem: custom-modules tags: [preload, iframe, prisma, nestjs, nextjs, zustand] requires: [261008-w5w] provides: - "Benutzer-Einstellung 'Beim Start vorladen' je eigenem Modul (User.customModulePreloadIds, PUT /custom-modules/:id/preload)" - "Vorlade-Planer + Preloader-Komponente (verzoegert, gestaffelt, unsichtbar)" - "Offenhalten-Grenze 8, gepinnte Module nie per LRU verworfen" affects: [custom-modules, app-shell, settings/custom-modules] key-files: created: - apps/api/prisma/migrations/20261008210000_user_custom_module_preload/migration.sql - apps/web/src/lib/custom-module-preload.ts - apps/web/src/components/modules/custom-module-preloader.tsx - apps/web/src/components/custom-modules/custom-module-preload-settings.tsx - .planning/quick/261008-who-eigene-module-beim-start-vorladen/e2e/e2e-preload-api.sh modified: - apps/api/prisma/schema.prisma - apps/api/src/custom-modules/* - apps/api/src/user/user.controller.ts - apps/web/src/lib/stores/custom-module-cache-store.ts - apps/web/src/components/modules/custom-module-frame-host.tsx - apps/web/src/components/modules/custom-module-view.tsx - apps/web/src/components/layout/app-shell.tsx - apps/web/src/messages/de.json - apps/web/src/messages/en.json - docs/anleitung-anwender.md - docs/mandantentrennung-zugriffsklassifikation.md - CHANGELOG.md - packages/shared/src/index.ts decisions: - "Speicherort: Spalte User.customModulePreloadIds (TEXT[]) statt eigener Tabelle - Benutzerzeile steht schon unter Zeilenschutz, keine neue RLS-Regel; tote Kennungen werden beim Lesen geschnitten, beim Schreiben entfernt" - "Schalter an zwei Orten: App-Leiste der Modulansicht und Karte in Einstellungen -> Eigene Module (alle sichtbaren Module, Zaehler x von 8)" - "Grenze acht gesamt; gepinnte zaehlen mit, werden nie verworfen; Server begrenzt Vorladen auf acht (409)" metrics: tasks: 3 commits: 3 plan_head_before: 1bb869a7b5245029ef28be844944e9b2914d2088 plan_head_after: 86495ae71be6fcb64bf2559a28ed8e376c91a925 status: complete actuals: tokens: 60000 tasks: 3 commits: 3 plan_head_before: 1bb869a7b5245029ef28be844944e9b2914d2088 plan_head_after: 86495ae71be6fcb64bf2559a28ed8e376c91a925 commits: 3 --- # Phase 261008-who Plan 01: Eigene Module beim Start vorladen Summary Pro Benutzer serverseitig gespeicherte Wahl "Beim Start vorladen" fuer eigene Module; Tessera laedt die gewaehlten Module 2 s nach dem Start gestaffelt (1,5 s Abstand) unsichtbar im bestehenden Rahmen-Behaelter, der erste Klick uebernimmt denselben iframe-Knoten ohne Neuladen; Offenhalten-Grenze von fuenf auf acht. ## Commits - ac10449 feat: Durchstich (Migration, API, Planer, Preloader, Speicher, Behaelter, E2E-Skript) - c7b6a4b feat: Schalter, Grenze acht mit gepinnten Modulen, Einstellungen-Karte, Texte de/en - 86495ae docs: Anleitung und CHANGELOG ## Wichtige Angaben - **Migrations-Zeitstempel:** 20261008210000 (`_user_custom_module_preload`), auf dem lokalen Stand angewendet (Spalte vorhanden, `prisma migrate status` sauber). - **Verhalten bei mehr als acht:** Server liefert 409 beim neunten Vorladen (tote Kennungen zaehlen nicht mit), Oberflaeche zeigt Hinweis, Kontrollkaestchen der Karte werden bei acht gesperrt. Extremfall: acht gepinnt plus ein aktives, nicht gepinntes = neun Rahmen; ein weiteres nicht gepinntes verdraengt das vorige. - **docs/anleitung-entwicklung.md:** per grep geprueft, keine Beschreibung der Architektur eigener Module/des Rahmen-Behaelters -> unveraendert. - **Modul-Changelog (261008-w5w):** kein Eintrag; eigene Module stehen nicht im Modul-Register (leere Liste). Nur Gesamt-CHANGELOG ("Unveroeffentlicht": Neu + Geaendert). Der alte Punkt "fuenf zuletzt benutzten" in einer freigegebenen Version bleibt als Historie stehen. - **Antworten mit Benutzerzeile:** `user.controller.ts` entfernt `customModulePreloadIds` aus den drei Antworten, die die ganze Zeile zurueckgaben (T-WHO-02); Listen nutzen `select`. ## Tests - API: 152 Dateien / 3049 Tests gruen (inkl. rls-coverage, rls-access-inventory); `tsc --noEmit` sauber. - Web: 148 Dateien / 1695 Tests gruen; `tsc --noEmit` sauber. - E2E `e2e-preload-api.sh` gegen neu gebauten Stack: `e2e preload api ok` (1-8 ok, 9 -> 409, "ja" -> 400, Zufalls-UUID -> 404, Aufraeumen). - Biome lint auf den geaenderten Dateien ohne neue Befunde (vorhandene Warnung in module-tile.tsx, Format-Abweichungen in user.controller.ts/shared index.ts bestanden schon). ## Browser-Messwerte (Chromium, Dunkelmodus, Neuladen mit bestehender Sitzung; `.playwright-mcp/custom-module-preload/t3-measure.json`) | Messwert | Ergebnis | |---|---| | frameCountAtStart | 2 (A, B; C nie) | | allHiddenAtStart / allWidthPositiveAtStart | true / true (Breite 1136 px) | | firstFrameAppearMs | 2539 (loadEventEnd 339) | | gapBetweenFramesMs | 1500 | | sameNodeAfterClick | true (2 Rahmen, derselbe Knoten) | | loadsAfterClick | 0 | | visibleAfterClick | true (1136 x 828) | | notPreloadedFramePresent | false | | Abmelden | 0 Rahmen; erneute Anmeldung: nur A und B | Bildschirmfotos: `t3-dark-preloaded-open.png`, `t3-dark-settings.png` (Karte "Beim Start vorladen", Zaehler 1 von 8). Probe-Module per curl geloescht. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] setPinned ignorierte die Serverwahl bei noch nicht offenem Rahmen** - **Found during:** Aufgabe 2 (Test Modulansicht) - **Issue:** `setPinned(id, true)` verlangt einen offenen Rahmen; beim ersten Laden der Modulansicht ist der Rahmen noch nicht in `openIds`, die Serverwahl wurde nicht gepinnt. - **Fix:** Die Ansicht und die Einstellungen-Karte rufen fuer "an" `preload(mod)` (nur bei gueltiger https-Adresse), fuer "aus" `setPinned(id, false)`. - **Files modified:** custom-module-view.tsx, custom-module-preload-settings.tsx - **Commit:** c7b6a4b **2. [Rule 3 - Blocking] Seitentest der Einstellungen zaehlte Listenaufrufe** - **Issue:** Die neue Karte ruft ebenfalls `listCustomModules`, der bestehende Test erwartet zwei Aufrufe. - **Fix:** Karte im Seitentest per `vi.mock` ausgeblendet (eigener Test fuer die Karte). - **Commit:** c7b6a4b **3. Fortsetzung nach abgebrochenem Lauf:** Aufgabe 1 war als unversionierter Arbeitsstand vorhanden; nach Pruefung (Tests, tsc, Migration angewendet, E2E) unveraendert uebernommen und committet. Sonst: Plan wie geschrieben. ## Known Stubs None. ## Threat Flags None - neue Route ist im Bedrohungsmodell (T-WHO-01..05) abgedeckt. ## Hinweise - Tote Kennungen geloeschter Module bleiben in der Benutzerzeile, bis der Benutzer das naechste Mal schreibt (Entwurfsentscheidung). - Nicht gepusht. ## Self-Check: PASSED Commits ac10449, c7b6a4b, 86495ae vorhanden; SUMMARY, Migration, Planer, Preloader, Karte, E2E-Skript vorhanden.