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:
@@ -0,0 +1,89 @@
|
||||
-- quick-261003-387 — Modulkategorien durch Administratoren bearbeitbar.
|
||||
--
|
||||
-- Zweck: zwei neue Tabellen und eine neue Spalte.
|
||||
-- * "ModuleCategory": die Kategorien einer Organisation (Kennung, optionaler
|
||||
-- eigener Name, Reihenfolge, Systemkennzeichen fuer "Eigene Module").
|
||||
-- Die Kennung ist unveraenderlich, sie steht als URL-Segment in
|
||||
-- /modules/<kennung>/<slug>.
|
||||
-- * "ModuleCategoryPlacement": Zuordnung eines Marktplatz-Moduls zu einer
|
||||
-- Kategorie der Organisation samt Reihenfolge. Die Spalte "Module"."category"
|
||||
-- (fuer alle Organisationen gleich) bleibt unveraendert; die wirksame
|
||||
-- Kategorie ist die Zuordnung, sonst diese Spalte.
|
||||
-- * "CustomModule"."sortOrder": Reihenfolge gemeinsamer eigener Module
|
||||
-- innerhalb ihrer Kategorie (NULL = noch nicht sortiert).
|
||||
-- Es gibt keine Rueckfuellung in SQL: der Dienst legt den Grundbestand je
|
||||
-- Organisation beim ersten Lesen an.
|
||||
--
|
||||
-- Von Hand geschrieben (Vorbild 20261002150000_nextcloud_status), von Hand
|
||||
-- gepflegter Kopfkommentar Pflicht bei jeder RLS-Migration in diesem Projekt.
|
||||
--
|
||||
-- Zeilenschutz (Pflicht — sonst schlaegt rls-coverage.spec.ts fehl): beide
|
||||
-- Tabellen tragen `tenantId` und `tenant_isolation_policy` OHNE
|
||||
-- Benutzerdimension (`USING ("tenantId" = current_tenant_id())`) — die
|
||||
-- Kategorien sind gemeinsame Einstellungen der Organisation, nicht
|
||||
-- persoenliche Daten eines Benutzers. Keine `system_read_policy`: es gibt
|
||||
-- keinen Hintergrunddienst, der darueber liest.
|
||||
--
|
||||
-- Rechte fuer die Anwendungsrolle tessera_app kommen automatisch ueber
|
||||
-- ALTER DEFAULT PRIVILEGES aus 20260909130000_rls_app_role — hier nichts zu
|
||||
-- tun.
|
||||
--
|
||||
-- WICHTIG: wie alle bisherigen RLS-Migrationen wirken diese Regeln erst,
|
||||
-- wenn die Anwendung als Rolle ohne Umgehungsrecht verbindet (Schalter
|
||||
-- heute AUS, siehe docs/mandantentrennung-datenbankrolle.md).
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "CustomModule" ADD COLUMN "sortOrder" INTEGER;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ModuleCategory" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenantId" TEXT NOT NULL,
|
||||
"key" TEXT NOT NULL,
|
||||
"name" TEXT,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"isSystem" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ModuleCategory_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ModuleCategoryPlacement" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenantId" TEXT NOT NULL,
|
||||
"moduleId" TEXT NOT NULL,
|
||||
"categoryKey" TEXT NOT NULL,
|
||||
"sortOrder" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "ModuleCategoryPlacement_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ModuleCategory_tenantId_idx" ON "ModuleCategory"("tenantId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ModuleCategory_tenantId_key_key" ON "ModuleCategory"("tenantId", "key");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ModuleCategoryPlacement_tenantId_idx" ON "ModuleCategoryPlacement"("tenantId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ModuleCategoryPlacement_tenantId_moduleId_key" ON "ModuleCategoryPlacement"("tenantId", "moduleId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ModuleCategoryPlacement" ADD CONSTRAINT "ModuleCategoryPlacement_moduleId_fkey" FOREIGN KEY ("moduleId") REFERENCES "Module"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- Zeilenschutz
|
||||
ALTER TABLE "ModuleCategory" ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "ModuleCategory" FORCE ROW LEVEL SECURITY;
|
||||
CREATE POLICY tenant_isolation_policy ON "ModuleCategory"
|
||||
USING ("tenantId" = current_tenant_id());
|
||||
|
||||
ALTER TABLE "ModuleCategoryPlacement" ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE "ModuleCategoryPlacement" FORCE ROW LEVEL SECURITY;
|
||||
CREATE POLICY tenant_isolation_policy ON "ModuleCategoryPlacement"
|
||||
USING ("tenantId" = current_tenant_id());
|
||||
Reference in New Issue
Block a user