„Was ist eigentlich mit meinem Notebook passiert?“ musste bisher ein Techniker nachsehen. Ein Mitarbeiter kann die Arbeiten an **seinen** Geraeten jetzt selbst ansehen — mit der fuenften Rolle MITARBEITER, zugeordnet beim Anmelden ueber den UPN. Was er sieht, sind Titel, Zeitraum und Status. Keine Schritte, keine Notizen, keine Kommentare, keine Anhaenge: in einem Lauf stehen Arbeitsnotizen ueber Menschen und Befehle mit Platzhaltern fuer Zugangsdaten. Eine Selbstauskunft ist keine Akteneinsicht, und das haelt nicht die Seite fest, sondern das Lesemodell — eine Seite, die filtert, ist eine Seite, die es vergessen kann. `selbstauskunft` ist ein **Ersatz** fuer `lesen` und kein Zusatz; auch ein ADMIN hat es nicht. Ein zweiter Weg zu denselben Daten waere eine zweite Stelle, an der jemand die Einschraenkung auf die eigene Person vergisst. Die Datenbank verlangt das sogar: ein CHECK haelt fest, dass Rolle und Zuordnung zusammengehoeren, in beide Richtungen. Ein mehrdeutiger UPN wird abgewiesen und protokolliert. Zwei Kunden koennen dieselbe Person fuehren; ein findFirst entschiede nach Sortierung darueber, wessen Geraete jemand sieht. **Verhaltensaenderung:** wer sich anmeldet und in keiner Rollengruppe steht, bekommt nicht mehr automatisch LESER — also nicht mehr Lesezugriff auf alle Laeufe des Hauses. Das greift nur mit konfigurierten OIDC_GROUP_*; ohne sie bleibt alles wie vorher, denn ohne abgebildete Gruppen laesst sich Techniker nicht von Mitarbeiter unterscheiden. Nebenbei behoben: `staerksteRolle` benutzte LESER als Startwert und damit als Untergrenze — mit einer Rolle darunter lieferte sie mehr Rechte als uebergeben. Gefunden von einem Test, der seit #007 unveraendert dasteht. Closes #55 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
99 lines
3.7 KiB
TypeScript
99 lines
3.7 KiB
TypeScript
/**
|
||
* Die Seitenleiste an einer Stelle beschrieben.
|
||
*
|
||
* `verfuegbar` wird umgestellt, sobald der Meilenstein die Seite liefert. So zeigt
|
||
* die Huelle von Anfang an die echte Struktur, ohne auf Seiten zu verlinken, die
|
||
* es noch nicht gibt. Die Beschriftungen haengen am Betriebsmodus (#008).
|
||
*/
|
||
import type { Recht } from "@/server/auth/rollen";
|
||
|
||
export type Betriebsmodus = "INTERN" | "DIENSTLEISTUNG";
|
||
|
||
export type NavEintrag = {
|
||
readonly pfad: string;
|
||
readonly beschriftung: string;
|
||
/**
|
||
* Abweichende Beschriftung im Modus DIENSTLEISTUNG.
|
||
*
|
||
* Dort heisst „Mitarbeiter“ „Personen“: es sind die Leute des Kunden, nicht
|
||
* die eigenen Angestellten. Derselbe Eintrag, dieselbe Seite — nur das Wort
|
||
* passt sich an (#008, ausgebaut in #011).
|
||
*/
|
||
readonly beschriftungDienstleistung?: string;
|
||
/** Nur in diesem Modus zeigen. Fehlt der Wert, gilt der Eintrag in beiden. */
|
||
readonly nurModus?: Betriebsmodus;
|
||
readonly symbol: string;
|
||
/** Wer dieses Recht nicht hat, sieht den Eintrag gar nicht erst. */
|
||
readonly recht?: Recht;
|
||
readonly verfuegbar: boolean;
|
||
/** Issue, das die Seite liefert – nur fuer den Hinweis, solange sie fehlt. */
|
||
readonly ausIssue?: number;
|
||
};
|
||
|
||
/**
|
||
* **Jeder Eintrag nennt sein Recht.**
|
||
*
|
||
* Bis #035 stand `recht` nur am Admin-Bereich, und das genuegte: jede Rolle
|
||
* durfte `lesen`, also war alles andere fuer jeden sichtbar. Mit `MITARBEITER`
|
||
* stimmt das nicht mehr — diese Rolle darf **nicht** `lesen`, und ohne das Recht
|
||
* an jedem Eintrag haette die Seitenleiste ihr sechs Links angeboten, die alle
|
||
* auf `/kein-zugriff` fuehren. Ein Eintrag ohne `recht` ist seitdem die Ausnahme
|
||
* und nicht die Regel.
|
||
*/
|
||
export const NAVIGATION: readonly NavEintrag[] = [
|
||
{ pfad: "/", beschriftung: "Übersicht", symbol: "LayoutDashboard", recht: "lesen", verfuegbar: true },
|
||
{ pfad: "/laeufe", beschriftung: "Läufe", symbol: "ListChecks", recht: "lesen", verfuegbar: true },
|
||
{ pfad: "/vorlagen", beschriftung: "Vorlagen", symbol: "FileText", recht: "lesen", verfuegbar: true },
|
||
{
|
||
pfad: "/mitarbeiter",
|
||
beschriftung: "Mitarbeiter & Geräte",
|
||
beschriftungDienstleistung: "Personen & Geräte",
|
||
symbol: "Users",
|
||
recht: "lesen",
|
||
verfuegbar: true,
|
||
},
|
||
{
|
||
pfad: "/kunden",
|
||
beschriftung: "Kunden",
|
||
nurModus: "DIENSTLEISTUNG",
|
||
symbol: "Building2",
|
||
recht: "lesen",
|
||
verfuegbar: true,
|
||
},
|
||
{ pfad: "/archiv", beschriftung: "Archiv", symbol: "Archive", recht: "lesen", verfuegbar: true },
|
||
{ pfad: "/admin", beschriftung: "Admin", symbol: "Settings", recht: "verwaltung", verfuegbar: true },
|
||
/*
|
||
* Die eine Seite der Selbstauskunft (#035). Sie steht am Ende, weil die
|
||
* Reihenfolge fuer alle anderen Rollen gilt — und fuer einen `MITARBEITER` ist
|
||
* sie der einzige Eintrag, da ist die Position gleichgueltig.
|
||
*/
|
||
{
|
||
pfad: "/meine-geraete",
|
||
beschriftung: "Meine Geräte",
|
||
symbol: "Laptop",
|
||
recht: "selbstauskunft",
|
||
verfuegbar: true,
|
||
},
|
||
];
|
||
|
||
/**
|
||
* Die sichtbaren Eintraege fuer diesen Modus und diese Rolle.
|
||
*
|
||
* Das Ausblenden ist Bequemlichkeit, keine Absicherung – die Rechtepruefung
|
||
* sitzt in der Service-Schicht. Aber ein Leser soll nicht auf Knoepfe klicken,
|
||
* die ihm hinterher eine Fehlermeldung zeigen.
|
||
*/
|
||
export function navigationFuer(
|
||
modus: Betriebsmodus,
|
||
darfEintrag: (recht: Recht) => boolean = () => true,
|
||
): readonly NavEintrag[] {
|
||
return NAVIGATION.filter(
|
||
(e) =>
|
||
(e.nurModus === undefined || e.nurModus === modus) && (e.recht === undefined || darfEintrag(e.recht)),
|
||
).map((eintrag) =>
|
||
modus === "DIENSTLEISTUNG" && eintrag.beschriftungDienstleistung
|
||
? { ...eintrag, beschriftung: eintrag.beschriftungDienstleistung }
|
||
: eintrag,
|
||
);
|
||
}
|