Fundament: ISMS-Module entfernt; Craftvia-Rollen, Module, Navigation, i18n-Split
- ISMS-Routen, Actions, Server-/Lib-Code, Komponenten, Prisma-Modelle, Seeds, Importer, Skripte und ISMS-Tests entfernt (Fundament bleibt: Auth, Identity, MFA/WebAuthn, RBAC, Audit, Mail, Storage, Backup/DSGVO, Plattform-Admin) - Schema auf Fundament-Modelle reduziert; TenantSettings generisch (+phone/email) - TENANT_MODELS (db.ts, backup/topology.ts) und PII-Felder ausgedünnt - RBAC: Rollen tenant-admin/backoffice/team-lead/technician + Craftvia-Permissions - Modul-Katalog (customers, sites, teams, work_orders, imports, field, reports, emergency, documents, notifications, lotse) + Navigation aus src/lib/nav.ts - Modul-Routen mit requireModule-Layout und Platzhalterseite - Message-Katalog je Namespace (messages/<locale>/<namespace>.json), fs-Loader - check-module-guards: Modul-Key aus src/server/actions/<moduleKey>/ - Provisionierung, Admin-Konsole, Einstellungen, Files-Route, Mail entkoppelt - Seed minimal (demo/demo2, Nutzer je Rolle); Fundament-Tests auf Role/ NotificationPreference-Fixtures umgestellt Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
LayoutDashboard,
|
||||
ClipboardList,
|
||||
FileInput,
|
||||
Users,
|
||||
Building2,
|
||||
UsersRound,
|
||||
FileText,
|
||||
FolderOpen,
|
||||
Settings,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
import type { ModuleKey } from "@/lib/modules";
|
||||
import type { Permission } from "@/server/rbac";
|
||||
|
||||
/**
|
||||
* Sidebar-Navigation des Backoffice (src/app/(app)/layout.tsx).
|
||||
*
|
||||
* Ein Eintrag ist sichtbar, wenn
|
||||
* - sein Modul (falls gesetzt) für den Mandanten aktiv ist UND
|
||||
* - die Session mindestens EINE der `permissions` hat (leer = immer).
|
||||
* Das ist reiner Komfort — Seiten und Actions prüfen Modul + Rechte serverseitig selbst.
|
||||
*
|
||||
* Neue Backoffice-Seite ⇒ hier eintragen; `label` ist ein Schlüssel in messages nav.*.
|
||||
* Mobile-Einträge (/m, /m/emergency) gehören NICHT hierher (eigene Mobile-Navigation).
|
||||
*/
|
||||
export interface NavItem {
|
||||
href: string;
|
||||
label: string;
|
||||
icon: LucideIcon;
|
||||
module?: ModuleKey;
|
||||
permissions?: readonly Permission[];
|
||||
section: "main" | "admin";
|
||||
}
|
||||
|
||||
export const NAV_ITEMS: readonly NavItem[] = [
|
||||
{ href: "/dashboard", label: "dashboard", icon: LayoutDashboard, section: "main" },
|
||||
{
|
||||
href: "/work-orders",
|
||||
label: "workOrders",
|
||||
icon: ClipboardList,
|
||||
module: "work_orders",
|
||||
permissions: ["work_order:read_all", "work_order:read_team"],
|
||||
section: "main",
|
||||
},
|
||||
{ href: "/imports", label: "imports", icon: FileInput, module: "imports", permissions: ["import:write"], section: "main" },
|
||||
{ href: "/customers", label: "customers", icon: Users, module: "customers", permissions: ["customer:read"], section: "main" },
|
||||
{ href: "/sites", label: "sites", icon: Building2, module: "sites", permissions: ["site:read"], section: "main" },
|
||||
{ href: "/teams", label: "teams", icon: UsersRound, module: "teams", permissions: ["team:read"], section: "main" },
|
||||
{ href: "/reports", label: "reports", icon: FileText, module: "reports", permissions: ["report:read"], section: "main" },
|
||||
{ href: "/documents", label: "documents", icon: FolderOpen, module: "documents", permissions: ["document:read"], section: "main" },
|
||||
{ href: "/settings", label: "settings", icon: Settings, permissions: ["tenant:manage"], section: "admin" },
|
||||
];
|
||||
|
||||
/** Filtert die Navigation nach aktiven Modulen und Rechten der Session. */
|
||||
export function visibleNavItems(
|
||||
items: readonly NavItem[],
|
||||
opts: { disabledModules: ReadonlySet<string>; permissions: readonly string[] },
|
||||
): NavItem[] {
|
||||
return items.filter(
|
||||
(item) =>
|
||||
(!item.module || !opts.disabledModules.has(item.module)) &&
|
||||
(!item.permissions?.length || item.permissions.some((p) => opts.permissions.includes(p))),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user