feat(quick-261003-387): Modulkategorien je Organisation - Tabellen, Grundbestand, Lese-Endpunkt bis in die Seitenleiste

- 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>
This commit is contained in:
2026-10-03 02:33:59 +02:00
parent 53a49a109f
commit 8ec116c75a
21 changed files with 1052 additions and 16 deletions
+42 -1
View File
@@ -120,6 +120,7 @@ model Module {
updatedAt DateTime @updatedAt
activations TenantModuleActivation[]
grants ModuleGrant[]
categoryPlacements ModuleCategoryPlacement[]
}
model TenantModuleActivation {
@@ -849,7 +850,11 @@ model CustomModule {
tenantId String
name String
url String
category String // eine der MODULE_CATEGORIES aus @tessera/shared
category String // Kennung einer ModuleCategory der Organisation
// quick-261003-387: Reihenfolge innerhalb der Kategorie (nur gemeinsame
// Eintraege; null = noch nicht sortiert, steht hinten). Persoenliche
// Eintraege bekommen nie eine sortOrder.
sortOrder Int?
// quick-260929-dzu: null = gemeinsamer Eintrag (vom Administrator, fuer alle
// sichtbar); gesetzt = persoenlicher Eintrag, nur fuer diesen Benutzer
// sichtbar. Faellt der Benutzer weg, fallen seine Eintraege mit.
@@ -906,3 +911,39 @@ model WelcomeMailTemplate {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// quick-261003-387: Modulkategorien je Organisation, durch Administratoren
// pflegbar. `key` ist unveraenderlich (URL-Segment /modules/<key>/<slug>),
// `name` null = Uebersetzung moduleCategories.<key>. isSystem nur fuer
// "custom-modules" (Eigene Module): umbenennbar und verschiebbar, nicht
// loeschbar.
model ModuleCategory {
id String @id @default(uuid())
tenantId String
key String
name String?
sortOrder Int @default(0)
isSystem Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([tenantId, key])
@@index([tenantId])
}
// quick-261003-387: Zuordnung eines Marktplatz-Moduls zu einer Kategorie der
// Organisation samt Reihenfolge. Wirksame Kategorie = Zuordnung, sonst
// Module.category (die Spalte selbst bleibt fuer alle gleich).
model ModuleCategoryPlacement {
id String @id @default(uuid())
tenantId String
moduleId String
module Module @relation(fields: [moduleId], references: [id], onDelete: Cascade)
categoryKey String
sortOrder Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([tenantId, moduleId])
@@index([tenantId])
}