feat: konfigurierbaren Freigabe-Workflow mit Genehmiger-Rollen einführen
Mandanten können jetzt selbst festlegen, wer bei welcher abgeleiteten Bedingung (Anforderung/Einstufung/Datenklasse) zusätzlich zur Fachebene-Entscheidung zustimmen muss (z. B. Datenschutzbeauftragter, Geschäftsführung) - Genehmiger-Rollen sind orthogonal zu den fünf bestehenden Zugriffsrollen. Alle ausgelösten Rollen müssen zustimmen, eine Ablehnung kippt kaskadierend den gesamten Antrag. Mandanten ohne Freigabe-Regeln (aktuell alle) sind unverändert vom alten Direktpfad betroffen, siehe TestOhneFreigabeRegelnVerhaeltSichWieVorher. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,23 @@
|
||||
<p><strong>{{.Entscheidung.Entscheidung}}</strong>{{if .Entscheidung.WerkzeugName}} — {{.Entscheidung.WerkzeugName}}{{end}}<br>
|
||||
<span class="hinweis">am {{.Entscheidung.CreatedAt}}{{if .Entscheidung.GueltigBis}}, gültig bis {{.Entscheidung.GueltigBis}}{{end}}</span></p>
|
||||
{{if .Entscheidung.Begruendung}}<p>{{.Entscheidung.Begruendung}}</p>{{end}}
|
||||
|
||||
{{if .Freigabeschritte}}
|
||||
<h2>Zusätzliche Freigaben</h2>
|
||||
{{if eq .Status "wartet_auf_freigabe"}}
|
||||
<p class="hinweis">Die Genehmigung ist erst endgültig, wenn alle unten stehenden Freigaben erteilt sind.</p>
|
||||
{{end}}
|
||||
<ul class="beitraege-liste">
|
||||
{{range .Freigabeschritte}}
|
||||
<li>
|
||||
{{.RolleName}}
|
||||
<span class="status {{if eq .Status "genehmigt"}}status-published{{else if eq .Status "abgelehnt"}}status-hoch{{else}}status-mittel{{end}}">{{.Status}}</span>
|
||||
{{if .Kommentar}}<p>{{.Kommentar}}</p>{{end}}
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
|
||||
{{else if .CanEntscheiden}}
|
||||
<h2>Entscheiden</h2>
|
||||
{{if .Error}}<p class="fehler">{{.Error}}</p>{{end}}
|
||||
|
||||
93
internal/web/templates/freigabe_regeln_liste.html
Normal file
93
internal/web/templates/freigabe_regeln_liste.html
Normal file
@@ -0,0 +1,93 @@
|
||||
{{define "freigabe-regeln-liste"}}<!doctype html>
|
||||
<html lang="de">
|
||||
<head>{{template "head" .}}</head>
|
||||
<body>
|
||||
{{template "nav" .Nav}}
|
||||
<div class="page">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1>Freigabe-Regeln</h1>
|
||||
<p class="hinweis">
|
||||
"Wenn Bedingung X zutrifft, ist zusätzlich eine Freigabe durch
|
||||
Genehmiger-Rolle Y nötig." Bedingungen sind die vom Regelwerk
|
||||
abgeleiteten Anforderungen/Einstufungen/Datenklassen — keine
|
||||
freie Regel, sondern eine Auswahl aus dem, was das System ohnehin
|
||||
schon berechnet. Eine Genehmigung durch die Fachebene wartet dann
|
||||
erst auf diese zusätzlichen Freigaben, bevor sie endgültig ist;
|
||||
lehnt eine davon ab, gilt der gesamte Antrag als abgelehnt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{if .Error}}<p class="fehler">{{.Error}}</p>{{end}}
|
||||
|
||||
{{if not .RollenOptionen}}
|
||||
<p class="hinweis">
|
||||
Zuerst mindestens eine <a href="/verwaltung/genehmiger-rollen">Genehmiger-Rolle</a>
|
||||
anlegen, bevor eine Freigabe-Regel definiert werden kann.
|
||||
</p>
|
||||
{{else}}
|
||||
<div class="form-card">
|
||||
<form method="post" action="/verwaltung/freigabe-regeln">
|
||||
<fieldset class="form-section">
|
||||
<legend>Neue Freigabe-Regel</legend>
|
||||
<div class="form-grid">
|
||||
<div>
|
||||
<label for="bedingung">Bedingung</label>
|
||||
<select id="bedingung" name="bedingung" required>
|
||||
<option value="">Bitte wählen…</option>
|
||||
{{range .BedingungGruppen}}
|
||||
{{$gruppe := .Label}}
|
||||
<optgroup label="{{$gruppe}}">
|
||||
{{range .Optionen}}
|
||||
<option value="{{.Value}}">{{.Label}}</option>
|
||||
{{end}}
|
||||
</optgroup>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="genehmiger_rolle_id">Genehmiger-Rolle</label>
|
||||
<select id="genehmiger_rolle_id" name="genehmiger_rolle_id" required>
|
||||
<option value="">Bitte wählen…</option>
|
||||
{{range .RollenOptionen}}
|
||||
<option value="{{.ID}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-actions">
|
||||
<button type="submit">Anlegen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if not .Regeln}}
|
||||
<p class="hinweis">Noch keine Freigabe-Regeln.</p>
|
||||
{{else}}
|
||||
<div class="table-responsive">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Bedingung</th><th>Erforderliche Freigabe</th><th></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Regeln}}
|
||||
<tr>
|
||||
<td data-label="Bedingung">{{.BedingungLabel}}</td>
|
||||
<td data-label="Erforderliche Freigabe">{{.GenehmigerRolle}}</td>
|
||||
<td data-label="">
|
||||
<form method="post" action="/verwaltung/freigabe-regeln/{{.ID}}/loeschen" style="display:inline" onsubmit="return confirm('Freigabe-Regel wirklich löschen?')">
|
||||
<button type="submit" class="entfernen">Löschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
38
internal/web/templates/freigaben_liste.html
Normal file
38
internal/web/templates/freigaben_liste.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{{define "freigaben-liste"}}<!doctype html>
|
||||
<html lang="de">
|
||||
<head>{{template "head" .}}</head>
|
||||
<body>
|
||||
{{template "nav" .Nav}}
|
||||
<div class="page">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1>Meine Freigaben</h1>
|
||||
<p class="hinweis">Anträge, die zusätzlich zur Fachebene-Entscheidung deine Freigabe brauchen.</p>
|
||||
</div>
|
||||
</div>
|
||||
{{if not .Freigaben}}
|
||||
<p class="keine-findings">Keine ausstehenden Freigaben.</p>
|
||||
{{else}}
|
||||
<ul class="beitraege-liste">
|
||||
{{range .Freigaben}}
|
||||
<li>
|
||||
<div class="beteiligter-kopf">
|
||||
<strong>{{.AntragTitel}}</strong> · Freigabe als {{.RolleName}} · seit {{.CreatedAt}}
|
||||
</div>
|
||||
<form method="post" action="/freigaben/{{.ID}}/entscheiden">
|
||||
<label for="kommentar-{{.ID}}">Kommentar (optional, Pflicht bei Ablehnung empfohlen)</label>
|
||||
<input type="text" id="kommentar-{{.ID}}" name="kommentar">
|
||||
<div class="form-actions">
|
||||
<button type="submit" name="entscheidung" value="genehmigt">Freigeben</button>
|
||||
<button type="submit" name="entscheidung" value="abgelehnt" class="entfernen" onclick="return confirm('Wirklich ablehnen? Das lehnt den gesamten Antrag ab.')">Ablehnen</button>
|
||||
</div>
|
||||
</form>
|
||||
<p><a href="/faelle/{{.AntragID}}">Antrag ansehen →</a></p>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
79
internal/web/templates/genehmiger_rollen_liste.html
Normal file
79
internal/web/templates/genehmiger_rollen_liste.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{{define "genehmiger-rollen-liste"}}<!doctype html>
|
||||
<html lang="de">
|
||||
<head>{{template "head" .}}</head>
|
||||
<body>
|
||||
{{template "nav" .Nav}}
|
||||
<div class="page">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1>Genehmiger-Rollen</h1>
|
||||
<p class="hinweis">
|
||||
Freigabe-Funktionen wie "Datenschutzbeauftragter" oder
|
||||
"Geschäftsführung" — unabhängig von den normalen Zugriffsrollen,
|
||||
eine Person kann beides zugleich sein. Wer wann zusätzlich
|
||||
freigeben muss, legst du unter
|
||||
<a href="/verwaltung/freigabe-regeln">Freigabe-Regeln</a> fest.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{if .Error}}<p class="fehler">{{.Error}}</p>{{end}}
|
||||
|
||||
<div class="form-card">
|
||||
<form method="post" action="/verwaltung/genehmiger-rollen">
|
||||
<fieldset class="form-section">
|
||||
<legend>Neue Genehmiger-Rolle</legend>
|
||||
<div class="form-grid">
|
||||
<div>
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" name="name" placeholder="z. B. Datenschutzbeauftragter" required>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-actions">
|
||||
<button type="submit">Anlegen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{if not .Rollen}}
|
||||
<p class="hinweis">Noch keine Genehmiger-Rollen.</p>
|
||||
{{else}}
|
||||
<ul class="beitraege-liste">
|
||||
{{range .Rollen}}
|
||||
{{$rolleID := .ID}}
|
||||
<li>
|
||||
<div class="beteiligter-kopf"><strong>{{.Name}}</strong></div>
|
||||
{{if .Mitglieder}}
|
||||
<ul class="beitraege-liste">
|
||||
{{range .Mitglieder}}
|
||||
<li>
|
||||
{{.Email}}
|
||||
<form method="post" action="/verwaltung/genehmiger-rollen/{{$rolleID}}/mitglieder/{{.ID}}/entfernen" style="display:inline">
|
||||
<button type="submit" class="entfernen">Entfernen</button>
|
||||
</form>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p class="hinweis">Noch keine Mitglieder.</p>
|
||||
{{end}}
|
||||
<form method="post" action="/verwaltung/genehmiger-rollen/{{$rolleID}}/mitglieder" style="display:inline">
|
||||
<select name="user_id" required>
|
||||
<option value="">Person hinzufügen…</option>
|
||||
{{range $.Nutzer}}
|
||||
<option value="{{.ID}}">{{.Email}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<button type="submit">Hinzufügen</button>
|
||||
</form>
|
||||
<form method="post" action="/verwaltung/genehmiger-rollen/{{$rolleID}}/loeschen" style="display:inline" onsubmit="return confirm('Genehmiger-Rolle wirklich löschen?')">
|
||||
<button type="submit" class="entfernen">Rolle löschen</button>
|
||||
</form>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{end}}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -24,6 +24,7 @@
|
||||
<nav class="app-nav">
|
||||
<a href="/">Start</a>
|
||||
{{if not .IsBetreiber}}<a href="/antraege">Meine Anträge</a>{{end}}
|
||||
{{if not .IsBetreiber}}<a href="/freigaben">Meine Freigaben</a>{{end}}
|
||||
{{if .IsFachebene}}<a href="/faelle">Posteingang</a>{{end}}
|
||||
{{if .IsFachebene}}<a href="/registereintraege">Register</a>{{end}}
|
||||
{{if .IsFachebene}}<a href="/wiedervorlage">Wiedervorlage</a>{{end}}
|
||||
@@ -31,6 +32,8 @@
|
||||
{{if .IsAdmin}}<a href="/verwaltung/einladung">Einladungslink</a>{{end}}
|
||||
{{if .IsAdmin}}<a href="/verwaltung/abteilungen">Abteilungen</a>{{end}}
|
||||
{{if .IsAdmin}}<a href="/verwaltung/werkzeuge">Werkzeugkatalog</a>{{end}}
|
||||
{{if .IsAdmin}}<a href="/verwaltung/genehmiger-rollen">Genehmiger-Rollen</a>{{end}}
|
||||
{{if .IsAdmin}}<a href="/verwaltung/freigabe-regeln">Freigabe-Regeln</a>{{end}}
|
||||
{{if .IsBetreiber}}<a href="/betreiber">Plattform</a>{{end}}
|
||||
<form method="post" action="/logout">
|
||||
<button type="submit">Abmelden</button>
|
||||
|
||||
Reference in New Issue
Block a user