12 KiB
phase, plan, subsystem, tags, status, requires, provides, affects, tech-stack, key-files, decisions, metrics, actuals, plan_head_before
| phase | plan | subsystem | tags | status | requires | provides | affects | tech-stack | key-files | decisions | metrics | actuals | plan_head_before | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260922-m1h | 01 | apps/web/src/components/dashboard |
|
complete |
|
|
|
|
|
|
|
ee2b025 |
Quick-Aufgabe 260922-m1h: Ein Modul bringt seine Dashboard-Kachel selbst mit — Zusammenfassung
Die Kachel-Typliste stand an sieben Stellen; sie steht jetzt an einer. Der Katalog fuehrt keine zweite Liste mehr und blendet Kacheln gesperrter Module aus, eine Kachel ohne Bauteil erklaert sich mit einem Satz statt leer zu bleiben. Die neun vorhandenen Kacheln verhalten sich unveraendert.
So fuegt man kuenftig eine Modul-Kachel hinzu
Vorher sieben Stellen, jetzt drei (plus das Uebliche an Text und Maßen):
- Kachel-Komponente schreiben —
apps/web/src/components/dashboard/widgets/<name>-widget.tsx, nimmtWidgetProps(instanceId,config,isEditMode). - Typ eintragen — in
WIDGET_TYPESinpackages/shared/src/index.ts. Gehoert die Kachel zu einem Modul, zusaetzlichWIDGET_MODULE_SLUGS['<typ>'] = '<modul-slug>'in derselben Datei. Das ist die einzige Liste — die API validiert per@IsIngegen genau sie. - Anmelden —
registerWidget('<typ>', <Name>Widget)inapps/web/src/app/(portal)/page.tsx.
Dazu wie bei jeder Oberflaeche: Uebersetzungsschluessel <typ>.name und <typ>.description unter
widgets in de.json und en.json, ein Inline-SVG-Symbol und die Groessenvorgaben in
WIDGET_CONSTRAINTS — Symbol und Maße in widget-registry.tsx.
Eine Kachel mit moduleSlug verschwindet danach von selbst aus Katalog und Dashboard, wenn der
Benutzer das Modul nicht nutzen darf. Vergisst man eine der drei Stellen, schlaegt der
Deckungsgleichheits-Test in widget-registry.test.tsx fehl, statt dass die Kachel im Katalog fehlt
oder die API mit 400 antwortet.
Dieselbe Liste steht als Abschnitt „Eine Kachel zum Modul" in
docs/anleitung-entwicklung.md.
Was gebaut wurde
Aufgabe 1 — 56c07c3 (refactor)
packages/shared/src/index.ts:WIDGET_TYPES,WidgetType,WIDGET_MODULE_SLUGS.create-widget.dto.ts:@IsIn([...WIDGET_TYPES])statt handgepflegter Liste.widget-module-map.ts: liestWIDGET_MODULE_SLUGSstatt einer eigenen Kopie; die oeffentliche FunktiongetModuleSlugForWidgetType()ist unveraendert, damitdashboard.service.spec.tssie weiter mocken kann.widget-registry.tsx: neunwireXWidget()→ einregisterWidget()(idempotent; unbekannter Typ wirft in der Entwicklung, wird in der Produktion ignoriert).WidgetDefinitiontraegtmoduleSlug?. Neue reine FunktionvisibleWidgetTypes(registry, slugs|null).widget-catalog-modal.tsx: Liste kommt aus der Registry (Reihenfolge erhalten, Test darauf), gefiltert nach Modulzugriff; neue PropaccessibleModuleSlugs.(portal)/page.tsx: neunregisterWidget-Aufrufe; holt/modules/activeim Muster der Seitenleiste (credentials: 'include', Fehler still) und reicht die Slugs an den Katalog durch.
Aufgabe 2 — 8be0725 (docs)
widget-wrapper.tsx: Kachel ohne Bauteil zeigtwidgets.unavailablezentriert und grau statt des rohen Typnamens; Schluessel in de.json und en.json.- Changelog-Stichpunkt unter „Unveroeffentlicht → Geaendert"; Entwicklerdoku-Abschnitt.
Abweichungen vom Plan
1. [Rule 3 — blockierend] Die Planannahme „apps/web importiert @tessera/shared bereits" war falsch
- Gefunden bei: Aufgabe 1, vor der ersten Zeile Code.
- Befund:
apps/webhatte keine Abhaengigkeit auf@tessera/shared. Zwei Kommentare (lib/app-version.ts,lib/desktop.ts) dokumentierten das sogar ausdruecklich als Absicht und begruendeten damit gespiegelte Typen. Ohne Abhaengigkeit ist Entscheidung 1 des Plans nicht umsetzbar. Zudem waren alle bisherigen@tessera/shared-Importe inapps/apireineimport type— die Typliste ist aber ein Laufzeitwert. - Geprueft statt vermutet:
nest buildmit einem Laufzeit-Import: laeuft; das Ergebnis laedt@tessera/sharedim fertigendisttatsaechlich (nachgestellt, 9 Typen).packages/sharedliefert rohes TypeScript ohne Bauschritt — innode:24-alpinedirekt geprueft: Node 24 laedt es per nativem Type-Stripping (OK [ 'clock', 'xframe' ] {}).- Die alte Gegenbegruendung ist ueberholt: der Web-Dockerfile kopiert
packages/sharedin deps- und builder-Stufe bereits. Es aendert sich nur das Lockfile (3 Zeilen). pnpm --filter @tessera/web buildlaeuft durch — ohnetranspilePackages.
- Umsetzung:
@tessera/shared: workspace:*inapps/web/package.json. Die beiden Kommentare, deren Begruendung dadurch unwahr wurde, sagen jetzt den aktuellen Stand; die Typ-Spiegel selbst blieben bewusst unangetastet (nicht Teil dieser Aufgabe). - Nebenwirkung fuer die Zukunft:
packages/shared/src/index.tsdarf nur noch loeschbare Syntax enthalten — keinenum, keinnamespace, keine Parameter-Eigenschaften. Steht als Warnung in der Datei.
2. [Abweichung vom Auftrag des Orchestrators] Keine gemeinsame Hilfsfunktion fuer /modules/active
Der Auftrag nannte „dieselbe Hilfsfunktion wie die Seitenleiste". Eine solche gibt es nicht: die
Seitenleiste hat einen eingebauten fetch, und lib/api.ts#getActiveModules ist serverseitig
(Cookie-Header, kein credentials). Die Dashboard-Seite benutzt daher dasselbe Muster wie die
Seitenleiste. Eine Hilfsfunktion herauszuloesen haette sidebar.tsx angefasst — ausserhalb dieser
Aufgabe.
Bewusst offen gelassen
widget-settings-panel.tsx— der Einstellungs-Zweig je Typ bleibt wie er war. Den generisch zu machen ist ein eigener Umbau (so im Plan festgelegt). Die Datei wurde nicht angefasst.- Die Typ-Spiegel in
lib/app-version.tsundlib/desktop.tskoennten jetzt echte Importe werden. Nicht gemacht, nur die Kommentare richtiggestellt. - Katalog aktualisiert sich nicht live, wenn im Marketplace gerade ein Modul freigeschaltet
wird — die Seitenleiste tut das ueber
sidebarRefreshKey, die Dashboard-Seite holt die Liste nur beim Aufbau. Heute ohne Wirkung (keine Kachel hat einenmoduleSlug); mit Proxmox reicht ein Neuladen der Seite. Bewusst so, weil der Auffrisch-Ausloeser einenbiome-ignoreerzwungen haette, den die Qualitaetsregeln dieser Aufgabe ausschliessen.
Keine Stubs
Es wurden keine Platzhalter, leeren Rueckgaben oder „coming soon"-Texte eingebaut.
WIDGET_MODULE_SLUGS ist leer — das ist kein Stub, sondern der korrekte Zustand: alle neun Kacheln
sind Plattform-Kacheln. Die erste Modul-Kachel (Proxmox) traegt sich dort ein.
Bedrohungsmodell
| ID | Stand |
|---|---|
| T-M1H-01 | Akzeptiert wie geplant. Der Katalogfilter ist Komfort; im Code an drei Stellen so kommentiert. Durchsetzung bleibt DashboardService.getWidgets (unveraendert, 85 Tests gruen). |
| T-M1H-02 | Unveraendert — diese Aufgabe schwaecht nichts ab. Fuer Proxmox bleibt @UseModule(slug) verbindlich. |
| T-M1H-03 | Mitigiert. Reine Konstantenliste, keine Laufzeitdaten; die API validiert weiterhin @IsIn gegen genau diese Liste — jetzt nachweislich (Test validiert alle neun Typen und lehnt einen unbekannten ab). |
| T-M1H-04 | Mitigiert. accessibleModuleSlugs === null blendet Kacheln MIT moduleSlug aus; Test im Katalog und in visibleWidgetTypes. |
Zahlen
| Commits | 2 (56c07c3, 8be0725), Basis ee2b025 |
| Dateien geaendert | 20 (1 neu) |
| Zeilen | +610 / −150 (gemessen: git diff --shortstat ee2b025 HEAD) |
| Neue Tests | 29 (Registry 9, Katalog 3, Seite 2, widget-module-map.spec.ts 14, Wrapper 1) |
| API-Tests | 1202 gruen (76 Dateien) |
| Web-Tests | 659 gruen (81 Dateien) |
| type-check | sauber (4 Pakete) |
| lint | api 74 / web 53 Warnungen — unveraendert zur Basis |
as unknown as |
api 27 / web 6 — unveraendert |
neue any / ! / biome-ignore |
0 / 0 / 0 |
| Next.js-Produktionsbau | laeuft |
nest build |
laeuft |
Browser-Pruefliste
Der Umbau ist verhaltensneutral — die Pruefung soll vor allem bestaetigen, dass nichts anders
aussieht. Lokalen Stack neu bauen (--build), dann im Portal:
- Dashboard oeffnen. Alle bisherigen Kacheln stehen an ihrem Platz und funktionieren wie vorher (Uhr laeuft, Kalender zeigt Termine, Bilderrahmen wechselt, XFrame laedt).
- Stift → „Widget hinzufuegen". Der Katalog zeigt neun Kacheln in genau dieser Reihenfolge: Uhr, Suchleiste, Kalender, Notiz, Taschenrechner, Favoriten, Stoppuhr, Bilderrahmen, XFrame. Namen und Beschreibungen unveraendert.
- Eine Kachel anlegen (z. B. Stoppuhr) — sie erscheint, laesst sich ziehen, vergroessern und wieder entfernen. Kein 400-Fehler.
- Groessen pruefen: eine frisch angelegte Kachel hat dieselbe Startgroesse wie frueher, und sie laesst sich nicht kleiner ziehen als bisher.
- Einstellungen → Dashboard: die Einstellungen je Kachel sind unveraendert da (dieser Bereich wurde bewusst nicht angefasst).
- Sprache auf Englisch umstellen — der Katalog bleibt vollstaendig, keine rohen Schluessel wie
clock.namesichtbar. - (optional, zeigt das Neue) Der Hinweis bei einer nicht verfuegbaren Kachel laesst sich heute
nur kuenstlich ausloesen — er greift erst mit der ersten Modul-Kachel. Wer ihn sehen will: in der
Datenbank den
widgetTypeeiner vorhandenen Kachel aufproxmoxsetzen und die Seite neu laden; die Kachel zeigt dann „Diese Kachel steht nicht zur Verfuegung — das zugehoerige Modul ist nicht freigegeben." statt leer zu bleiben. Danach zuruecksetzen.
Self-Check: PASSED
apps/api/src/dashboard/widget-module-map.spec.tsvorhanden.- Commits
56c07c3und8be0725ingit loggefunden. git diff --diff-filter=D ee2b025..HEAD— keine geloeschten Dateien.git rev-list --count ee2b025..HEAD= 2, gemessen..planning/**nicht committet.
Rundgang durch den Orchestrator (22.09.2026, lokaler Stack aus 8be0725)
Bestanden, keine Abweichung zum Stand vorher:
- Dashboard zeigt die bestehenden Kacheln (Kalender, Notizen, Favoriten, Bilderrahmen, XFrame) unveraendert, keine Konsolenfehler.
- Katalog zeigt neun Kacheln in der alten Reihenfolge: Uhr, Suchleiste, Kalender, Notizen, Taschenrechner, Favoriten, Stoppuhr, Bilderrahmen, XFrame; Namen und Beschreibungen unveraendert, keine rohen Schluessel.
- Stoppuhr angelegt → erscheint (396x160 px), wird gespeichert (
stopwatchinGET /dashboard/widgets), kein 400; danach wieder entfernt, Liste sauber. /modules/activewird beim Seitenaufbau abgerufen (4x 200) — der Katalogfilter hat seine Datenquelle.- Der Hinweis bei nicht verfuegbarer Kachel liess sich nicht echt ausloesen (es gibt noch keine Modul-Kachel); er ist durch den Test in
widget-wrapper.test.tsxgedeckt und greift mit Proxmox.