Web Application2025Lead Developer

DigiDekan

Hochschul-Dekanats-Plattform — Java/Spring Boot, modernes JS-Frontend, CI/CD-Pipelines (GitHub Actions, automatisierte Tests).

DigiDekan

Eckdaten

Umfang

200

Dateien

21

Modelle

16

API-Routes

~83k

Lines of Code

2

Apps

31

Seiten

13

Services

Herausforderung

Manuelle Semesterplanung per Tabelle, papierbasierte Formulare, keine zentrale Übersicht für den Dekan, fehleranfällige SWS-Berechnung und wochenlange Anerkennungs-Prozesse auf Papier — alles administrative Engpässe an einer deutschen Hochschule.

Lösung

Duale Plattform mit 7-Schritte-SemesterplanungWizard, SWS/Deputat-Berechnungs-Engine mit Kategorien-Obergrenzen und Warnungen, rollenbasierten Dashboards (Dekan, Professor, Lehrbeauftragte) und einem 5-Schritte-AnerkennungWizard mit 6-Stufen-Status-Timeline. Java/Spring-Boot-Backend mit REST-APIs, JWT-Auth via Spring Security, PDF-Export für Deputatsabrechnungen und @Scheduled-Jobs für E-Mail-Erinnerungen. Modernes TypeScript/React-Frontend mit React Hook Form-Validierung.

Ergebnis

Produktiv im Einsatz an einer deutschen Hochschule. Automatisierte SWS/Deputat-Berechnung ersetzt manuelle Tabellen, Anerkennungs-Prozesse von Wochen auf Tage verkürzt, zentrale Dekan-Übersicht über alle Professoren und Semester.

Über das Projekt

Hintergrund

Duale Plattform für Hochschul-Dekanate. „Digitales Dekanat" bietet Semesterplanung mit 7-Schritte-Wizard, SWS/Deputat-Berechnungs-Engine, Modulverwaltung und rollenbasierte Dashboards für Dekan, Professor und Lehrbeauftragte. „Anerkennung Standalone" liefert einen 5-Schritte-Wizard für Studierende mit 6-Stufen-Status-Timeline, Dokumenten-Upload, Dozent-Review-Workflow und automatischen E-Mail-Benachrichtigungen. Weiterentwicklung mit Java/Spring Boot, modernem JS-Frontend und automatisierten CI/CD-Pipelines (GitHub Actions, automatisierte Tests).

Stack

Technologien

Java 17Spring BootREST APIsTypeScriptReactPostgreSQLJUnitGitHub ActionsDockerClean Code

Highlights

Kernfunktionen

    Java/Spring Boot Backend mit REST-APIs, JPA und Spring Security
    Modernes TypeScript/React-Frontend mit React Hook Form
    Automatisierte CI/CD-Pipelines (GitHub Actions, JUnit-Tests)
    7-Schritte-SemesterplanungWizard, SWS/Deputat-Engine, PDF-Export
    Dual-System: Dekanats-Plattform + Studierenden-Anerkennungs-Workflow

Architektur

System auf einen Blick

React-Frontends sprechen über Spring Security mit JWT gegen vier Domain-Services. Geschäftslogik (SWS, Workflows, Planung) bleibt im Backend, PostgreSQL hält den Zustand mit Audit-Trail.

UI-Tour

Im Detail — 7 Kapitel · 22 Screens

Jeder Screenshot mit fachlichem Kontext. Springe direkt in ein Kapitel oder scrolle die komplette Tour.

01 / Dekanat

Zugang & Dashboards

Einstiegspunkt der Plattform für drei unterschiedliche Rollen — Dekan, Professor und Lehrbeauftragte. Jede Rolle bekommt nach JWT-Login eine eigene, rollen­spezifisch zugeschnittene Übersicht.

DigiDekan Login

01.01 · Auth · JWT · RBAC

Einheitlicher Login

Eine gemeinsame Login-Seite für alle drei internen Rollen. Im Hintergrund läuft Spring Security mit JWT (Access- und Refresh-Token); methoden-basierte Annotationen (@PreAuthorize) regeln den Zugriff pro Endpoint, der globale ExceptionHandler liefert konsistente API-Fehlerformate.

  • Token-basierte Authentifizierung mit Rollen-Claim
  • Rate-Limit auf fehlgeschlagene Logins
  • Audit-Log jedes Anmeldeversuchs

01.02 · KPI · Semester-Übersicht

Dekan-Dashboard

Zentrale Übersicht für den Dekan: Status der aktiven Semesterplanung, Anzahl offener Aufträge, Deputat-Auslastung des Fachbereichs und Quick-Links in die wichtigsten Verwaltungs­bereiche. Die KPIs werden serverseitig über JPA-Aggregations-Queries auf den Domain-Entitäten berechnet.

  • Drilldown von jeder Kennzahl in die zugrundeliegende Liste
  • Visualisierung des aktuellen Planungsphasen-Status
  • Direkte Sprünge in Modul- und Dozentenverwaltung
Dekan-Dashboard
Professor-Dashboard

01.03 · Persönliche Deputatsübersicht

Professor-Dashboard

Professor-spezifische Ansicht: eigene SWS-Auslastung, Liste zugewiesener Module und Semesteraufträge, To-dos für die aktuelle Planungsphase. RBAC sorgt dafür, dass jeder Professor nur seine eigenen Daten sieht.

  • Eigenes Deputat mit Ampel-Bewertung (erfüllt / Abweichung / starke Abweichung)
  • Persönliche Aufgaben pro Planungsphase
  • Direkter Zugriff auf die eigene SWS-Abrechnung

02 / Dekanat

Semesterplanung — 7-Schritte-Wizard

Das Herzstück des Digitalen Dekanats: Ein geführter 7-Schritte-Wizard von Semester-Auswahl bis Freigabe. Jeder Schritt validiert serverseitig, lässt sich zwischenspeichern und ist resumable.

Wizard-Einstieg

02.01 · Stepper · React Hook Form · State Management

Wizard-Einstieg & Schritt-Navigation

Wizard-Startseite mit visuellem Stepper. Der Zustand jedes Schritts wird im Frontend gehalten und bei jeder Aktion gegen den Spring-REST-Endpoint validiert; der Stepper visualisiert offene und abgeschlossene Schritte.

  • 7 Schritte: Semester · Module · Multiplikatoren · Zusatzinfos · Mitarbeiter · Aufträge · Freie Tage · Freigabe
  • Zwischenspeichern jederzeit möglich — Resume beim nächsten Login
  • Schritt-Validierung sowohl client- als auch serverseitig

02.02 · Geplante Module · Lehrform-Multiplikatoren

Modulzuordnung per Drag & Drop

Aus dem Modulkatalog werden Module per Drag & Drop in die laufende Semesterplanung gezogen. Pro Modul wird die Lehrform (Vorlesung / Seminar / Praktikum) erkannt und der zugehörige SWS-Multiplikator angewendet.

  • Suche & Filter auf 100+ Modulen des Katalogs
  • Live-Validierung gegen Doppelvergaben
  • Multiplikator-Override mit Begründungsfeld
Modulzuordnung
Wizard Zusammenfassung

02.03 · Pre-Submit-Check · Audit-Trail

Validierung & Freigabe

Letzter Schritt: Komplette Zusammenfassung der Planung mit allen Validierungs-Warnungen (überschrittene SWS-Obergrenzen, fehlende Zuordnungen). Erst nach explizitem „Freigeben" wird die Planung versioniert in die DB übernommen.

  • Versionierte Snapshots — frühere Stände bleiben einsehbar
  • Warn-Hierarchie: Fehler blockieren, Warnungen lassen sich quittieren
  • Audit-Log mit Benutzer-ID und Zeitstempel

03 / Dekanat

Deputat & Planungssteuerung

Das fachliche Schwergewicht: Die SWS/Deputat-Engine berechnet pro Professor die Lehrverpflichtung nach Hochschulgesetz. Praxisseminare, Master-Seminare und Betreuungen unterliegen Obergrenzen — wird überschritten, gibt es Warnungen.

Live-Demo · Domain-Logik

SWS-Berechnung selbst ausprobieren

Bewege die Regler — die Engine wendet Kategorien-Obergrenzen an, bilanziert das Gesamtdeputat gegen die Netto-Lehrverpflichtung und kennzeichnet jeden Cap, der überschritten wird, mit einer Warnung.

4 SWS
6 SWS
2 SWS
8 SWS
2 SWS
0 SWS
5 SWS
1 SWS
18 SWS

Lehre angerechnet

20.0SWS

Gesamtdeputat

27.0SWS

Differenz zum Soll

+9.0SWS

Starke Abweichung

Cap-Warnungen aus der Engine

  • Betreuungen: 5 SWS, max. 4 angerechnet

Die Logik entspricht 1:1 dem produktiven DeputatService in DigiDekan: Kategorien-Caps, Status-Bewertung bei |Δ| ≤ 1 (erfüllt), ≤ 3 (Abweichung), sonst „starke Abweichung“.

Deputatsabrechnung

03.01 · Berechnungs-Engine · DeputatService.java

SWS/Deputat-Abrechnung

Pro Professor wird das Gesamtdeputat aus Lehrtätigkeiten, Lehrexport, Vertretungen, Betreuungen und Ermäßigungen berechnet. Praxisseminar (max. 6 SWS), Seminar Master (max. 4 SWS) und Betreuungen (max. 4 SWS) unterliegen Obergrenzen, die in der Engine automatisch angewendet und als Warnung dokumentiert werden.

  • Status-Bewertung: erfüllt (|Δ| ≤ 1) · Abweichung (|Δ| ≤ 3) · starke Abweichung (>3)
  • Multiplikatoren pro Lehrform mit Override
  • PDF-Export via OpenPDF für offizielle Abrechnung

03.02 · Dekan-Cockpit · Aggregation

Deputat-Gesamtsicht

Tabellarische Übersicht aller Professor-Deputate des Fachbereichs — IST, SOLL, Δ und Status pro Person nebeneinander. Sortier-, Filter- und Suchfunktionen erlauben dem Dekan, schnell Schieflagen zu erkennen.

  • Bulk-Sortierung nach Abweichung, Name, Status
  • CSV-Export für Verwaltungsberichte
  • Direktsprung in die einzelne Abrechnung
Deputat-Verwaltung
Planungsphasen-Manager

03.03 · Workflow-Steuerung · Deadlines

Planungsphasen-Manager

Steuerung der semesterweiten Planungsphasen — von „Vorbereitung" über „Modul-Pflege" und „Dozentenzuweisung" bis „Freigabe". Jede Phase hat Start- und End-Datum, Verantwortliche und Status; Spring @Scheduled-Jobs verschicken Erinnerungs-E-Mails an Säumige.

  • Phasen lassen sich aktivieren, sperren und versioniert kopieren
  • Automatische Reminder bei nahenden Deadlines
  • Phase-spezifische Sichtbarkeitsregeln für UI-Bereiche

04 / Dekanat

Stammdaten & Module

Saubere Stammdaten sind Voraussetzung für eine korrekte Planung. Vier eigenständige Verwaltungs­bereiche kümmern sich um Module, Modulkatalog, Dozenten und Semester.

Modul-Verwaltung

04.01 · Stammdaten · Data-Tables

Modul-Verwaltung (CRUD)

Vollständige CRUD-Operationen auf den Modul-Stammdaten: Modulnummer, Titel, ECTS, SWS, Lehrform, zugeordneter Studiengang. Validierung verhindert inkonsistente Datensätze (z. B. SWS ohne Lehrform).

  • Inline-Editing mit Optimistic Updates
  • Versionsführung pro Modul für Curriculum-Änderungen
  • Pflichtfeld-Validierung clientseitig & serverseitig

04.02 · Suchbarer Read-Only-Katalog

Modulkatalog

Lesefreundliche Sicht auf den gesamten Modulkatalog mit Volltextsuche und Filter nach Studiengang, ECTS, Pflicht/Wahl. Wird vom Wizard als Quelle für Modulauswahl genutzt und ist für alle Rollen einsehbar.

  • Fuzzy-Suche über Modulnummer und Titel
  • Filter nach Studiengang, Semester, Modultyp
  • Detail-Drawer mit Modulbeschreibung und Curriculum-Verortung
Modulkatalog
Dozenten-Verwaltung

04.03 · Personalstammdaten · Rollen

Dozenten-Verwaltung

Verwaltung aller Lehrenden — Professoren, Lehrbeauftragte und Vertretungen. Pro Person werden Rolle, Vertragsumfang (volle/halbe Stelle), Netto-Lehrverpflichtung in SWS und Sonderaufgaben gepflegt. Bildet die Datenbasis für die Deputatsberechnung.

  • Rollen-zentrierte RBAC-Zuweisung pro Person
  • Verlauf von Stellenanteil und Ermäßigungen
  • Verknüpfung zum Login-Konto (1:1)

04.04 · Zeitliche Strukturen · Wiederverwendbar

Semester-Verwaltung

Anlage und Konfiguration von Sommer- und Wintersemestern. Jedes Semester hat eigene Phasen, Stichtage, eine Liste angebotener Module und Statistiken. Semester können geklont werden, um neue Planungszyklen schnell aufzusetzen.

  • Semester-Klonen mit allen Modul-Zuordnungen
  • Semesterspezifische Stichtage und Phasen
  • Read-Only-Modus für abgeschlossene Semester
Semester-Verwaltung

05 / Dekanat

Aufträge & Konfiguration

Über das reine Modul-Lehren hinaus haben Lehrende viele weitere Aufgaben — Prüfungsausschuss, Studiengangsleitung, Mentoring. Diese werden über Semesteraufträge erfasst und können wiederverwendbar als Vorlage abgelegt werden.

Semesteraufträge

05.01 · Funktionszuweisung · SWS-Ermäßigungen

Semesteraufträge & Funktionen

Erfassung aller nicht-modulbezogenen Aufgaben pro Semester: Studiengangsleitung, Akkreditierung, Prüfungsausschuss usw. Jede Funktion ist mit einer SWS-Ermäßigung verknüpft, die in die Deputatsberechnung einfließt.

  • Funktions-Katalog mit Standard-Ermäßigungen
  • Mehrere Funktionen pro Person und Semester
  • Begründungsfelder für Abweichungen vom Standard

05.02 · Wiederverwendung · Best Practices

Planungsvorlagen

Wiederverwendbare Templates für typische Semester-Konfigurationen. Vor allem hilfreich, wenn sich Pflichtprogramm und Funktionen über Jahre wenig ändern — eine Vorlage spart das manuelle Anlegen.

  • Templates lassen sich freigeben für andere Studiengänge
  • Versionsführung pro Template
  • Materialisierung mit einem Klick in neue Planungen
Planungsvorlagen
Systemeinstellungen

05.03 · Konfiguration · Defaults

System- & Benutzereinstellungen

Konfigurationszentrale für system- und benutzerbezogene Defaults — SWS-Obergrenzen, Standard-Multiplikatoren, E-Mail-Templates, Benachrichtigungsregeln. Änderungen werden versioniert protokolliert.

  • SWS-Obergrenzen zentral pflegbar (Praxisseminar, Master, Betreuung)
  • E-Mail-Templates mit Platzhalter-Vorschau
  • Audit-Log jeder Konfigurationsänderung

06 / Anerkennung

Anerkennung — Studierenden-Portal

Zweite App im DigiDekan-Ökosystem: ein eigenständiges Portal, über das Studierende Anerkennungsanträge für extern erbrachte Leistungen stellen — komplett asynchron, mit eigenen Routen und eigenem Auth-Setup.

Anerkennung Login

06.01 · Eigene Auth-Domäne

Studierenden-Login

Separater Login für Studierende — eigenes Auth-Schema, eigene Session-Lebensdauer, eigener Token-Issuer. Strikte Trennung von der Mitarbeiter-Authentifizierung verhindert Rollenvermischung.

  • E-Mail-Verifikation bei Erstanmeldung
  • Passwort-Reset mit Time-Boxed-Tokens
  • Geräte-spezifische Refresh-Tokens

06.02 · Antragserstellung · Upload

5-Schritte-Anerkennungs-Wizard

Geführter Antrags-Wizard in 5 Schritten: Persönliche Angaben → Herkunfts-Hochschule → zu anerkennende Module → Dokument-Upload (Leistungsnachweis, Modulbeschreibung) → Zusammenfassung & Einreichen. Jeder Schritt ist auch als Entwurf speicherbar.

  • Drag & Drop-Upload mit Virus-Scan und Größen-Validierung
  • PDF-Vorschau direkt im Browser
  • Resume-fähig — Studierende können Antrag pausieren
Anerkennung Wizard

07 / Anerkennung

Anerkennung — Workflow & Verwaltung

Sobald ein Antrag eingereicht ist, durchläuft er einen 6-stufigen Workflow mit klaren Verantwortlichkeiten — Studierende, Verwaltung, fachprüfende Dozenten. Jeder Statuswechsel löst automatische E-Mail-Benachrichtigungen aus.

Anerkennung Verwaltung

07.01 · Workflow-Steuerung · Bulk-Aktionen

Admin-Dashboard für Anträge

Verwaltungs-Cockpit: alle eingehenden Anträge mit Status, Antragsteller, Modul-Anzahl und Tagen seit Einreichung. Filter, Sortierung und Bulk-Operationen (z. B. mehrere Anträge gleichzeitig an Dozenten zuweisen).

  • Filter nach Status, Studiengang, Dozent
  • Bulk-Zuweisung an Fachprüfer
  • SLA-Indikator: Tage seit letzter Aktion

07.02 · 6-Stufen-Workflow · State-Machine

Antragsdetail mit Status-Timeline

Vollständige Antragsansicht mit 6-stufiger Status-Timeline: Entwurf → Eingereicht → In Prüfung → Geprüft → Ergebnis mitgeteilt → Abgeschlossen. Eine Nachforderung kann den Status von „In Prüfung" zurück auf „Eingereicht" setzen — die State-Machine im Backend stellt sicher, dass nur erlaubte Übergänge passieren.

  • Zeitstempel und verantwortliche Person pro Statuswechsel
  • Nachforderungs-Schleife mit Frist-Tracking
  • Dokumenten-Anhänge pro Status sichtbar
Anerkennung Detail
Dozent-Prüfung

07.03 · Begutachtung · Notenmapping

Fachliche Prüfung durch Dozent

Der zuständige Dozent prüft fachlich, ob die extern erbrachte Leistung dem Hochschul-Modul entspricht. Eingabefelder für Note (mit automatischem Notenmapping zwischen Skalen), Begründung und Empfehlung (anerkannt / nicht anerkannt / Auflage).

  • Notenmapping mit Default-Tabelle (z. B. ECTS → deutsches System)
  • Kommentar-Pflichtfeld bei Ablehnung
  • Direktes Speichern eines Gutachtens als PDF

07.04 · Spring Scheduling · SMTP · Templates

Auto-Benachrichtigungen

Alle Statuswechsel lösen automatische E-Mails mit Template-Rendering aus — Studierende werden über Einreichungs-Bestätigung, Nachforderungen und Ergebnis informiert, Dozenten über neue Prüfungen. Spring @Scheduled-Jobs verschicken zusätzlich Erinnerungen bei Inaktivität nach 7 und 14 Tagen.

  • Templates pro Statuswechsel mit Platzhalter-Engine
  • Versand-Log mit Retry-Mechanik bei SMTP-Fehlern
  • Erinnerungs-Logik via Scheduler bei Säumigkeit
E-Mail-System

Code

Auszüge

SWS/Deputat-Berechnungs-Engine

java

Domain-Service in Spring Boot — berechnet alle SWS-Summen pro Professor mit Obergrenzen (Praxisseminar, Projektveranstaltung, Seminar Master, Betreuung), bestimmt Differenz zur Netto-Lehrverpflichtung und Status-Bewertung (erfüllt / Abweichung / starke Abweichung) und sammelt Warnungen bei überschrittenen Caps.

@Service
@RequiredArgsConstructor
public class DeputatService {

    private final DeputatsEinstellungenRepository einstellungenRepo;

    public DeputatsErgebnis berechneSummen(Professor prof) {
        DeputatsEinstellungen e = einstellungenRepo.getCurrent();

        // Lehrtätigkeiten nach Kategorie mit Obergrenzen
        Map<Kategorie, Double> nachKategorie = prof.getLehrtaetigkeiten().stream()
            .collect(Collectors.groupingBy(
                Lehrtaetigkeit::getKategorie,
                Collectors.summingDouble(Lehrtaetigkeit::getSws)));

        double praxisseminarRoh   = nachKategorie.getOrDefault(Kategorie.PRAXISSEMINAR, 0.0);
        double projektRoh         = nachKategorie.getOrDefault(Kategorie.PROJEKTVERANSTALTUNG, 0.0);
        double seminarMasterRoh   = nachKategorie.getOrDefault(Kategorie.SEMINAR_MASTER, 0.0);
        double sonstige           = nachKategorie.getOrDefault(Kategorie.SONSTIGE, 0.0);

        double praxisseminar = Math.min(praxisseminarRoh, e.getMaxSwsPraxisseminar());
        double projekt       = Math.min(projektRoh,       e.getMaxSwsProjekt());
        double seminarMaster = Math.min(seminarMasterRoh, e.getMaxSwsSeminarMaster());

        double swsLehre = sonstige + praxisseminar + projekt + seminarMaster;

        double lehrexport     = sumSws(prof.getLehrexporte());
        double vertretungen   = sumSws(prof.getVertretungen());
        double ermaessigungen = sumSws(prof.getErmaessigungen());

        double betreuungenRoh = sumSws(prof.getBetreuungen());
        double betreuungen    = Math.min(betreuungenRoh, e.getMaxSwsBetreuung());

        double gesamt   = swsLehre + lehrexport + vertretungen + betreuungen + ermaessigungen;
        double diff     = gesamt - prof.getNettoLehrverpflichtung();

        Bewertung bewertung = Math.abs(diff) <= 1.0 ? Bewertung.ERFUELLT
                            : Math.abs(diff) <= 3.0 ? Bewertung.ABWEICHUNG
                            : Bewertung.STARKE_ABWEICHUNG;

        List<String> warnungen = new ArrayList<>();
        if (praxisseminarRoh > e.getMaxSwsPraxisseminar()) {
            warnungen.add("Praxisseminar: %.1f SWS, max. %.1f angerechnet"
                .formatted(praxisseminarRoh, e.getMaxSwsPraxisseminar()));
        }
        if (betreuungenRoh > e.getMaxSwsBetreuung()) {
            warnungen.add("Betreuungen: %.1f SWS, max. %.1f angerechnet"
                .formatted(betreuungenRoh, e.getMaxSwsBetreuung()));
        }

        return DeputatsErgebnis.builder()
            .swsLehre(round(swsLehre))
            .gesamtdeputat(round(gesamt))
            .nettoLehrverpflichtung(round(prof.getNettoLehrverpflichtung()))
            .differenz(round(diff))
            .bewertung(bewertung)
            .warnungen(warnungen)
            .build();
    }
}

Credit Recognition Status Timeline

tsx

React-Stepper-Komponente implementiert einen 6-Stufen-Lifecycle (Entwurf → Eingereicht → In Prüfung → Geprüft → Ergebnis mitgeteilt → Abgeschlossen) mit Nachforderung-Handling, Zurückweisung-Anzeige, rollenbasierter Sichtbarkeit und Datums-Formatierung.

const TIMELINE_STEPS: TimelineStep[] = [
  { status: 'entwurf', label: 'Entwurf', dateField: 'created_at' },
  { status: 'eingereicht', label: 'Eingereicht', dateField: 'eingereicht_am' },
  { status: 'in_pruefung', label: 'In Pruefung', dateField: 'in_pruefung_am' },
  { status: 'geprueft', label: 'Geprueft', dateField: 'geprueft_am' },
  { status: 'ergebnis_mitgeteilt', label: 'Ergebnis mitgeteilt', dateField: 'ergebnis_mitgeteilt_am' },
  { status: 'abgeschlossen', label: 'Abgeschlossen', dateField: 'abgeschlossen_am' },
];

export default function AnerkennungStatusTimeline({ antrag, viewerRolle }: AnerkennungStatusTimelineProps) {
  const activeStepIndex = getActiveStepIndex(antrag.status);
  const isStudent = viewerRolle === 'student';

  return (
    <Box>
      <Stepper activeStep={activeStepIndex} orientation="vertical">
        {TIMELINE_STEPS.map((step, index) => {
          const dateValue = antrag[step.dateField] as string | undefined;
          const isCompleted = index < activeStepIndex;
          const isActive = index === activeStepIndex;
          const hasNachforderung =
            step.status === 'in_pruefung' &&
            (antrag.status === 'nachforderung' || antrag.nachforderung_am);

          return (
            <Step key={step.status} completed={isCompleted}>
              <StepLabel
                error={isActive && antrag.status === 'nachforderung'}
              >
                <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
                  <Typography variant="body2" sx={{ fontWeight: isActive ? 600 : 400 }}>
                    {step.label}
                  </Typography>
                  {isActive && antrag.status === 'nachforderung' && (
                    <Chip label="Nachforderung" size="small" color="error" variant="outlined" />
                  )}
                </Box>
              </StepLabel>
              <StepContent>
                {isActive && antrag.status === 'nachforderung' && antrag.nachforderung_grund && (
                  <Typography variant="body2" color="error.main">
                    Nachforderung: {antrag.nachforderung_grund}
                  </Typography>
                )}
                {step.status === 'eingereicht' && antrag.zurueckgewiesen_am && (
                  <Chip label="Zurueckgewiesen" size="small" color="warning" variant="outlined" />
                )}
              </StepContent>
            </Step>
          );
        })}
      </Stepper>
    </Box>
  );
}

RBAC — Spring Security mit Rollen

java

Konfiguration der Rollen-basierten Zugriffskontrolle in Spring Security: granulare URL-Mapping-Regeln plus methoden-basierte Annotation per @PreAuthorize. JWT-Filter validiert Token aus dem Authorization-Header und befüllt den SecurityContext.

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(AbstractHttpConfigurer::disable)
            .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/dekanat/**").hasRole("DEKAN")
                .requestMatchers("/api/deputat/own/**").hasAnyRole("DEKAN", "PROFESSOR")
                .requestMatchers("/api/anerkennung/pruefung/**").hasRole("DOZENT")
                .anyRequest().authenticated())
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
    }
}

// Methoden-basierte Absicherung im Controller
@RestController
@RequestMapping("/api/semester")
@RequiredArgsConstructor
public class SemesterPlanungController {

    private final PlanungService planung;

    @PreAuthorize("hasAnyRole('DEKAN', 'VERWALTUNG')")
    @PostMapping("/{id}/freigabe")
    public ResponseEntity<PlanungDto> freigeben(@PathVariable Long id, Principal user) {
        return ResponseEntity.ok(planung.freigeben(id, user.getName()));
    }
}