Files
tessera-ctl/apps/api/src/dashboard/dto/create-widget.dto.ts
T
schalli 9c518238f5 feat(quick-260923-ad9): Datenmodell, Migration und Reiter-Grundlage - Task 1
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>
2026-09-23 07:56:38 +02:00

30 lines
911 B
TypeScript

import { IsIn, IsObject, IsOptional, IsString } from 'class-validator';
import { WIDGET_TYPES } from '@tessera/shared';
/**
* DTO for creating a new widget instance on one dashboard tab.
*
* quick-260922-m1h: `widgetType` wird gegen `WIDGET_TYPES` aus
* `@tessera/shared` geprüft — dieselbe Liste, aus der das Frontend seine
* Registry und seinen Katalog ableitet. Vorher stand die Liste hier ein
* zweites Mal; vergaß man einen Eintrag, lehnte die API eine im Katalog
* angebotene Kachel mit 400 ab.
*
* quick-260923-ad9: `dashboardId` selects the tab — the service verifies
* ownership before writing (`assertOwnedDashboard`).
*
* config is optional and defaults to {} on the model.
*/
export class CreateWidgetDto {
@IsString()
dashboardId!: string;
@IsString()
@IsIn([...WIDGET_TYPES])
widgetType!: string;
@IsOptional()
@IsObject()
config?: Record<string, unknown>;
}