v0.59.21 Juli 2026 Features

Features

DB-Migrationen ab bestimmter Version starten

  • deploy-migrations.ps1 und deploy-migrations-dev.ps1 unterstützen jetzt den Parameter -StartVersion (z.B. -StartVersion 050), um Migrationsskripte mit einer kleineren Versionsnummer als angegeben zu überspringen, statt immer alle Skripte ab 001_... erneut auszuführen.
  • Ohne Angabe von -StartVersion verhalten sich beide Skripte wie bisher (alle Skripte werden ausgeführt).
v0.59.20 Juli 2026 Fixes

Fixes

Backend-E2E-Test “Mandanten-Admin landet auf dem Dashboard” seit v0.59.6 rot

  • Seit der persönlichen Begrüßung im Dashboard (<h1>Willkommen, {{ auth.user()?.name }}</h1> statt <h1>Dashboard</h1>, v0.59.6, #133) suchte tenant-dashboard.spec.ts weiterhin nach einer Überschrift mit dem exakten (Teil-)Text “Dashboard” — die gab es seitdem nicht mehr, der Test schlug auf master seit diesem Commit durchgängig fehl.
  • Assertion angepasst auf getByRole('heading', { name: /Willkommen/ }).
v0.59.19 Juli 2026 Fixes

Fixes

Migration 036 (User-Dashboard-Layouts) schlug in Produktion an verwaisten Mandanten-Referenzen fehl

  • 036_user_dashboard_layouts.sql scheiterte beim nachträglichen Ergänzen der Fremdschlüssel- Constraint mit insert or update ... violates foreign key constraint "fk_user_dashboard_layouts_tenant", weil bereits Layout-Zeilen für einen zwischenzeitlich gelöschten Mandanten existierten (mandant_id=6 in Produktion, ohne passenden Eintrag in tenant).
  • Die Migration räumt jetzt verwaiste Zeilen auf (DELETE ... WHERE mandant_id NOT IN (SELECT id FROM tenant)), bevor die Fremdschlüssel-Constraint ergänzt wird — analog zum bisherigen Vorgehen bei der Schutzklasse-Spaltenbereinigung in 009_dguv_v3.sql.
v0.59.18 Juli 2026 Fixes

Fixes

Production-Deploy der Suite-Frontend schlug mit “Permission denied” fehl

  • /www-revuwork-suite auf dem Produktivserver gehört root (einmalig manuell angelegt); der deploy-User darf das Verzeichnis selbst nicht entfernen, nur seinen Inhalt.
  • .github/workflows/deploy-production.yml und build-deploy-linux.ps1 haben beim Deploy des Suite-Frontends bisher rm -rf $REMOTE_SUITE && mkdir -p $REMOTE_SUITE ausgeführt — das scheiterte mit rm: cannot remove '/www-revuwork-suite': Permission denied, nachdem der Inhalt bereits gelöscht war, und brach den Deploy-Job ab.
  • Beide Stellen räumen jetzt nur noch den Inhalt des Verzeichnisses auf (mkdir -p $REMOTE_SUITE && rm -rf $REMOTE_SUITE/*) statt das Verzeichnis selbst zu entfernen.
v0.59.17 Juli 2026 Features

Features

revuwork.suite wird jetzt mit dem Kernprodukt zusammen deployt

  • build-deploy-linux.ps1 deployt jetzt drei Bausteine statt zwei: Backend, revuwork-ui-Frontend und revuwork-suite-ui-Frontend (neues -OnlySuite-Flag, kombinierbar mit -OnlyFrontend/-OnlyApi). Grund: revuwork.suite teilt sich dasselbe Backend mit dem Kernprodukt, ein separates Deploy-Skript hätte nur unnötig zwei Stellen für dieselbe Server-Zielumgebung gepflegt.
  • Das bisherige eigenständige Skript build-deploy-suite-light-linux.ps1 wurde entfernt.
  • .github/workflows/deploy-production.yml (spiegelt build-deploy-linux.ps1 für CI-basierte Deploys) baut und deployt revuwork-suite-ui jetzt im selben Lauf mit.
  • build-deploy.ps1 (separates Test-Ziel test.stratworx.de/amp via IIS) bleibt unverändert — dort ist revuwork.suite nicht vorgesehen.
v0.59.16 Juli 2026 Fixes

Fixes

Migration räumt verwaiste Inventory.Schutzklasse-Spalte aktiv auf

  • Der Guard aus 0.59.14 verhinderte nur, dass Inventory.Schutzklasse künftig erneut angelegt wird — bereits betroffene Datenbanken (bei denen die Spalte durch frühere Deploys schon leer wieder da war) blieben davon unberührt, wodurch die Mandanten-Datenmigration weiterhin mit column "schutzklasse" ... does not exist fehlschlagen konnte
  • 009_dguv_v3.sql droppt die verwaiste Spalte jetzt aktiv, sofern sie nachweislich leer ist (keine Zeile mit einem Wert) und ProtectionClass (das Umbenennungsziel) bereits existiert — kein Datenverlust möglich, da nur eine garantiert leere Spalte entfernt wird
  • Die Prüfung ist dabei verschachtelt statt mit AND kombiniert (analog 040_manual_intervention_automation.sql), da Postgres Tabellenreferenzen einer WHERE-Bedingung beim Parsen auflöst, auch ohne Kurzschluss — auf einer frischen Datenbank ohne die Spalte wäre der erste Entwurf sonst schon beim Parsen mit “column does not exist” gescheitert (in CI durch den sql-migrations-idempotency-Check aufgefallen, bevor es in Produktion landete)
v0.59.14 Juli 2026 Fixes

Fixes

Migrationen: verwaiste Legacy-Spalte nach Umbenennung

  • 009_dguv_v3.sql fügte Inventory.Schutzklasse per ADD COLUMN IF NOT EXISTS hinzu; 028_english_rename.sql benennt sie später zu ProtectionClass um. Da alle Migrationen bei jedem Deploy erneut vollständig durchlaufen, legte 009 die alte Spalte nach der Umbenennung bei jedem weiteren Lauf leer neu an — beide Spalten existierten dauerhaft nebeneinander. Das führte u.a. dazu, dass die Mandanten-Datenmigration (SuperAdmin → “Mandant migrieren”) mit column "schutzklasse" ... does not exist fehlschlug, sobald ein Mandant Inventardaten hatte
  • 009 prüft jetzt zusätzlich, ob ProtectionClass bereits existiert, bevor Schutzklasse neu angelegt wird
  • 040_manual_intervention_automation.sql verglich AspNetUsers gegen information_schema.tables.table_name='aspnetusers' (klein geschrieben) — die Tabelle wird von EF Core Identity aber case-preserved/quotiert angelegt, der Vergleich matchte nie und die komplette Anweisung (Tracking-Felder für den Bestätigungsmail-Retry) wurde stillschweigend übersprungen. Nutzt jetzt denselben pg_class-basierten Vergleich wie die entsprechende Stelle in 028_english_rename.sql
v0.59.13 Juli 2026 Fixes

Fixes

Mandanten-Datenmigration: Verifikation ignorierte vorbefüllte Referenzdaten

  • TenantDataMigrationService.MigrateAsync verglich nach dem Kopieren einer Tabelle die mandantenscoped Quellzahl mit der gesamten Zeilenzahl der Zieltabelle. Tabellen, die bei der Tenant-Provisionierung bereits mit globalen Standarddaten vorbefüllt werden (z.B. VisualCheckTemplate mit Standard-Prüfvorlagen ohne Mandantenbezug), hatten dadurch nie eine Zieldatenzahl von 0 — die Verifikation schlug fehl, obwohl der Kopiervorgang selbst korrekt war
  • Die Verifikation vergleicht jetzt die Differenz der Zielzeilenzahl vor/nach dem Kopieren mit der Quellzahl, statt der absoluten Zielzeilenzahl
v0.59.12 Juli 2026 Fixes

Fixes

Deploy löschte serverseitige appsettings.Production.json/appsettings.Preview.json

  • Der in 0.59.9 eingeführte rm -rf vor dem Kopieren des Backend-Builds hat auch appsettings.Production.json bzw. appsettings.Preview.json mitgelöscht — diese Dateien werden nur manuell auf dem Server gepflegt (Connection-Strings, Secrets), liegen aber im selben Verzeichnis wie der Build-Output. Jeder Deploy hat dadurch die Datenbankverbindung der Anwendung zerstört
  • deploy-production.yml und deploy-preview.yml sichern die jeweilige appsettings.*.json jetzt vor dem rm -rf nach /tmp und spielen sie danach zurück
  • Zusätzlich eine kurze Wartezeit vor dem abschließenden systemctl is-active-Check ergänzt, damit ein gerade erst neu gestarteter Dienst nicht fälschlich als fehlgeschlagen gemeldet wird, während er sich noch im Übergangszustand “activating” befindet
v0.59.11 Juli 2026 Fixes

Fixes

Mandanten-Datenmigration: Sequence-Reset schlug wegen Groß-/Kleinschreibung fehl

  • TenantDataMigrationService.CopyTableAsync übergab den Spaltennamen der Primärschlüssel-Spalte unquotiert in PascalCase (z.B. "Id") an pg_get_serial_sequence(). Postgres faltet das Tabellennamen-Argument dieser Funktion automatisch auf Kleinschreibung, gleicht das Spaltennamen-Argument intern aber exakt/case-sensitiv ab — da die Tenant-Datenbanken ihre Spalten tatsächlich kleingeschrieben anlegen, schlug der Abgleich fehl und die komplette Mandanten-Migration (SuperAdmin → “Mandant migrieren”) brach mit einem 500er ab, sobald eine Tabelle mit Daten befüllt war
  • Der Spaltenname wird beim Aufruf von pg_get_serial_sequence() jetzt klein geschrieben übergeben
v0.59.10 Juli 2026 Fixes

Fixes

Migrations-Deploy fragt DB-Passwort nur noch einmal ab

  • deploy-migrations.ps1 und deploy-migrations-dev.ps1 fragen das DB-Passwort jetzt nur noch einmal zu Skriptstart interaktiv ab (falls nicht per -DbPassword oder Umgebungsvariable AMV_DB_PASSWORD gesetzt), statt bei jeder einzelnen SQL-Datei/Datenbank erneut
v0.59.9 Juli 2026 Fixes

Fixes

Veraltete Build-Artefakte im Deploy behoben

  • deploy/api/, deploy/webapi/, deploy/web/ und deploy/frontend/ waren versehentlich als Build-Output ins Repo eingecheckt, darunter alte Amv.Api.*-Binaries von vor der Umbenennung des Projekts zu Revuwork.Api. Da der Deploy-Workflow das Zielverzeichnis auf dem Server bislang nicht vor dem Kopieren geleert hat, liefen diese veralteten Dateien bei jedem Deploy unbemerkt neben dem frischen Build weiter — der produktive Dienst startete dadurch tatsächlich weiterhin die alte, eingefrorene Binary statt der aktuell deployten Version
  • Die vier Build-Output-Ordner sind jetzt aus dem Git-Tracking entfernt und in .gitignore aufgenommen
  • deploy-production.yml und deploy-preview.yml leeren das Backend-Zielverzeichnis auf dem Server jetzt vor dem Kopieren (rm -rf + mkdir -p), analog zum bestehenden Verhalten beim Frontend-Deploy
v0.59.8 Juli 2026 Features

Features

DB-Migrationen im Production-Deploy-Workflow

  • deploy-production.yml führt jetzt analog zum Preview-Workflow automatisch die Postgres-Migrationen aus database/migrations/ gegen die Prod-Control-Plane-DB und alle Tenant-DBs aus, bevor der Backend-Dienst neu gestartet wird
  • Neues Repo-Secret PROD_DB_PASSWORD erforderlich (analog PREVIEW_DB_PASSWORD); ist es nicht gesetzt, wird der Schritt übersprungen statt den Deploy zu blockieren
  • Der Workflow bleibt weiterhin ausschließlich manuell auslösbar (workflow_dispatch mit Pflicht-Bestätigung confirm: deploy), kein automatischer Trigger
v0.59.7 Juli 2026 Features

Features

MandantenID in der Mandantenverwaltung

  • In der Liste „Alle Mandanten” (SuperAdmin-Bereich) wird jetzt zusätzlich zu Slug und Datum auch die MandantenID angezeigt, um schnellere manuelle Datenbankabfragen zu ermöglichen
v0.59.6 Juli 2026 Features

Features

Persönliche Begrüßung im Dashboard

  • Die Dashboard-Überschrift zeigt jetzt „Willkommen, {Name}” statt eines statischen „Dashboard”-Titels
  • Bezieht sich auf Issue #119 — Logo und Farbschema pro Mandant waren bereits über die bestehende Branding-/Theme-Einstellungen (Admin → Einstellungen) umsetzbar, nur die Begrüßung fehlte noch
v0.59.5 Juli 2026 Breaking

Breaking

Umbenennung “ERP” auf “Suite”

Die interne ERP-Integration wurde von “ERP” auf “Suite” umbenannt (Backend-Klassen/DTOs, appsettings-Sektion, eigenständiges Frontend, Changelog- und Deploy-Skript-Namen). Verweise auf den echten externen Dienst ErpLicensePlugin (VEMAS NextGen) sowie Backend-Routen/-Methodennamen mit FromErp-Suffix bleiben unverändert.

  • ErpLicenseClient/IErpLicenseClientSuiteLicenseClient/ISuiteLicenseClient; DTOs ErpLicenseSnapshotDto, ErpLicenseTermsDto, ErpLicensePackageDto (samt ErpLicenseFeatureDto, ErpLicenseQuantityAllowancesDto, ErpLicenseAllowanceDto, ErpLicenseLineItemDto), ErpTrialLicenseRequestDto → jeweilige Suite*-Pendants
  • appsettings-Sektion ErpLicenseSuiteLicense
  • Eigenständiges Frontend src/revuwork-erp-ui/src/revuwork-suite-ui/, Produktname revuwork.erprevuwork.suite
  • Changelog-Verzeichnis changelog-erp/changelog-suite/ (siehe dort 0.3.0.md)
  • Deploy-Skript build-deploy-erp-light-linux.ps1build-deploy-suite-light-linux.ps1, Live-Pfad /erp/suite (erfordert manuellen Umzug auf dem Server, siehe Skript-Header)
v0.59.4 Juli 2026 Features

Features

Transparenz & Warnung bei Speicherprovider-Berechtigungen

Beim Einrichten eines Speicherproviders war bisher nicht ersichtlich, welche Berechtigungen die Verbindung mit sich bringt — und wenn eine bestehende Verbindung durch spätere Erweiterungen (z.B. neue Scopes) nicht mehr ausreichte, bemerkte man das erst an einem kryptischen Fehler beim Import.

  • Jede Provider-Karte unter Admin → Provider → Speicherprovider zeigt jetzt über ein Info-Icon (und beim unverbundenen Zustand direkt als Text), welche Zugriffe/Berechtigungen die Verbindung erteilt
  • OAuth2-Verbindungen (Dropbox, OneDrive, SharePoint, Google Drive) speichern jetzt den beim Connect gewährten Scope. Fordert der Code inzwischen weitere Berechtigungen an als beim letzten Connect gespeichert, zeigt die Karte statt “Verbunden” ein Warnhinweis “Verbindung veraltet — bitte neu verbinden” mit einem direkten “Neu verbinden”-Button
  • Neue Spalte GrantedScope in StorageProviderConnection (Migration 049), neues Feld needsReconnect in der /admin/storage-providers-Antwort
v0.59.3 Juli 2026 Fixes

Fixes

Dropbox-Import schlug mit “Status 400 (Bad Request)” fehl

Der Dropbox-OAuth2-Connect forderte keinen expliziten scope-Parameter an (im Unterschied zu OneDrive, SharePoint und Google Drive, die das bereits taten). Dadurch erhielt Dropbox beim Verbinden nur die im App Console als Default markierten Berechtigungen — meist ausreichend für den automatischen PDF-Backup-Upload, aber nicht für das Auflisten (files.metadata.read) oder Herunterladen (files.content.read) von Dateien beim Import.

  • DropboxStorageProviderClient fordert jetzt explizit account_info.read files.content.write files.content.read files.metadata.read an
  • Wichtig: Bereits bestehende Dropbox-Verbindungen müssen einmalig unter Admin → Provider → Speicherprovider getrennt und neu verbunden werden, damit ein Token mit den neuen Berechtigungen ausgestellt wird — der Scope eines bereits ausgestellten Tokens ändert sich nicht automatisch
  • Zusätzlich prüfen: im Dropbox App Console (Permissions-Tab der App) müssen files.metadata.read, files.content.read, files.content.write und account_info.read aktiviert sein, sonst kann Dropbox den angeforderten Scope nicht erteilen
v0.59.2 Juli 2026 Fixes

Fixes

Speicherprovider-Browse zeigt echte Fehlerursache

Der Datei-Browser “Aus Speicheranbieter importieren” (Import-Center) zeigte bei jedem Fehler nur die generische Meldung “Ordner konnte nicht geladen werden.” — unabhängig davon, ob z.B. ein Token abgelaufen war, die Verbindung zum Provider fehlschlug oder ein anderer Fehler auftrat.

  • Backend (StorageProvidersController.Browse): fängt jetzt auch nicht-InvalidOperationException-Fehler (z.B. fehlgeschlagene Token-Entschlüsselung, Netzwerkfehler zum Provider) ab, loggt sie serverseitig und liefert eine aussagekräftige ProblemDetails-Meldung statt eines opaken 500ers
  • Frontend (StorageExplorerComponent): zeigt jetzt die vom Backend gelieferte Fehlermeldung (detail) an, statt sie durch einen hartkodierten Text zu ersetzen
v0.59.1 Juli 2026 Features

Features

Hinweis zur Datenspeicherung im Browser

Beim ersten Aufruf der Anwendung erscheint jetzt ein dismissibarer Hinweis-Banner, der erklärt, dass die Anmeldesitzung sowie einige UI-Einstellungen (Theme, Seitenleisten-Status, Ansichtsmodus) lokal im Browser gespeichert werden und kein Tracking stattfindet. Der Hinweis wird nach Bestätigung (“Verstanden”) dauerhaft pro Browser unterdrückt.

v0.59.0 Juli 2026 Features

Features

Verlinkung Kunden-Grid → Inventarliste

In der Kundenliste öffnet ein Klick auf die Spalte “Geräte” jetzt direkt die Inventarliste, gefiltert auf den jeweiligen Kunden. Der Filter wird als entfernbarer Chip angezeigt.

v0.58.2 Juli 2026 Features

Features

Administration neu strukturiert

Die Admin-Startseite wurde neu gegliedert, damit verwandte Funktionen leichter zu finden sind:

  • Logs: Audit-Log, Import-Journal
  • Sicherheit: API-Keys, Webhooks
  • Provider: Speicherprovider
  • Einstellungen: aufgeteilt in eigene Unterseiten — Allgemein (Mandant, Inventar-Export, Inventar-Archivierung), Themes / Farben, Benachrichtigungen, Backups, Sichtprüfungen
  • Verwaltung: Benutzer

Die bisherige Sammel-Seite /admin/settings wurde in vier eigenständige, per Rolle sichtbare Unterseiten aufgeteilt (/admin/settings/general, /admin/settings/theme, /admin/settings/notifications, /admin/settings/backups).

v0.58.1 Juli 2026 Fixes

Fixes

Admin-Dashboard: doppelte Überschrift entfernt

  • Im SuperAdmin-Bereich zeigte die Seite “Admin-Dashboard” zwei Überschriften an (“Admin-Dashboard” und “Dashboard”). Die redundante Seitenüberschrift wurde entfernt.
v0.58.0 Juli 2026 Features

Features

Speicheranbieter: Azure Blob Storage (Beta)

  • Neuer Speicherprovider Azure Blob Storage — authentifiziert über eine Azure-AD-App-Registrierung (Service Principal, Client-Credentials-Flow) statt statischem Access-Key/Secret-Key. Reiht sich als weiterer IKeyBasedStorageProviderClient neben s3 ein (siehe 0-56-0.md): Tenant-ID/Client-ID/Client-Secret/Storage-Account/Container werden über dasselbe Zugangsdaten-Formular wie bei S3-Anbietern eingegeben (Feldbeschriftungen provider-spezifisch), intern auf die generischen StorageProviderKeyCredentials-Felder gemappt (Endpoint→Storage-Account-URL, Region→Tenant-ID, Bucket→Container, AccessKey→Client-ID, SecretKey→Client-Secret) und in derselben StorageProviderKeyConnection-Tabelle gespeichert — keine neue Migration nötig.
  • Da Access-Keys bei Azure nicht existieren, holt der Client bei jedem Aufruf (Test/Upload/Listing/Download) einen frischen AAD-Bearer-Token per Client-Credentials-Flow; anders als bei den OAuth2-Providern gibt es dafür kein eigenes Token-Caching in StorageProviderService.
  • Als Beta gekennzeichnet, solange noch keine Praxiserfahrung in Produktion vorliegt.

Import: Speicheranbieter als Quelle nutzen (interner Explorer)

  • Im Import-Center kann eine Datei jetzt zusätzlich zum lokalen Upload aus einem verbundenen und aktivierten Speicheranbieter importiert werden — Auswahl über einen neuen, wiederverwendbaren Datei-/Ordner-Browser (app-storage-explorer, shared/components/storage-explorer/).
  • Dafür wurden sowohl IStorageProviderClient (OAuth2-Provider) als auch IKeyBasedStorageProviderClient (Access-Key-Provider) um Listing (ListAsync) und Download (DownloadFileAsync) erweitert und für alle sieben Provider implementiert (Dropbox, OneDrive, SharePoint, Google Drive, Box, S3, Azure Blob).
  • Neuer Endpunkt GET /admin/storage-providers/{provider}/browse liefert Ordner-/Dateiinhalt für den Explorer; POST /import/upload-from-provider lädt die ausgewählte Datei serverseitig herunter und speist sie in dieselbe Import-Pipeline wie der lokale Datei-Upload ein.
v0.57.1 Juli 2026 Fixes

Fixes

  • Der Sidebar-Eintrag “Administration” (verlinkt auf die neue Card-Grid-Übersichtsseite aus #82) steht jetzt am Ende der Navigationsliste, direkt über “Hilfe & Support”, statt zwischen den Kernfunktionen und dem SuperAdmin-Bereich “Mandanten”.
v0.57.0 Juli 2026 Features

Features

Administration: neue Card-Grid-Übersichtsseite

  • Neue Seite unter /admin fasst alle bisherigen Admin-Unterseiten (Benutzer, Einstellungen, Sicherheit, Import-Journal, Webhooks, Speicheranbieter, Sichtprüfungs-Vorlagen, Audit-Journal) in Kategorie-Cards (“Einstellungen”, “Verwaltung”) zusammen, inkl. Client-seitigem Suchfeld zum Filtern der Einträge.
  • Die zugehörigen Admin-Einträge wurden aus der globalen Sidebar entfernt; stattdessen gibt es dort nur noch einen einzelnen Eintrag “Administration”, der auf die neue Übersichtsseite verlinkt. Reines Layout-Redesign — Labels, Routen und Rollen-Sichtbarkeit der einzelnen Admin-Funktionen sind unverändert (1:1-Migration).
  • Kategorien und Rollen-Sichtbarkeit kommen aus dem neuen, zentralen AdminCategoriesService (features/admin/admin-categories.service.ts) statt aus verstreuten group-Feldern, die zuvor pro Rolle (Admin/Editor/SuperAdmin) dupliziert waren.
  • Die zur Laufzeit editierbare Rollenzuordnung pro Eintrag durch SuperAdmins ist bewusst nicht Teil dieser Änderung — siehe Folge-Issue #81.
v0.56.0 Juli 2026 Features

Features

Neuer Speicheranbieter: S3-kompatibler Objektspeicher (ohne OAuth2)

  • Ergänzt die bisher rein OAuth2-basierte Speicherprovider-Verwaltung (Dropbox, OneDrive, SharePoint, Google Drive, Box) um einen Provider-Typ mit statischer Access-Key/Secret-Key-Authentifizierung: s3. Deckt AWS S3, Hetzner Object Storage und MinIO ab, da alle das S3-Protokoll sprechen (ForcePathStyle aktiv für Anbieter ohne Wildcard-Subdomain-DNS).
  • Neues, paralleles Interface IKeyBasedStorageProviderClient (Provider, TestConnectionAsync, UploadFileAsync) ergänzt IStorageProviderClient, statt es zu verbiegen — OAuth2-spezifische Methoden (BuildAuthorizeUrl/ExchangeCodeAsync/RefreshAsync) passten nicht zu statischen Zugangsdaten (siehe bekannte Lücke in 0-55-0.md). StorageProviderService verwaltet beide Provider-Arten transparent nebeneinander; neue Provider werden weiterhin einfach per DI registriert.
  • StorageProviderDto hat ein neues Feld authMode (oauth2 | apikey), damit das Frontend pro Provider-Karte den passenden “Verbinden”-Fluss zeigt: Redirect zu GET /{provider}/connect bei OAuth2, ein Zugangsdaten-Formular mit POST /{provider}/connect (Endpoint, Region, Bucket, Access Key, Secret Key) bei Access-Key-Providern. Die Zugangsdaten werden vor dem Speichern sofort getestet — bei Fehlschlag wird nichts persistiert.
  • Neue Tabelle StorageProviderKeyConnection (Migration 048_storage_provider_key_connections.sql, verschlüsselter Access-/Secret-Key analog zu den OAuth2-Tokens) statt Wiederverwendung von StorageProviderConnection, da sich die Spalten nicht überschneiden (kein Refresh-Token/Ablaufzeit, dafür Endpoint/Bucket/Region).
  • Zielordner-Einstellung (StorageProviderSettings) funktioniert unverändert auch für s3 (als Objekt-Präfix); der automatische Prüfbericht-PDF-Backup (PruefberichtBackupService) unterstützt S3 dadurch ohne eigene Anpassung, da er ausschließlich über IStorageProviderService.UploadFileAsync läuft.
v0.55.2 Juli 2026 Features

Features

Speicheranbieter: echte Provider-Logos statt generischer Icons

  • Die Speicheranbieter-Karten (Dropbox, OneDrive, SharePoint, Google Drive, Box) zeigen jetzt das jeweilige Marken-Logo statt eines generischen Material-Icons — bessere Wiedererkennbarkeit auf einen Blick.
  • Logos liegen als eigenständige SVG-Dateien unter public/storage-provider-logos/, jeweils mit der offiziellen Markenfarbe eingefärbt (Dropbox #0061FF, OneDrive #0078D4, SharePoint #038387, Google Drive #2684FC, Box #0061D5). Dropbox/Google Drive/Box stammen aus dem aktuellen, CC0-lizenzierten Simple-Icons-Katalog; die OneDrive-/SharePoint-Formen wurden aus einer älteren Simple-Icons-Version übernommen, da Microsoft-Produkte dort inzwischen aus dem offiziellen Katalog entfernt wurden — die Nutzung als reine Wiedererkennungsmarke für den “Verbinden”-Button ist als nominativer Fair-Use-Verweis auf den Drittanbieter-Dienst unproblematisch.
v0.55.1 Juli 2026 Features

Features

Automatisches PDF-Backup für Prüfberichte

  • Neuer Schalter “Automatisches PDF-Backup” in den Mandanten-Einstellungen (Karte “Prüfbericht-Backup”): sichert einmal täglich im Hintergrund die PDFs aller finalisierten Prüfberichte beim aktivierten externen Speicherprovider des Mandanten.
  • Der Schalter ist standardmäßig deaktiviert und lässt sich erst aktivieren, wenn mindestens ein Speicherprovider verbunden und eingeschaltet ist (PUT /settings liefert sonst 422 Unprocessable Entity). Wird der Provider später wieder deaktiviert, überspringt der Hintergrunddienst den Mandanten mit einer Warnung, statt fehlzuschlagen.
  • Neuer manueller/externer Cron-Trigger-Endpunkt POST /inspection/pdf-backup/run — verarbeitet unabhängig vom internen 24h-Hintergrunddienst alle Mandanten mit aktiviertem Schalter (analog zu POST /inventory/archive/run).
  • IStorageProviderClient kann jetzt Dateien hochladen (UploadFileAsync, überschreibend/idempotent) — implementiert für alle Provider (Dropbox, OneDrive, SharePoint, Google Drive, Box) in den in den jeweiligen Speicherprovider-Einstellungen konfigurierten Zielordner.
v0.55.0 Juli 2026 Features

Features

Neue Speicheranbieter: OneDrive, SharePoint, Google Drive, Box

  • Vier neue OAuth2-fähige Storage-Provider ergänzt (Speicheranbieter-Verwaltung unterstützte bisher nur Dropbox): onedrive, sharepoint, googledrive, box. Verbinden, Trennen, Aktivieren/Deaktivieren, Testen und Zielordner-Einstellung funktionieren identisch zu Dropbox — kein Sonderfall im Frontend.
  • OneDrive und SharePoint teilen sich eine gemeinsame Microsoft-Graph-OAuth2-Basisklasse (MicrosoftGraphStorageProviderClientBase), da beide über dieselbe Azure-AD-App-Registrierung laufen und sich nur in Scope (Files.ReadWrite vs. Sites.ReadWrite.All) und Konto-Query unterscheiden.
  • SharePoint benötigt zusätzlich zur Zielordner-Einstellung die ID der SharePoint-Site (/sites/{siteId}/drive) — dafür wurde StorageProviderSettings um eine optionale SiteId-Spalte erweitert (Migration 047_storage_provider_settings_site_id.sql). Bei allen anderen Providern bleibt sie ungenutzt/null.
  • Das bisher Dropbox-spezifische Settings-Formular (dropbox-settings-form) wurde durch ein generisches, providerparametrisiertes Formular (storage-provider-settings-form) ersetzt, das das Site-ID-Feld nur für SharePoint einblendet.
  • Neue App-Zugangsdaten-Konfigurationssektionen MicrosoftGraph, GoogleDrive, Box in appsettings.json (analog zu Dropbox) — müssen serverseitig mit den jeweiligen OAuth2-App-Credentials befüllt werden, bevor die Provider nutzbar sind.

Bekannt: Amazon S3 / S3-kompatible Speicher noch nicht unterstützt

  • S3 und S3-kompatible Anbieter (Hetzner Object Storage, MinIO, Azure Blob im Access-Key-Modus) authentifizieren über Access-Key/Secret statt OAuth2 und passen nicht in das bestehende IStorageProviderClient-Interface (BuildAuthorizeUrl/ExchangeCodeAsync/RefreshAsync). Das ist als separate Erweiterung vorgesehen.
v0.54.1 Juli 2026 Fixes

Fixes

Storage-Provider-Callback: kein ungefangener 500 mehr, Fehler werden geloggt

  • StorageProviderService.HandleCallbackAsync fing bisher nicht alle Fehlerfälle ab: schlug das Speichern der neu verbundenen Verbindung fehl, führte das zu einem ungefangenen 500 Internal Server Error auf /admin/storage-providers/{provider}/callback statt eines Redirects mit Fehlerstatus.
  • Alle Fehlerpfade im Callback (State ungültig, Code-Exchange fehlgeschlagen, Konto-Info nicht abrufbar, Speichern fehlgeschlagen) werden jetzt sauber abgefangen und mit ILogger geloggt (vorher: StorageProviderService hatte kein Logging, Fehler waren nur über eine generische ProblemDetails-Antwort ohne Detail sichtbar).

StorageProviderConnection/-Settings: FK-Verletzung bei physisch getrennten Mandanten-DBs

  • Ursache des zuvor beobachteten 500ers: TenantId REFERENCES Tenant(Id) in den Migrationen 044/045 validierte bei physisch getrennten Tenant-DBs nur gegen die dortige leere Schatten-Kopie von Tenant (echte Tenant-Zeilen leben nur in der Control-Plane-DB) — jeder Schreibzugriff schlug mit 23503 foreign key violation fehl. Exakt derselbe Fehler wurde für andere Tabellen bereits in Migration 039_drop_cross_db_tenant_fks.sql (Issue #3) behoben; die neuen Tabellen haben ihn wiederholt.
  • Neue Migration 046_storage_provider_drop_tenant_fk.sql entfernt die FK-Constraints (analog zu 039) — TenantId bleibt erhalten, die Zugehörigkeit wird weiterhin über ITenantContext sichergestellt.
v0.54.0 Juli 2026 Features

Features

Eigenes Einstellformular pro Speicheranbieter

  • Neues Einstellformular pro Provider: über das Zahnrad-Symbol auf der Karte (/admin/storage-providers) hinterlegt jeder Mandant seine providerspezifischen Zusatz-Einstellungen — für Dropbox aktuell: optionaler Zielordner für Exporte.
  • Jeder Provider bekommt sein eigenes, dediziertes Formular (DropboxSettingsFormComponent) statt eines generischen Einstellungs-Screens — weitere Provider ergänzen künftig ihr eigenes Formular, ohne bestehende anzufassen.
  • App Key/Secret für den Dropbox-OAuth2-Flow bleiben zentral in der Server-Konfiguration (Dropbox:AppKey/Dropbox:AppSecret, per systemd-Env Dropbox__AppKey/Dropbox__AppSecret) — eine Dropbox-App für alle Mandanten, wie bisher.

Fixes

Dropbox-Verbindung als SuperAdmin blieb nach erfolgreichem Connect als “nicht verbunden” stehen

  • StorageProviderRepository/StorageProviderSettingsRepository nutzten die ambiente factory.CreateConnection()-Überladung statt der expliziten factory.CreateConnection(tenantId). Der Dropbox-OAuth2-Callback läuft ohne ?tenantId=-Query-Parameter (Dropbox liefert nur code/state zurück), wodurch ITenantContext.TenantId für SuperAdmins dort null war und die neue Verbindung fälschlich in der Control-Plane-DB statt der Tenant-DB landete (analog zur Regression aus v0.42.1 bei AuditRepository).
  • Alle Storage-Provider-Repository-Methoden verwenden jetzt durchgängig die explizite Tenant-Verbindung; Regressionstests ergänzt (StorageProviderRepositoryTests).
v0.53.1 Juli 2026 Fixes

Fixes

Speicheranbieter: Karten-Layout verkleinert

  • Provider-Kacheln auf der Seite „Speicheranbieter” (/admin/storage-providers) von einer vollbreiten Zeilenliste auf ein kompaktes Karten-Grid umgestellt, sodass bei ausreichender Breite 4 Karten nebeneinander passen (responsiv: 3 / 2 / 1 Spalten auf kleineren Viewports).
v0.53.0 Juli 2026 Features

Features

Einstellformular „Speicheranbieter” (Dropbox)

  • Neuer Admin-Bereich Speicheranbieter (/admin/storage-providers), in dem Mandanten externe Storage-Provider per OAuth2 verbinden können — erster Provider: Dropbox.
  • Backend-Architektur bewusst providerunabhängig gehalten (IStorageProviderClient), damit weitere Provider (z.B. OneDrive, Google Drive) ohne Formular-Neubau ergänzt werden können.
  • Vollständiger OAuth2-Connect-Flow (/admin/storage-providers/dropbox/connect → Dropbox-Autorisierung → /admin/storage-providers/dropbox/callback), inkl. signiertem, zeitlich begrenztem State-Parameter gegen CSRF.
  • Zugangs- und Refresh-Token werden mandantenspezifisch verschlüsselt gespeichert (IDataProtector) und bei Bedarf automatisch erneuert.
  • Verbindung kann pro Mandant aktiviert/deaktiviert, getestet (Konto-Info abrufen) und getrennt werden.
v0.52.12 Juli 2026 Features

Features

Prüfberichte-Liste auf das neue Data-Grid umgestellt

Die Prüfberichte-Liste nutzt jetzt app-data-grid statt der handgebauten Karten-Liste, analog zur Inventar- und Kundenliste: Drag&Drop-Spaltenreorder, Gruppierung (persistiert pro Benutzer), sortierbare Spaltenköpfe für die serverseitig unterstützten Felder (Gerät/Typ, Prüfdatum, nächste Prüfung, Ergebnis, Importdatum) sowie eine funktionierende Mehrfachauswahl für den Excel-Export.

v0.52.11 Juli 2026 Fixes

Fixes

Inventarliste: weißer Bildschirm behoben

InventoryListComponent hat DatePipe per inject(DatePipe) verwendet, ohne die Pipe als Provider zu registrieren. Das führte beim Öffnen der Inventarliste zu einem NG0201-Fehler (“No provider found for DatePipe”), der das Rendern der gesamten Komponente verhinderte — Seite blieb komplett weiß, keine Toolbar, kein Grid. DatePipe ist jetzt Teil der Komponenten-Provider.

v0.52.10 Juli 2026 Features

Features

Inventar-Liste: Umstellung auf das neue Grid

Die Tabellenansicht der Inventarliste (inventory-list) nutzt jetzt die neue app-data-grid-Komponente statt der bisherigen, handgebauten Karten-Liste — analog zur bereits umgestellten Kundenliste (customer-list).

  • Spalten lassen sich per Drag & Drop verschieben und in die Gruppierleiste ziehen; die bestehende Spalten-Konfiguration (Dialog „Spalten“) bleibt erhalten und bleibt die Quelle der Wahrheit für Sichtbarkeit/Reihenfolge
  • Gruppierzustand wird jetzt (wie bei der Kundenliste) pro Benutzer gespeichert (UserPreferenceService.saveGroupLevels, Kontext inventory)
  • Sortierbare Spaltenköpfe für die serverseitig sortierbaren Felder (Typ, Art, Gebäude, Geschoss, Raum, Status, nächste/letzte Prüfung, Hersteller, Projektnummer)
  • Mehrfachauswahl per Checkbox-Spalte für „Als MXP exportieren“ und „Kunde zuweisen“ ist jetzt tatsächlich nutzbar (vorher fehlte dafür die UI)
  • Die Kartenansicht (app-card-Grid) ist unverändert; die farbige Status-Markierung der ganzen Zeile (ok/warnung/fehler) entfällt in der Tabellenansicht, da das neue Grid keine zeilenweite Einfärbung unterstützt — die Fälligkeits-Hervorhebung bleibt auf die Spalte „Nächste Prüfung“ beschränkt
v0.52.9 Juli 2026 Features

Features

Grid: Persistenz von Spalten- und Gruppierzustand

Die Kundenliste (customer-list) speichert Spalten-Sichtbarkeit/-Reihenfolge und den Gruppierzustand (groupLevels) jetzt pro Benutzer statt nur im Arbeitsspeicher der Komponente. Nach einem Neuladen der Seite bleibt sowohl die Spaltenkonfiguration als auch eine aktive Gruppierung erhalten.

  • Neue Backend-Endpunkte GET/PUT /api/v1/user/group-state (analog zu column-preferences), gesichert über dieselbe Benutzer-Authentifizierung und ohne Mandantenbezug (reine UI-Präferenz, wie bei den Spalteneinstellungen)
  • UserPreferenceService (Frontend) um getGroupLevels/saveGroupLevels erweitert; Kontext-Parameter unterstützt jetzt zusätzlich customer
  • Neue Tabelle UserGroupLevel (Control-Plane-DB), idempotent angelegt über UserPreferenceRepository.EnsureTableAsync() analog zu UserColumnPreference
v0.52.8 Juli 2026 Features

Features

Grid: Aggregate/Summen in Gruppenzeilen

ColumnConfig bekommt ein neues optionales Feld aggregate?: 'sum' | 'avg'. Ist es für eine Spalte gesetzt, zeigt die neue DataGridComponent-Gruppierung (shared/components/data-grid) neben Gruppenwert und Anzahl jetzt auch die Summe bzw. den Durchschnitt dieser Spalte über die Zeilen der jeweiligen Gruppe an (Betrag: Σ 1.234,56) — sowohl in der Tabellen- als auch in der Kartenansicht.

  • Nicht-numerische Werte innerhalb einer Gruppe werden beim Aggregieren übersprungen; enthält eine Gruppe gar keinen numerischen Wert, wird für sie kein Aggregat angezeigt
  • Betrifft nur Spalten mit explizit gesetztem aggregate — unverändertes Verhalten für bestehende Konsumenten ohne diese Option
v0.52.7 Juli 2026 Features

Features

Kundenliste: vollständige Toolbar wie bei Prüfberichten/Inventar

Die Kundenliste (Kunden) hat jetzt dieselbe Toolbar wie die Prüfberichte- und Inventarliste:

  • Filter: Suchfeld plus separates Filter-Menü über alle Kundenfelder (Name, Straße, PLZ, Ort, externe Referenz, Anzahl Geräte von/bis) mit entfernbaren Filter-Chips
  • Spalten: “Spalten X/Y”-Button mit Badge öffnet dieselbe Spalten-Auswahl wie zuvor, jetzt nur optisch aufgewertet statt als reines Icon
  • 3-Punkte-Menü: neuer Excel-Export der aktuell sichtbaren/gefilterten/ gruppierten Kundenliste
  • Die bestehende Drag&Drop-Gruppierleiste des Grids bleibt unverändert erhalten

DataGridComponent (shared/components/data-grid) bekommt dafür ein neues optionales Input columnMenuVisible (Default true, unverändertes Verhalten für bestehende Konsumenten): darüber kann ein Konsument das eingebaute Spalten-Icon-Menü ausblenden und über die bereits öffentliche columnState/isColumnVisible/toggleColumnVisibility-API einen eigenen, stärker gestalteten “Spalten”-Button bauen — wie jetzt bei den Kunden.

Backend: Excel-Export für Kunden (POST /customers/export/excel)

Neuer Endpoint exportiert die per customerIds übergebenen Kunden (oder alle Kunden des Mandanten, wenn leer/weggelassen) als Excel-Datei. Respektiert wie alle Endpunkte die Mandantengrenze — angefragte IDs aus einem fremden Mandanten tauchen in der zugrunde liegenden, bereits mandantengefilterten Abfrage gar nicht erst auf.

v0.52.6 Juli 2026 Fixes

Fixes

Kundenliste: fehlende Toolbar ergänzt

Die Kundenliste (Kunden) wirkte nach der Migration auf shared/components/data-grid im Vergleich zur Prüfberichte-Liste leer — es fehlte die gewohnte Toolbar mit Suchfeld. Die Kundenliste hat jetzt dieselbe Toolbar-Optik wie die Prüfberichte-Liste (Suchfeld über Name/Adresse/externe Referenz, Aktions-Button daneben); der “Kunde anlegen”-Button ist aus der Kopfzeile in die Toolbar gewandert.

v0.52.5 Juli 2026 Features

Features

Grid: Karte/Tabelle-View-Toggle für shared/components/data-grid

DataGridComponent unterstützt jetzt optional einen Karte/Tabelle-View-Toggle, wie ihn die bisherige Card-List-Implementierung in inventory-list/inspection-list schon kannte:

  • Neues Input cardViewEnabled blendet zwei Toggle-Buttons (“Tabellenansicht” / “Kartenansicht”) in der Toolbar ein — ohne dieses Input bleibt das Grid wie bisher tabellenbasiert (kein Verhaltensunterschied für bestehende Konsumenten)
  • Neues Two-Way-Model viewMode ('table' | 'card'), damit Konsumenten die gewählte Ansicht wie bisher persistieren können (z.B. in localStorage)
  • Kartenansicht nutzt dieselben visibleRows() wie die Tabelle: Gruppierung (inkl. Ein-/Ausklappen) und Spalten-Sichtbarkeit wirken identisch in beiden Ansichten — die erste sichtbare Spalte wird zum Kartentitel, die übrigen zu Feld/Wert-Zeilen
  • Neue Direktive appGridCardDef als Erweiterungspunkt für ein komplett eigenes Karten-Layout, falls die generische Fallback-Karte nicht reicht
  • Auswahl (Checkbox) funktioniert in der Kartenansicht genauso wie in der Tabelle
v0.52.4 Juli 2026 Features

Features

Grid: Export-Extension-Point in shared/components/data-grid

DataGridComponent stellt jetzt einen öffentlichen exportRows()-Zugriff bereit, über den Konsumenten (z.B. inventory-list/inspection-list bei ihrer künftigen Migration auf die neue Grid-Komponente) an die aktuell sichtbaren/gefilterten/gruppierten Zeilen für einen eigenen Export (Excel/PDF/MXP) kommen:

  • exportRows() liefert die reinen Datenzeilen in der aktuellen Sortier-/Gruppierreihenfolge, über alle Seiten hinweg (nicht nur die paginierte Seite) und ohne Zeilen aus eingeklappten Gruppen
  • kombinierbar mit dem bereits über exportAs="appDataGrid" öffentlichen selectedIds() für einen “nur Auswahl exportieren”-Flow
  • Export-Logik selbst (Backend-Aufrufe, Datei-Erzeugung) bleibt bewusst beim Konsumenten, nicht im Grid
v0.52.3 Juli 2026 Features

Features

Kundenliste: Pagination aktiviert

Die Kundenliste (customer-list) nutzt jetzt die in 0.52.2 eingeführte Pagination-Unterstützung von DataGridComponent:

  • pagination="client" — die Grid-Komponente paginiert die vom Backend geladene Kundenliste selbst (kein neuer paginierter API-Endpunkt notwendig, CustomerService.getAll liefert weiterhin die volle Liste)
  • Funktioniert wie gewohnt in Kombination mit Sortierung und Gruppierung
v0.52.2 Juli 2026 Features

Features

Grid: Pagination-Integration in shared/components/data-grid

Die wiederverwendbare Grid-Komponente (DataGridComponent) unterstützt jetzt optional Pagination, ohne die bestehende API für aktuelle Konsumenten (customer-list) zu ändern:

  • Neuer Input pagination: 'none' (Standard, unverändertes Verhalten) | 'client' (die Grid-Komponente slict die übergebenen Daten selbst) | 'server' (data enthält bereits nur die aktuelle Seite, die Gesamtanzahl kommt über totalCount)
  • Neue Inputs/Outputs pageIndex, pageSize, pageSizeOptions, totalCount und pageChange (analog zu MatPaginator/PageEvent, wie bereits in inventory-list/inspection-list verwendet)
  • Pagination funktioniert jetzt auch in Kombination mit Gruppierung (groupLevels):
    • Client-seitig wird zuerst über den vollständigen Datensatz gruppiert, die Seite wird anschließend aus den geflatteten Zeilen (inkl. Gruppen-Header) geschnitten — eine Gruppe kann sich dadurch über zwei Seiten erstrecken
    • Server-seitig gruppiert die Komponente weiterhin nur innerhalb der aktuell geladenen Seite (ein Hinweis macht das in der UI transparent)
v0.52.1 Juli 2026 Features

Features

Superadmin-Kundenliste auf neue Grid-Komponente umgestellt

Die Kundenliste im Superadmin-Bereich (Superadmin > Kunden) nutzte bisher eine unfertige Tabelle ganz ohne Sortieren, Gruppieren oder Spalten-Sichtbarkeit — anders als die reguläre Kundenliste, die in 0.52.0 bereits auf die neue Grid-Komponente umgestellt wurde. Jetzt nutzt auch die Superadmin-Ansicht shared/components/data-grid mit denselben Funktionen: Sortieren per Klick auf den Spaltenkopf, Spalten ein-/ausblenden, Spaltenreihenfolge per Drag & Drop sowie Gruppieren per Drag & Drop in die Gruppierleiste.

Fixes

Ort-Spalte in der Superadmin-Kundenliste zeigte keine Adresse

Die Spalte “Ort” griff auf nicht existierende Felder (plz/ort) zu und blieb dadurch immer leer. Sie greift jetzt korrekt auf postalCode/city zu.

v0.52.0 Juli 2026 Features

Features

Neue Grid-Komponente mit Gruppieren per Drag & Drop

Neue wiederverwendbare Grid-Komponente (shared/components/data-grid) für Listenansichten: Spalten ein-/ausblenden, Spaltenreihenfolge direkt im Tabellenkopf per Drag & Drop ändern, Sortieren durch Klick auf den Spaltenkopf sowie Zeilen-Selektion.

Neu ist das Gruppieren per Drag & Drop: ein Spaltenkopf wird in die Gruppierleiste oberhalb der Tabelle gezogen, die Daten werden daraufhin nach dieser Spalte gruppiert (mehrstufig durch mehrere Spalten möglich). Gruppenzeilen zeigen den Gruppenwert und die Anzahl der enthaltenen Einträge und lassen sich ein-/ausklappen.

Die Kundenliste (Kunden-Verwaltung) wurde als erste Ansicht auf die neue Komponente umgestellt.

v0.51.7 Juli 2026 Features

Features

Fehlerquote pro Projekt im Dashboard

Neues Dashboard-Widget “Fehlerquote pro Projekt”: zeigt je Projektnummer die Gesamtanzahl Einträge, die Anzahl mit Mängeln sowie die daraus berechnete Fehlerquote in Prozent (Einträge mit Mängel ÷ Gesamteinträge des Projekts × 100).

Die zehn Projekte mit der höchsten Fehlerquote werden farblich nach Ampelschema markiert (< 5 % grün, 5–20 % orange, ≥ 20 % rot). Archivierte Einträge und Einträge ohne Projektnummer fließen nicht in die Berechnung ein. Das Widget kann wie alle anderen Dashboard-Kacheln über “Bearbeiten” ein-/ausgeblendet und frei positioniert werden.

v0.51.6 Juli 2026 Features

Features

Automatische Archivierung überfälliger Prüfungen

Inventar-Einträge, deren nächste Prüfung seit vielen Jahren überfällig ist, wurden bisher dauerhaft in den Fälligkeits-Listen und -Statistiken angezeigt — meist, weil das Arbeitsmittel inzwischen von einem anderen Anbieter geprüft wird und in revuwork eigentlich nicht mehr aktiv geführt werden sollte.

Solche Einträge lassen sich jetzt archivieren, statt sie zu löschen:

  • Schwellenwert konfigurierbar: In den Einstellungen → Inventar-Archivierung lässt sich festlegen, ab wie vielen Jahren Überfälligkeit ein Eintrag als Archivierungs-Kandidat gilt (Standard: 5 Jahre).
  • Automatischer Archivmodus: Ein Schalter in denselben Einstellungen aktiviert einen internen Hintergrunddienst, der Kandidaten einmal täglich automatisch archiviert — ganz ohne Server-Setup.
  • Manueller/externer Trigger: Alternativ (oder zusätzlich) lässt sich der neue Endpunkt POST /inventory/archive/run per Cron-Job aufrufen (Anleitung in deploy/setup-archive-cron.md); dieser verarbeitet unabhängig vom Schalter immer alle Mandanten.
  • Archiv-Ansicht: Im Reiter “Inventar” blendet der neue “Archiv”-Button in der Toolbar zwischen der normalen Liste und einer reinen Archiv-Ansicht um. Archivierte Einträge werden in der normalen Liste, im Export und in den Fälligkeits-Statistiken ab sofort nicht mehr mitgezählt.
  • Reversibel: Über “Aus Archiv zurückholen” im Kontextmenü eines archivierten Eintrags lässt sich die Archivierung jederzeit rückgängig machen — es wird nichts gelöscht.
v0.51.5 Juli 2026 Fixes

Fixes

Ort-Spalte in Gebäude, Geschoss und Raum aufgeteilt

Die Spalte “Ort” in der Inventar-Tabelle und im Excel-/PDF-Export kombinierte bisher Gebäude, Geschoss und Raum zu einem Text (z.B. “Halle A · EG · R001”). Das machte ein Filtern oder Sortieren nach Gebäude in Excel praktisch unmöglich, obwohl die Daten bereits als getrennte Felder vorliegen (wie in den Inventar-Filtern links).

Die Spaltenkonfiguration bietet jetzt standardmäßig drei separate, sichtbare Spalten Gebäude, Geschoss und Raum an — sowohl in der Tabellenansicht als auch im davon abgeleiteten Export. Die bisherige kombinierte “Ort”-Spalte bleibt als optionale, standardmäßig ausgeblendete Spalte weiterhin verfügbar.

v0.51.4 Juli 2026 Features

Features

Konfigurierbare Spalten im Inventar-Export

Der Excel- und PDF-Export im Reiter “Inventar” exportierte bisher immer nur fünf fest codierte Spalten (Typ, Art, Ort, Status, Nächste Prüfung) — unabhängig davon, welche Spalten in der Tabellenansicht ein- oder ausgeblendet waren.

Der Export nutzt jetzt dieselbe Spaltenkonfiguration wie die Inventar-Tabelle (Dialog “Spalten konfigurieren”): Welche Spalten sichtbar sind und in welcher Reihenfolge sie stehen, bestimmt jetzt auch den Excel-/PDF-Export.

Außerdem stehen im Spalten-Dialog nun deutlich mehr Parameter zur Auswahl, die bisher weder in der Tabelle noch im Export verfügbar waren: Kostenstelle, Kostenstellen-Nr., Abteilung, Lieferant, Baujahr, Anschaffung, Ausmusterung, Gerätestatus, Benutzerstatus, Gefährdungsklasse, HW-/SW-Revision (inkl. Revisionsdatum) und letzte Änderung. Nicht benötigte Spalten lassen sich wie gewohnt über den Dialog ausblenden.

Die Inventar-Nr., die bereits standardmäßig sichtbar war, ist jetzt ebenfalls Teil des Exports (bisher fehlte sie dort trotz sichtbarer Spalte in der Tabelle).

v0.51.3 Juli 2026 Features

Features

Manueller Anstoß der Trial-Lizenz-Anfrage ans ERP-System

Bisher wurde die Trial-Lizenz-Anfrage ans ErpLicensePlugin nur automatisch bei der Erstfreigabe eines selbst registrierten Mandanten ausgelöst. Im SuperAdmin-Frontend gibt es jetzt im Lizenz-Dialog zusätzlich zum “Von ERP synchronisieren”-Button einen Button “Trial-Lizenz anfordern” (POST /superadmin/tenants/{id}/license/trial-request), mit dem sich die ERP-Anbindung für einen beliebigen Mandanten manuell testen lässt — unabhängig davon, ob bereits eine lokale Lizenz existiert. Im Gegensatz zur automatischen Anfrage bei der Erstfreigabe (best-effort, Fehler werden nur geloggt) wird ein ERP-Fehler bei diesem manuellen Anstoß direkt im Dialog angezeigt.

v0.51.2 Juli 2026 Fixes

Fixes

”Von ERP synchronisieren”-Button im SuperAdmin-Frontend lieferte 403

Die Endpunkte GET /superadmin/tenants/{id}/license/erp und POST /superadmin/tenants/{id}/license/sync-from-erp verlangten bisher zwingend Authentifizierung per X-Api-Key (SuperAdminApiKeyOnly-Policy). Das SuperAdmin-Frontend ruft diese beiden Pull-Endpunkte aber über die normale Browser-Session auf, wodurch der Button “Von ERP synchronisieren” im Lizenz-Dialog immer mit 403 Forbidden fehlschlug.

Beide Endpunkte verwenden jetzt die neue Policy SuperAdminSessionOrApiKey, die sowohl eine eingeloggte SuperAdmin-Session als auch den API-Key akzeptiert. Der reine Push-Endpunkt POST /superadmin/tenants/{id}/license/push (für Aufrufe vom ErpLicensePlugin) bleibt bewusst bei SuperAdminApiKeyOnly.

v0.51.1 Juli 2026 Fixes

Fixes

ERP-Konfiguration in Preview-Deploy-Dokumentation ergänzt

build-deploy-preview-linux.ps1 dokumentiert jetzt zusätzlich ErpLicense__BaseUrl und ErpLicense__ApiKey als Environment=-Zeilen der revuwork-preview.service-Unit (analog zu den bestehenden Smtp__*-Zeilen). Der GitHub-Actions-Workflow deploy-preview.yml setzt keine App-Umgebungsvariablen selbst — diese Werte müssen weiterhin direkt in der systemd-Unit auf dem Server hinterlegt werden.

v0.51.0 Juli 2026 Fixes

Fixes

ERP-Konfiguration im Server-Setup-Skript ergänzt

Install-linux-web-postgres-server.sh setzt jetzt auch ErpLicense__BaseUrl und ErpLicense__ApiKey als Umgebungsvariablen der systemd-Unit (analog zu den bestehenden Smtp__*-Variablen). Die Werte werden über ERP_LICENSE_BASE_URL und ERP_LICENSE_API_KEY beim Aufruf des Skripts gesetzt und sind optional (leerer Default), da die ERP-Anbindung nicht zwingend erforderlich ist.

v0.49.0 Juli 2026 Features

Features

Neues ERP-Lizenzformat mit Paketpreisen und Kontingenten

Das ErpLicensePlugin (VEMAS NextGen) liefert Lizenzpakete jetzt in einem erweiterten, preisbehafteten Format (Paketname, Preis, Feature-Liste mit Einzelpreisen, Mengenkontingente für Inventar-Items, Prüfberichte und Benutzer, Addin- und API-Request-Kontingente – jeweils mit Preis pro Einheit oberhalb des Kontingents). Dieses Format wird jetzt vollständig auf die interne Lizenzverwaltung übernommen:

  • LicenseTemplate und die Lizenz eines Mandanten führen neu: Price, InventoryItemOveragePrice, MaxInspectionReports + InspectionReportOveragePrice, UserOveragePrice, MaxAddins + AddinOveragePrice, MaxApiRequestsPerMonth + ApiRequestOveragePrice.
  • Der ERP-Sync (POST /superadmin/tenants/{id}/license/sync-from-erp) übernimmt Paket, Preise und Kontingente automatisch in die lokale Lizenz. Dieser Endpunkt ist jetzt auch im SuperAdmin-Frontend als “Von ERP synchronisieren”-Button im Lizenz-Dialog verfügbar – damit lässt sich ein im ERP-System vorgenommenes Tarif-Upgrade eines Mandanten mit einem Klick übernehmen.
  • Preise werden ausschließlich per ERP-Sync gepflegt; es gibt bewusst kein manuelles Preis-Eingabeformular in AMV.
  • Überschreitungen von Mengenkontingenten (Inventar-Items, Benutzer, Prüfberichte, API-Requests/Monat) sperren die Nutzung nicht mehr – da jedes Kontingent jetzt einen Overage-Preis hat, wird die Überschreitung stattdessen abgerechnet. Der Verbrauch des Vormonats wird dafür weiterhin je Mandant erfasst (u.a. ApiAccessDailySummary für API-Requests) und steht für die Rechnungsstellung zur Verfügung. Eine grundsätzlich abgelaufene oder fehlende Lizenz sperrt die Nutzung weiterhin.

Trial-Lizenz-Anfrage beim ERP-System bei Mandanten-Registrierung

Bei der Erstfreigabe eines selbst registrierten Mandanten wird jetzt zusätzlich zur lokalen 7-Tage-Testlizenz automatisch eine Trial-Lizenz-Anfrage an das ErpLicensePlugin geschickt (inkl. Firmenname, Adresse und Admin-E-Mail-Adresse). Die Anfrage läuft best-effort: ist das ERP-System nicht erreichbar, wird die lokale Testlizenz trotzdem angelegt, der Fehler wird nur geloggt.

v0.48.0 Juli 2026 Features

Features

Rückfrage vor Löschen zugehöriger Prüfberichte beim Import-Löschen

Beim Löschen eines Import-Eintrags (DELETE /api/v1/import/{id}) werden auch die zugehörigen Inventareinträge entfernt. Waren zu diesen Inventareinträgen noch Prüfberichte vorhanden, wurden sie bisher als verwaiste Datensätze zurückgelassen (kein Fremdschlüssel zwischen InspectionReport und Inventory in der Datenbank).

Jetzt prüft der Endpunkt vorab, ob verknüpfte Prüfberichte existieren:

  • Ohne Bestätigung antwortet er mit 409 Conflict und der Anzahl betroffener Prüfberichte (affectedInspectionReportCount).
  • Erst mit dem neuen Query-Parameter confirmCascadeDelete=true werden die Prüfberichte zusammen mit den Inventareinträgen und dem Import-Log in einer Transaktion gelöscht.

Im Import-Protokoll (Frontend) fragt der Lösch-Dialog entsprechend nach, wenn Prüfberichte betroffen sind, bevor der Löschvorgang bestätigt wird.

v0.47.0 Juli 2026 Fixes

Fixes

ErpLicensePlugin-Endpunkte auf /api/revuwork/… umgestellt

Das ErpLicensePlugin (VEMAS NextGen) hat seine REST-Routen von /api/erplicense/... nach /api/revuwork/... umbenannt. ErpLicenseClient ruft GetLicenseAsync/GetLicenseTermsAsync jetzt unter dem neuen Pfad api/revuwork/distribution/{tenantId} bzw. api/revuwork/distribution/{tenantId}/terms auf.

v0.46.0 Juli 2026 Feature

Feature

News-Anmeldung bei Registrierung und Profilseite für Benachrichtigungen & Theme

  • Die Registrierung enthält jetzt eine Checkbox “Ich möchte per E-Mail über News und Updates informiert werden”, standardmäßig aktiviert. Der Wert wird beim Anlegen des Kontos in den neuen benutzerbezogenen UserSettings gespeichert.
  • Neue Profilseite (/profile, erreichbar über das Benutzermenü) erlaubt es, die News-Benachrichtigung jederzeit ein-/auszuschalten sowie zwischen hellem und dunklem Theme zu wechseln.
  • Die Theme-Präferenz wird nun serverseitig über GET/PUT /api/v1/user/settings gespeichert und beim Login geräteübergreifend geladen (bisher nur pro Browser in localStorage).
v0.45.1 Juli 2026 Fixes

Fixes

ErpLicenseClient deserialisierte case-sensitiv, ErpLicensePlugin liefert camelCase

IErpLicenseClient.GetLicenseAsync/GetLicenseTermsAsync lasen die JSON-Antwort ohne PropertyNameCaseInsensitive. Revuwork.Api selbst liefert (wie die meisten ASP.NET-Core-APIs) camelCase-JSON – dieselbe Konvention ist beim ErpLicensePlugin (eigener Host, VEMAS NextGen) zu erwarten. Ohne case-insensitives Deserialisieren wären alle Felder still auf ihren Default-Wert (0/""/null) gefallen, ohne Fehlermeldung. Betrifft direkt die neue Preiskalkulation im ErpLicensePlugin, die auf korrekt gelesene Lizenzbedingungen angewiesen ist.

v0.45.0 Juli 2026 Features

Features

Lizenz per REST vom ErpLicensePlugin abrufen und dorthin pushen

Die API kann jetzt mit dem ErpLicensePlugin (VEMAS-NextGen-Erweiterung) sprechen:

  • Abrufen (Pull): GET /api/v1/superadmin/tenants/{id}/license/erp ruft die aktuelle Lizenz-Momentaufnahme eines Mandanten direkt vom ErpLicensePlugin ab (X-Api-Key-authentifizierter REST-Aufruf über den neuen IErpLicenseClient).
  • Pushen: POST /api/v1/superadmin/tenants/{id}/license/push nimmt eine Lizenz-Aktualisierung von einem externen System entgegen und legt sie an oder aktualisiert sie (Upsert) – für den Fall, dass das ErpLicensePlugin (oder ein anderes System) die Lizenz proaktiv nach revuwork überträgt, statt dass revuwork sie abholt.
  • Synchronisieren: POST /api/v1/superadmin/tenants/{id}/license/sync-from-erp ruft die aktuell gültigen Lizenzbedingungen (Features/Limits/Gültigkeit) vom neuen .../distribution/{tenantId}/terms-Endpunkt des ErpLicensePlugin ab und übernimmt sie in einem Schritt als lokale Lizenz (Pull + Upsert kombiniert).

Konfiguration über die neue appsettings-Sektion ErpLicense (BaseUrl, ApiKey).

Mandanten-Nutzungsmengen für die Rechnungsstellung

GET /api/v1/superadmin/tenants/{id}/quantities liefert die aktuellen Nutzungsmengen eines einzelnen Mandanten (Inventar-Anzahl, Prüfberichte, Benutzer, Benachrichtigungskonfiguration, Sichtprüfungs-Overrides) – dieselben Werte wie im Massenexport (export/tenants), aber gezielt für einen Mandanten und ohne die anderen Tenant-Datenbanken per Fan-out abzufragen. Basis für externe Abrechnungssysteme (z.B. den PriceCalculator oder das ErpLicensePlugin).

Integrationsendpunkte nur noch per SuperAdmin-API-Key

Die vier neuen Endpunkte (.../license/erp, .../license/push, .../license/sync-from-erp, .../quantities) sind für externe Systeme gedacht, nicht für eingeloggte Menschen. Die neue Policy SuperAdminApiKeyOnly lässt hier zusätzlich zur Rolle SuperAdmin nur den X-Api-Key-Pfad zu (AuthenticationType == "ApiKey") – eine SuperAdmin-Cookie-Session (Browser-Login) reicht dafür nicht mehr aus.

v0.44.0 Juli 2026 Fixes

Fixes

Vemas-NextGen-Plugin (revuworkVFSPlugin) an aktuelle API angepasst

Das Plugin für das ERP-System Vemas NextGen rief die revuwork-API noch mit veralteten, deutschen Feldnamen ab. Da die API heute ausschließlich englische Property-Namen liefert, wurden viele Felder beim Deserialisieren stillschweigend auf ihren Default-Wert (""/0) gesetzt – ohne Fehlermeldung.

  • InventoryDto: alle Feldnamen auf die aktuellen API-Namen umgestellt (InventoryNumber, DeviceType, DeviceCategory, Manufacturer, Building, Floor, Room, Result, LastInspectionDate, NextInspectionDate, ProjectNumber, ProtectionClass, CableLength, SerialNumber) und um die inzwischen neuen Felder ergänzt (CostCenter, CostCenterNumber, Department, Supplier, YearOfManufacture, PurchaseDate, DecommissionDate, Status, UserStatus, AssignedPersonUserId, HazardClass, HardwareRevision(Date), SoftwareRevision(Date)). Damit funktioniert u. a. die Report-Anreicherung in RevuworkInventoryAfterLoad wieder korrekt (bisher liefen alle Items auf ProjectNumber = 0).
  • InspectionReportDto: MandantIdTenantId, ProjektnummerProjectNumber korrigiert.
  • Update-Request beim Verknüpfen/Trennen von NextGen-Assets (RevuworkSyncService): der PUT-Body verwendete durchgehend falsche (deutsche) Feldnamen, wodurch jeder Link-/Unlink-Vorgang an der [Required]-Validierung der API mit 400 Bad Request scheiterte. Der Request enthält jetzt die korrekten Feldnamen und alle Felder des aktuellen Inventar-Eintrags, damit beim Schreiben keine Daten überschrieben werden.
  • Tenant-Filter: Query-Parameter beim Abruf von Inventar/Prüfberichten von MandantId auf TenantId korrigiert (relevant für den SuperAdmin-API-Key-Pfad).
  • Die SQL-Report-Prozedur ReportrevuworkInventar wurde um die neuen amv_*-Spalten ergänzt, damit die zusätzlichen Inventarfelder im NextGen-Report zur Verfügung stehen.

Umbenennung Amv*Revuwork*

Alle Klassen-, Interface- und Dateinamen im Plugin, die noch das alte Amv-Präfix trugen, wurden auf Revuwork umgestellt (RevuworkApiClient, IRevuworkApiClient, RevuworkApiClientOptions, RevuworkAuthException, RevuworkUpdateInventoryRequest, RevuworkSyncService, IRevuworkSyncService, RevuworkWebhookController, RevuworkWebhookReceiver, RevuworkWebhookEnvelope), passend zum sonst im Projekt verwendeten Namensschema. Die SQL-seitigen amv_*-Report-Spaltennamen (bestehender Vertrag mit den NextGen-Reports) bleiben unverändert.

Build-Warnungen behoben

Mit Zugriff auf den privaten Vemas-NuGet-Feed konnte revuworkVFSPlugin erstmals vollständig gebaut und getestet werden (0 Fehler, 15/15 Tests grün). Dabei behoben:

  • Nullability-Warnings (CS8619/CS8601) in den *AfterLoad-Workflows: ExpandoObject implementiert intern IDictionary<string, object?> (nullable Value-Typ) – die Report-Zeilen wurden entsprechend als IDictionary<string, object?> typisiert, statt die Warnung zu unterdrücken.
  • Bekannte Sicherheitslücken in transitiven Paketen von Vemas.NextGEN.Core/Vemas.NextGen.PluginCore per expliziter Versions-Overrides im .csproj geschlossen: AutoMapper → 16.1.1, MailKit/MimeKit → 4.16.0, die komplette Microsoft.Kiota.*-Paketfamilie → 1.22.2 (im Lockstep, um Versionsinkompatibilitäten zu vermeiden).
v0.43.0 Juli 2026 Features

Features

Self-Service-Beitritt zu bestehendem Mandanten

Mitarbeiter können sich jetzt per Einladungslink direkt einem bestehenden, aktiven Mandanten anschließen, statt wie bisher zwangsläufig einen neuen Mandanten anzulegen.

  • Admin-Invite: Mandanten-Admins können unter „Benutzer” über „Einladungslink senden” eine E-Mail-gebundene Einladung mit frei wählbaren Rollen erstellen. Die Einladung ist 7 Tage gültig und einmal verwendbar.
  • Registrierung: Der Registrierungsdialog hat einen neuen dritten Weg „Mitarbeiter (mit Einladung)” neben „Privatperson” und „Unternehmen”. Über den Einladungslink (?type=Mitarbeiter&token=...) wird der Firmenname zur Bestätigung angezeigt.
  • Sicherheit: Der Einladungs-Token wird ausschließlich per E-Mail versendet und nur gehasht gespeichert; die Ziel-E-Mail-Adresse ist fest an das Token gebunden. Ein Token kann nicht erraten oder für einen anderen Mandanten verwendet werden.
  • Offene Einladungen können vom Admin eingesehen und widerrufen werden.

Backend

  • Neue Tabelle TenantInvites (Control-Plane, idempotent per EnsureTableAsync)
  • Neue Endpunkte:
    • POST /api/v1/admin/invites — Einladung erstellen (Admin/SuperAdmin)
    • GET /api/v1/admin/invites — Offene Einladungen des eigenen Mandanten auflisten
    • DELETE /api/v1/admin/invites/{id} — Einladung widerrufen
    • GET /api/v1/auth/invites/{token} — Firmenname zu einem Einladungs-Token abrufen (Prefill Registrierung)
  • POST /api/v1/auth/register unterstützt neuen Type: "Mitarbeiter" mit InviteToken-Feld
v0.42.7 Juli 2026 Fixes

Fixes

Manueller Produktions-Deploy-Workflow

  • Neuer GitHub-Actions-Workflow deploy-production.yml: baut Frontend und Backend und deployt sie auf die Produktion (revuwork.stratworx.de), ausgelöst manuell über “Run workflow” mit Bestätigungsfeld — bewusst kein automatischer Zeitplan, damit ein fehlerhafter master-Stand nicht unbeaufsichtigt live geht.
  • build-deploy-linux.ps1 und build-deploy.ps1 zeigten noch auf den alten Frontend-Ordner src\amv-ui, der beim Umbenennen auf src\revuwork-ui nicht mitgezogen wurde — beide produktiven Deploy-Skripte waren dadurch defekt. Pfade korrigiert.
v0.42.6 Juli 2026 Features

Features

Testabdeckung für fehlende Controller ergänzt

  • Neue Unit-Tests für alle 14 Controller, die bisher keine direkten Controller-Tests hatten: CustomerController, DashboardController, DashboardLayoutController, UserController, NotificationsController, DokumenteController, GefaehrdungsBeurteilungController, PruefvorschriftKatalogController, PruefvorschriftenController, TourController, SettingsController, ImportController, InspectionController, InventoryController.
  • Jeder Endpunkt hat mindestens einen Happy-Path-Test (korrekter ActionResult-Typ + korrekter Service-/Repository-Aufruf).
  • Für alle Endpunkte mit ?tenantId=-Override oder ITenantContext-Zugriff zusätzliche Mandantengrenz-Tests nach dem bestehenden Muster (WebhooksControllerTests, AuditControllerTests): normaler Admin ignoriert fremde tenantId, SuperAdmin-Override funktioniert, fehlender Mandantenkontext liefert 400/403.
  • Damit haben jetzt alle 21 API-Controller direkte Unit-Tests (insgesamt 171 neue Testfälle, Gesamt-Testsuite: 393 Tests, alle grün).
v0.42.5 Juli 2026 Features

Features

Testabdeckung für Mandantengrenze im Webhook-Endpunkt ergänzt

  • Neue Unit-Tests für WebhooksController sichern ab, dass ein normaler Admin über den ?tenantId=-Query-Parameter niemals Webhooks eines fremden Mandanten lesen oder löschen kann — sowohl über ResolveMandant (GetAll, Upsert, Test) als auch über die separat implementierte Logik in Delete.
  • Zusätzlich abgesichert: SuperAdmin-Tenant-Override sowie der 400-Fehlerfall für einen Aufrufer ohne Mandantenkontext.
v0.42.4 Juli 2026 Features

Features

Testabdeckung für Mandantengrenze im Audit-Log-Endpunkt ergänzt

  • Neue Unit-Tests für AuditController.GetAuditLog sichern ab, dass ein normaler Admin über den ?tenantId=-Query-Parameter niemals das Audit-Log eines fremden Mandanten abfragen kann — die eigene TenantId aus ITenantContext hat immer Vorrang vor dem Query-Parameter.
  • Zusätzlich abgesichert: SuperAdmin-Tenant-Override (?tenantId=), SuperAdmin-Cross-Tenant-Ansicht ohne Override, sowie die Begrenzung von pageSize auf 200.
v0.42.3 Juli 2026 Features

Features

Testabdeckung für AuditService.Log() ergänzt

  • Neue Unit-Tests prüfen die Hintergrund-Verarbeitung von AuditService.Log(): korrektes Mapping der Eingabeparameter auf AuditLog, Auflösung von API-Key-Aufrufern (apikey:{id}, apikey:superadmin) zu einem lesbaren Anzeigenamen, sowie dass ein fehlgeschlagener DB-Insert den Datei-basierten Audit-Trail nicht mit sich reißt (zwei unabhängige try/catch-Blöcke).
v0.42.2 Juli 2026 Features

Features

Testabdeckung für Mandantentrennung erweitert

  • Neuer Unit-Test für AuditRepository.InsertAsync prüft explizit, dass die Verbindungsauswahl über entry.TenantId erfolgt (statt über den ambienten ITenantContext) — Regressionsschutz für den in v0.42.1 behobenen Bug mit verlorenen AuditLog-Einträgen bei Hintergrund-Inserts.
  • Neue Tests für TenantDatabaseNaming sichern ab, dass Prod- und Preview-Umgebung durch Tenancy:EnvironmentSuffix immer unterschiedliche physische Datenbanknamen erhalten.
  • Neue Tests für TenantProvisioningService prüfen den Status-Übergang InProgress → Failed bei fehlgeschlagener Provisionierung sowie die Invariante, dass ein Mandant erst nach erfolgreicher Migration auf die neue Datenbank umgeschaltet wird.
v0.42.1 Juli 2026 Fixes

Fixes

AuditLog-Einträge gingen bei Hintergrund-Inserts verloren

  • AuditService.Log() schreibt Einträge asynchron über einen fire-and-forget Task.Run(), außerhalb des ursprünglichen Request-Kontexts. AuditRepository.InsertAsync() wählte die Ziel-DB bisher über das ambiente ITenantContext.TenantId — das ist in diesem Hintergrund-Task nicht verlässlich (der HTTP-Request kann zu diesem Zeitpunkt schon abgeschlossen sein) und lieferte dann null, wodurch der Insert auf die Control-Plane-DB umgeleitet wurde. Dort existiert keine rohe AuditLog-Tabelle (nur in den physischen Tenant-Datenbanken angelegt), der Fehler wurde intern geloggt und der Eintrag ging stillschweigend verloren.
  • InsertAsync() nutzt jetzt die bereits vom Aufrufer übergebene entry.TenantId zur expliziten Verbindungsauswahl (analog zu GetPagedAsync()), statt sich auf den Hintergrund-Kontext zu verlassen.
  • Neuer Regressionstest (inventory-api.spec.ts) prüft, dass nach POST /inventory tatsächlich ein inventory.created-Eintrag über GET /audit sichtbar wird.
v0.42.0 Juli 2026 Features

Features

REST-API-Checks nach SQL- und Endpunkt-Änderungen

  • Neue Backend-E2E-Tests (e2e/backend/inventory-api.spec.ts) prüfen die zuletzt geänderten POST/GET-Endpunkte von /api/v1/inventory direkt über die REST-API: Vertragsprüfung (Statuscodes, Response-Felder, Validierungsfehler, Duplikat-Konflikt) sowie ein expliziter Mandantentrennungs-Test — ein zweiter Test-Mandant darf einen fremden Inventar-Eintrag weder per ID noch über die Liste sehen.
  • global-setup.ts legt dafür jetzt zwei getrennte Test-Mandanten mit eigener Tenant-DB an.
  • Neuer CI-Job sql-migrations-idempotency (e2e-backend.yml) spielt alle database/migrations/*.sql-Dateien zweimal hintereinander gegen dieselbe frische Datenbank ein, damit nicht-idempotente Migrationen (fehlendes IF NOT EXISTS o.ä.) schon in der CI auffallen und nicht erst beim Produktions-Deploy.

Fixes

AssignedPersonUserId-Umbenennung lief nie

  • 028_english_rename.sql verglich column_name gegen 'benanntePersonuserid' (gemischte Schreibweise) statt 'benanntepersonuserid'. Da Postgres unquoted Spaltennamen beim Anlegen immer klein schreibt, griff die Bedingung nie — BenanntePersonUserId wurde nie zu AssignedPersonUserId umbenannt. Dadurch schlugen INSERT/UPDATE auf jeder neu angelegten Mandanten-Datenbank mit column "assignedpersonuserid" does not exist fehl (u.a. das manuelle Anlegen von Inventar-Einträgen aus v0.41.2). Der neue sql-migrations-idempotency-Job und die neuen Inventory-API-Tests haben das aufgedeckt.
v0.41.2 Juli 2026 Fixes

Fixes

Manuelles Anlegen von Inventar-Geräten

  • Neuer Endpunkt POST /api/v1/inventory (Rollen Admin, Editor) zum manuellen Anlegen einzelner Inventar-Einträge — bisher lieferte der Server hier ein 405 Method Not Allowed, da nur der Import-Weg (XLS/JSON) unterstützt wurde.
  • Prüft Lizenzlimit (MaxInventoryItems) sowie die Eindeutigkeit der Inventarnummer je Mandant (409 Conflict bei Duplikat).
  • Der „Neu”-Button im Inventar öffnet weiterhin den Formular-Drawer, jetzt aber mit Pflichtfeld für die Inventarnummer; der Speichern-Button ruft für neue Geräte den neuen Endpunkt auf, statt wirkungslos zu bleiben.
v0.41.1 Juli 2026 Fixes

Fixes

Mandanten-Neuanlage schlug fehl (Regression aus v0.40.0)

  • Die in v0.40.0 ergänzte Migration 040_manual_intervention_automation.sql prüfte die Existenz der Control-Plane-Tabelle LicenseTemplate fälschlich mit IF EXISTS(...) AND NOT EXISTS (SELECT ... FROM LicenseTemplate ...) in einem einzigen Ausdruck. Postgres muss beim Planen dieses Ausdrucks beide Seiten des AND auflösen — auch wenn die linke Bedingung false ist — wodurch die Tabellenreferenz auf der frisch provisionierten Mandanten-Datenbank (wo LicenseTemplate nicht existiert) mit einem Fehler abbrach.
  • Dadurch schlug jede Neuanlage eines Mandanten (SuperAdmin-Provisionierung wie Selbstregistrierung) mit 500 Internal Server Error fehl.
  • Die Prüfung ist jetzt korrekt verschachtelt (analog zu den beiden anderen DO-Blocks derselben Migration), sodass die Testlizenz-Seed-Logik auf Mandanten-Datenbanken sauber übersprungen wird, auf der Control-Plane-DB aber weiterhin greift.
v0.41.0 Juli 2026 Features

Features

Pull-Request-Template

  • .github/pull_request_template.md hinzugefügt, um PR-Beschreibungen zu vereinheitlichen.
  • Enthält eine Checkliste für projektspezifische Pflichtpunkte: Changelog-Eintrag, Versions-Update in den Environment-Dateien, Aktualisierung von docs/api-v1.yaml, Mandantentrennung sowie sichere Fehler-Responses.
v0.40.0 Juli 2026 Features

Features

Automatische Mandanten-Freischaltung bei E-Mail-Bestätigung

  • Ein selbst registrierter Mandant wird nicht mehr manuell durch einen SuperAdmin freigeschaltet, sondern automatisch aktiviert, sobald der Admin-User seine E-Mail-Adresse über den Bestätigungslink verifiziert.
  • Schlägt die Provisionierung dabei ausnahmsweise fehl, bleibt der Mandant weiterhin “Pending” und kann wie bisher manuell über die Mandantenverwaltung freigeschaltet werden (Fallback).

Automatische 7-Tage-Testlizenz

  • Bei der automatischen Freischaltung eines neuen Mandanten wird sofort eine 7-Tage-Testlizenz vergeben (PDF-Export, Inspektionen, Import; bis zu 100 Inventar-Items, 5 Benutzer).
  • Die Testlizenz ist in der Mandantenverwaltung im Lizenz-Drawer als solche gekennzeichnet.

Automatischer Retry für Bestätigungsmails

  • Fehlgeschlagene Sendeversuche der Bestätigungsmail werden nun mit Zeitpunkt und Fehlermeldung je Benutzer gespeichert, statt nur im Server-Log zu verschwinden.
  • Ein Hintergrunddienst versucht fehlgeschlagene Sendungen automatisch erneut (alle 10 Minuten, bis zu 5 Versuche).
  • In der Benutzerverwaltung sieht der SuperAdmin je Benutzer den Mailstatus (Anzahl Versuche, letzter Fehler) auf einen Blick.
v0.39.9 Juli 2026 Fixes

Fixes

Zu großer Abstand zwischen Sidebar-Einträgen

  • Die Navigationseinträge in der Sidebar hatten durch zu viel vertikales Padding und Mindesthöhe unnötig viel Abstand zueinander.
  • Padding und Mindesthöhe der Einträge verkleinert, dadurch wirkt die Navigation kompakter.
v0.39.8 Juli 2026 Features

Features

Mandanten-Auswahl aus der Sidebar entfernt

  • Die Mandanten-Combobox (GodMode) steht jetzt ausschließlich in der SuperAdmin-Toolbar zur Verfügung (siehe v0.39.7) und wurde aus der Sidebar entfernt, um die doppelte Anzeige zu vermeiden.
v0.39.7 Juli 2026 Features

Features

Mandanten-Auswahl auch in der SuperAdmin-Toolbar

  • Die Combobox zur Mandanten-Auswahl (GodMode) war bisher nur in der Sidebar verfügbar und verschwand beim Einklappen der Sidebar vollständig.
  • Die Combobox ist jetzt zusätzlich in der SuperAdmin-Toolbar sichtbar, unabhängig vom Sidebar-Zustand.
v0.39.6 Juli 2026 Fixes

Fixes

  • Der Link zur E-Mail-Bestätigung wurde aus App:ApiUrl + /auth/confirm-email gebaut, ohne das /v1-Segment der tatsächlichen Route (/api/v1/auth/confirm-email). Dadurch verwies der Link auf einen nicht existierenden Pfad (z.B. http://localhost:4201/api/auth/confirm-email statt .../api/v1/auth/confirm-email).
  • Betroffen: AuthController.BuildConfirmUrl (Registrierung) und AdminService.ResendConfirmationEmailAsync (“Bestätigung senden”-Button in der Benutzerverwaltung).
  • App:ApiUrl in appsettings.json sowie die Code-Fallbacks korrigiert, jetzt einheitlich mit /v1.
v0.39.5 Juli 2026 Fixes

Fixes

SuperAdmin-Toolbar: nur “Global”-Einträge verschoben, Rest zurück in die Sidebar

Korrektur zu 0.38.0: Es sollten nur die drei “Global”-Einträge (Dashboard, Mandanten, Benutzer) in die neue Top-Toolbar wandern. Die Gruppen “Mandanten” (Admin-Dashboard, Kunden, Inventar, Prüfberichte, Import) und “Einstellungen” (Einstellungen, Sicherheit, Import-Journal, Webhooks, Sichtprüfungs-Vorlagen, Audit-Journal) bleiben für SuperAdmins wie zuvor in der Sidebar.

  • app-superadmin-toolbar zeigt jetzt nur noch die drei “Global”-Einträge als flache Links (kein Dropdown-Menü mehr nötig).
  • Der Mandanten-Umschalter (Tenant-Select) ist zurück in die Sidebar gewandert (Teil der “Mandanten”-Gruppe, wie vor 0.38.0).
v0.39.4 Juli 2026 Fixes

Fixes

Login blieb bei ausbleibender Server-Antwort im Spinner hängen

  • AuthService.login() hatte keinen Timeout: Antwortete der Server auf POST /auth/login gar nicht (z.B. Preview-System, SuperAdmin-Login), drehte sich der Spinner im Login-Button unendlich weiter, ohne dass der Benutzer eine Fehlermeldung sah oder den Vorgang abbrechen konnte. Die Anfrage bricht jetzt nach 20 Sekunden mit einer verständlichen Fehlermeldung ab.
  • LoginComponent.onSubmit() setzte loading bei erfolgreichem Login nie zurück, sondern verließ sich darauf, dass die Navigation zu /dashboard die Komponente zerstört. Schlug die Weiterleitung fehl oder wurde abgebrochen, blieb der Benutzer mit drehendem Spinner auf dem Login-Screen stehen. Navigation wird jetzt ausgewertet (inkl. Fehlerfall) und der Spinner bei Fehlschlag zurückgesetzt.
v0.39.3 Juli 2026 Fixes

Fixes

SMTP-Konfiguration im Server-Setup ergänzt

  • Registrierungs- und andere System-E-Mails wurden nicht versendet, weil Smtp:Host in appsettings.json standardmäßig auf localhost:25 zeigt und auf frisch aufgesetzten Servern kein lokaler Mail-Relay läuft. Fehlschläge beim Senden wurden bisher nur geloggt, ohne dass die Registrierung selbst fehlschlägt.
  • Install-linux-web-postgres-server.sh legt die amv.service-systemd-Unit jetzt mit Smtp__Host, Smtp__Port, Smtp__EnableSsl, Smtp__User, Smtp__Password und Smtp__From als Umgebungsvariablen an (per SMTP_*-Env-Vars beim Setup gesetzt, nie im Repo hardcodiert), analog zum bestehenden ConnectionStrings__Default-Muster.
  • build-deploy-preview-linux.ps1: Beispiel-Unit für revuwork-preview.service um dieselben Smtp__*-Umgebungsvariablen als Dokumentation ergänzt, da der Preview-Dienst manuell auf dem Server eingerichtet wird.
v0.39.2 Juli 2026 Fixes

Fixes

Branding-Texte: “AMV” durch “revuwork” ersetzt

  • Registrierungsseite: Untertitel “Beantragen Sie Zugang zum AMV-Portal” → “Beantragen Sie Zugang zum revuwork-Portal”
  • BrandingService: Default-Firmenname (Fallback, falls kein Mandanten-Branding hinterlegt ist) von AMV auf revuwork geändert
  • Admin-Einstellungen: gleicher Fallback-Firmenname beim Speichern der Branding-Einstellungen angepasst
  • API-Dokumentation (Scalar): Titel “AMV API” → “revuwork API”
v0.39.1 Juli 2026 Fixes

Fixes

Firmenregistrierung schlug immer fehl

  • Auth:AllowPublicRegistration war in allen appsettings.json (lokal und Deploy-Artefakte) auf false gesetzt, wodurch POST /api/v1/auth/register jede Registrierung mit 403 Forbidden ablehnte, bevor überhaupt Daten geprüft wurden. Flag auf true gesetzt, damit die Registrierung wieder funktioniert.
  • Falls die Registrierung künftig wieder deaktiviert wird, liefert der Endpunkt jetzt ProblemDetails mit verständlicher Fehlermeldung statt eines leeren 403-Bodys, damit das Frontend keine generische Fehlermeldung mehr anzeigt.
v0.39.0 Juli 2026 Features

Features

Node.js 24.18.0

  • CI/CD-Workflows (ci.yml, deploy-preview.yml, e2e-backend.yml, e2e-ui.yml) verwenden jetzt Node.js 24.18.0 statt 20 für Build, Tests und Deployment des Angular-Frontends
v0.38.0 Juli 2026 Features

Features

SuperAdmin-Navigation: Sidebar-Einträge in eine Top-Toolbar umgezogen

Die SuperAdmin-spezifischen Sidebar-Einträge (bisher als eigene “Global”/“Mandanten”/“Einstellungen”-Gruppen in der linken Sidebar) sind für die Rolle SuperAdmin in eine neue horizontale Toolbar oberhalb des Inhaltsbereichs umgezogen. Für alle anderen Rollen (Admin, Editor, Viewer) ändert sich nichts — deren Sidebar-Einträge bleiben unverändert.

  • Neue Komponente app-superadmin-toolbar (shared/components/superadmin-toolbar/): zeigt die bisherigen drei Gruppen als Dropdown-Menüs (“Global”, “Mandanten”, “Einstellungen”) mit den jeweiligen Navigationspunkten.
  • Der aktive Menüpunkt wird über die aktuelle Route erkannt und farblich hervorgehoben (Akzentfarbe --color-role-superadmin).
  • Der Mandanten-Umschalter (Tenant-Select) ist aus der Sidebar in die neue Toolbar gewandert und dort immer sichtbar (rechts, unabhängig von der Gruppenauswahl).
  • Die Sidebar selbst (Logo, Hilfe, Theme-Umschalter, Benutzermenü) bleibt für SuperAdmins bestehen, zeigt aber keine eigenen Navigationspunkte mehr.
v0.37.0 Juli 2026 Features

Features

Backfill: Bestandsmandanten auf eigene Datenbank migrieren

Aufbauend auf 0.32.0: Bisher bekamen nur neu freigegebene Mandanten automatisch eine eigene physische Datenbank (TenantProvisioningService). Bestandsmandanten blieben dauerhaft auf der geteilten amv-Datenbank, ohne einen Weg, das nachträglich zu ändern.

  • Neuer Endpoint POST /superadmin/tenants/{id}/migrate-database: kopiert die Bestandsdaten eines Altmandanten in eine neue, eigene Datenbank, verifiziert die Kopie (Zeilenzahl-Abgleich je Tabelle) und schaltet danach den DB-Pointer um.
  • Während der Migration wird der Mandant in einen Wartungsmodus versetzt (Status = "Migrating"): Lesezugriffe bleiben möglich, Schreibzugriffe werden mit 503 abgelehnt, damit die Kopie konsistent bleibt.
  • Die alten Zeilen bleiben nach der Migration zunächst redundant in der geteilten Datenbank liegen. Ein separater, bewusst auszulösender Endpoint POST /superadmin/tenants/{id}/purge-legacy-data entfernt sie erst nach expliziter Bestätigung — kein automatisches Löschen von Produktionsdaten in einem Aufwasch.
  • TenantProvisioningService ist jetzt idempotent und retry-sicher: CREATE DATABASE wird übersprungen, falls die Datenbank aus einem vorherigen, fehlgeschlagenen Versuch bereits existiert; Fehler werden je Mandant nachvollziehbar getrackt (ProvisioningStatus/ProvisioningError).
  • Mandantenverwaltung im SuperAdmin-Bereich: neue Buttons „Auf eigene Datenbank migrieren” und „Altdaten bereinigen” pro Mandant, sichtbar je nach Migrationsstatus (MandantDto liefert dafür jetzt databaseName/dataMigratedAt/legacyDataPurgedAt mit).
  • Neuer Config-Wert Tenancy:EnvironmentSuffix (appsettings.json): Prod und Preview laufen auf derselben Postgres-Instanz und würden ohne Unterscheidung identisch benannte Tenant-Datenbanken anlegen wollen. Neue Tenant-Datenbanken heißen jetzt revuwork_{id} (Prod, ohne Suffix — keine Änderung am Server nötig) bzw. revuwork_{id}_preview (Preview, Suffix in appsettings.Preview.json auf dem Server, nicht im Repo).
  • ITenantDatabaseNaming.ControlPlaneDatabaseName liest den Namen der geteilten Datenbank jetzt direkt aus ConnectionStrings:ControlPlane statt ihn hart zu codieren — Prod (amv, künftig revuwork) und Preview (eigenständige DB revuwork-preview) haben unterschiedliche, unabhängige Control-Plane-Datenbanken. Neue Mandanten (MandantRepository.CreateAsync) bekommen DatabaseName jetzt ebenfalls explizit aus dieser Quelle statt aus dem umgebungsunabhängigen Spalten-Default in 038_tenant_database_name.sql.
  • Runbook für die geplante Umbenennung der Prod-Datenbank amvrevuwork: docs/sql/rename-prod-database-amv-to-revuwork.sql + docs/sql/backfill-tenant-databasename-revuwork.sql (manuell auszuführen, nicht automatisiert — siehe Kommentare in den Dateien für die genaue Reihenfolge inkl. Wartungsfenster).

Fixes

  • SupportRepository/HistoryRepository joinen nicht mehr direkt gegen AspNetUsers/AspNetRoles über die Tenant-Connection (funktioniert nicht mehr, sobald eine Tenant-DB physisch getrennt ist) — Benutzername/Rolle werden jetzt über den neuen IUserNameLookupService gegen die Control-Plane-DB nachgeladen.
  • Der Datenkopiervorgang beim Backfill überspringt LicenseTemplate, MandantLicense, TenantSettings, ApiKeys und ApiAccessDailySummary — diese Tabellen sind seit 0.36.0/0.36.4 bewusst Control-Plane-only (EnsureTableAsync beim App-Start) und existieren in keiner Tenant-Datenbank.
  • Migration 039_tenant_provisioning_tracking.sql und der „Auf eigene Datenbank migrieren”-Button prüften bisher hartcodiert gegen den Prod-DB-Namen amv — auf Preview (geteilte DB revuwork-preview) hätten dadurch bereits migrierte bzw. noch nicht migrierte Mandanten falsch erkannt werden können. Beide prüfen jetzt umgebungsunabhängig (current_database() serverseitig, Tenant-DB-Namensschema revuwork_{id} clientseitig).
  • TenantProvisioningService.EnsureDatabaseAsync (läuft bei jeder Neuanlage eines Mandanten, nicht nur beim Backfill) schrieb nach Tenant.ProvisioningStatus — diese Spalte existierte auf einer frisch gebooteten Control-Plane-DB nicht, da 039_tenant_provisioning_tracking.sql (wie alle database/migrations/*.sql) nie automatisch dagegen ausgeführt wird, sondern nur gegen neu provisionierte Tenant-DBs bzw. manuell per deploy-migrations.ps1. MandantRepository.EnsureTableAsync() legt die Tracking-Spalten jetzt beim App-Start zusätzlich selbst an (analog zu DatabaseName), damit die Mandanten-Neuanlage auch auf einer frischen DB (E2E-Tests, lokale Erstinstallation) funktioniert.

Noch offen (bewusst zurückgestellt): Massen-Rollout des Backfills über alle Bestandsmandanten (aktuell einzeln pro Mandant auszulösen), generelle Trennung von Control-Plane- und Tenant-Migrationsskripten (weiterhin laufen alle Migrationen inkl. nie genutzter Kopien von Tenant/AspNetUsers/ApiKeys in jede Tenant-DB mit).

v0.36.5 Juli 2026 Fixes

Fixes

Control-Plane vs. Tenant-DB: falsche Connection-Factory in mehreren Repositories (#3)

Mehrere Repositories griffen auf die falsche physische Datenbank zu — ein Bug, der bislang folgenlos blieb, weil bisher nur ein Mandant mit produktiven Daten existiert und dessen Tenant-DB noch identisch mit der Control-Plane-DB ist. Sobald ein Mandant über die automatische Provisionierung eine eigene physische Datenbank erhält, hätte dies zu falsch abgelegten bzw. unauffindbaren Daten geführt.

  • TenantSettingsRepository: CRUD-Methoden (GetAsync, SetAsync, GetAllAsync) nutzten die Tenant-Verbindung, obwohl TenantSettings nur in der Control-Plane-DB existiert — jetzt konsistent auf Control-Plane-Verbindung umgestellt.
  • ApiKeyRepository: bleibt bewusst auf der Control-Plane-DB (ApiKeyMiddleware muss einen Schlüssel per Hash auflösen können, bevor der Mandant überhaupt bekannt ist — eine Tenant-DB-Trennung würde diese Auflösung unmöglich machen). Tabelle wird nicht mehr über database/migrations/ angelegt (würde sonst als leere Schattenkopie in jede neue Tenant-DB repliziert), sondern per EnsureTableAsync() beim App-Start.
  • TourRepository und UserPreferenceRepository: bleiben bewusst auf der Control-Plane-DB (reine UI-Präferenzen/Fortschrittsdaten, über die global eindeutige Benutzer-ID bereits korrekt isoliert). Tabellen ebenfalls per EnsureTableAsync() statt über replizierte Migrationsdateien angelegt.
  • CustomerRepository: geprüft — nutzt bereits durchgängig die Tenant-Verbindung, kein Änderungsbedarf.
  • Cross-Datenbank-Fremdschlüssel auf Tenant(Id) entfernt (AuditLog, Customer, user_dashboard_layouts, support_tickets, VisualCheckTemplate, NotificationConfig, Webhook): eine FK-Referenz über physisch getrennte Datenbanken hinweg ist in PostgreSQL nicht möglich und hätte bei getrennten Tenant-DBs nur gegen eine leere lokale Schattenkopie von Tenant validiert — Schreibzugriffe wären mit einer FK-Verletzung fehlgeschlagen. Die Zugehörigkeit wird weiterhin anwendungsseitig über ITenantContext sichergestellt. Die letzten vier Tabellen waren im Issue nicht explizit genannt, zeigten beim Nachstellen einer frischen Tenant-DB-Provisionierung (database/migrations/*.sql zweimal gegen eine Scratch-Datenbank ausgeführt) aber dasselbe Muster.

Verifiziert durch tatsächliches Ausführen aller 39 database/migrations/*.sql-Dateien gegen zwei Scratch-Datenbanken (Control-Plane- und frisches-Tenant-Szenario, je zweimal für Idempotenz) sowie dotnet test (183/183 grün).

Keine API-Endpunkt-Änderungen.

v0.36.4 Juli 2026 Fixes

Fixes

Backend-E2E-Test scheiterte an mehrdeutigem Locator

tenant-dashboard.spec.ts prüfte page.getByText(TEST_TENANT_ADMIN_NAME) — der Name steht aber doppelt auf der Seite (Header-Badge und Sidebar), Playwright verweigert im Strict Mode die Auswertung bei mehreren Treffern. Alle vorherigen Backend-Fixes (Tenant-Tabelle, EmailConfirmed, Migrations-Reihenfolge) haben tatsächlich gegriffen — die App bootstrapped, der Mandant wird angelegt, Login und Dashboard-Rendering funktionieren. .first() ergänzt, um den ersten Treffer zu prüfen.

v0.36.3 Juli 2026 Fixes

Fixes

Tenant-Provisionierung schlug auf einer wirklich frischen Datenbank fehl

Beim Anlegen eines neuen Mandanten (TenantProvisioningService.ProvisionAsync) werden alle database/migrations/*.sql-Dateien nacheinander gegen die neue, dedizierte Tenant-Datenbank ausgeführt. Das lief bisher nie gegen eine wirklich leere Datenbank durch (bestehende Umgebungen hatten die betroffenen Tabellen/Spalten schon aus älteren, kombinierten Deployments) — durch den neuen Backend-E2E-Test kam das jetzt erstmals zum Vorschein. Reproduziert und verifiziert mit einer lokalen Postgres-Instanz, alle 38 Migrationen laufen jetzt sauber und idempotent gegen eine frische Datenbank durch.

  • 028_english_rename.sql: Index-Neuanlage auf Inventory (TenantId, InventoryNumber) stand vor der Umbenennung MandantId → TenantId in derselben Datei — auf einer frischen DB existierte TenantId an der Stelle noch nicht. Statement hinter die Umbenennung verschoben.
  • 029_license_external_integration.sql / 030_license_addins.sql: mehrere ALTER TABLE-Anweisungen auf TenantSettings/LicenseTemplate/MandantLicense (Control-Plane-Tabellen) waren nicht dagegen abgesichert, dass diese Tabellen in einer frisch provisionierten Tenant-Datenbank gar nicht existieren. Alle betroffenen Statements jetzt mit IF EXISTS (... information_schema.tables ...)-Guards versehen, analog zum bereits bestehenden Muster in derselben Datei.
v0.36.2 Juli 2026 Fixes

Fixes

Automatisch angelegter Bootstrap-SuperAdmin konnte sich nie einloggen

Beim ersten Start auf einer leeren Datenbank legt Program.cs automatisch einen SuperAdmin (admin@amv.local) an — ohne EmailConfirmed zu setzen. Da AuthController.Login unbestätigte E-Mail-Adressen blockt, konnte sich dieser Account nie einloggen. Betraf bisher nur frische Umgebungen (siehe 0.36.0), da bestehende Installationen ihren SuperAdmin-Zugang längst anders eingerichtet haben.

  • EmailConfirmed = true beim Bootstrap-Admin gesetzt, analog zu den bereits behobenen Fällen in MandantService/AdminService
v0.36.1 Juli 2026 Fixes

Fixes

Seed-Script des Backend-E2E-Tests rief falsche URLs auf

e2e/backend/global-setup.ts nutzte request.newContext({ baseURL: 'http://localhost:5000/api/v1' }) zusammen mit Pfaden wie /auth/login (führender Slash). Laut URL-Standard ersetzt ein Pfad mit führendem Slash den kompletten Pfad der Basis-URL, statt ihn zu ergänzen — die Requests gingen dadurch an http://localhost:5000/auth/login statt .../api/v1/auth/login und schlugen mit 404 fehl.

  • API_BASE_URL endet jetzt mit einem trailing slash
  • Pfade in global-setup.ts ohne führenden Slash (auth/login, superadmin/tenants)

Reiner Test-Infrastruktur-Fix, keine Auswirkung auf Produktionscode.

v0.36.0 Juli 2026 Fixes

Fixes

App-Start scheiterte auf einer wirklich frischen Datenbank

Der neue Backend-E2E-Test-Workflow (0.35.0) deckte einen bestehenden Bootstrap-Bug auf: TenantSettingsRepository.EnsureTableAsync() und LicenseRepository.EnsureTablesAsync() legen Tabellen mit Fremdschlüssel auf Tenant(Id) an — aber nirgendwo im Code oder in database/migrations/ wurde die Tenant-Tabelle selbst erzeugt. Auf bestehenden Servern (Dev/Preview/Prod) fiel das nie auf, da die Tabelle dort bereits vorhanden ist; eine wirklich leere, neue Postgres-Instanz konnte die API aber nie hochfahren.

  • MandantRepository bekommt ein neues EnsureTableAsync() (CREATE TABLE IF NOT EXISTS Tenant (...)), analog zu den bereits bestehenden EnsureTableAsync/EnsureTablesAsync-Methoden der anderen Control-Plane-Repositories
  • Wird in Program.cs vor TenantSettingsRepository/LicenseRepository aufgerufen
  • Da IF NOT EXISTS: auf bestehenden Umgebungen ein No-Op, behebt aber den Bootstrap dauerhaft für jede neue/frische Umgebung
v0.35.1 Juli 2026 Fixes

Fixes

Backend-E2E-Tests brauchen kein Docker mehr

Die in 0.35.0 eingeführten Backend-E2E-Tests setzten eine per docker-compose.e2e.yml gestartete Postgres-Instanz voraus — im Team wird lokal aber ausschließlich mit direkt installiertem Postgres gearbeitet, nicht mit Docker.

  • docker-compose.e2e.yml entfernt
  • npm run e2e:db:reset legt stattdessen per psql eine eigene Datenbank revuwork_e2e auf der bestehenden lokalen Postgres-Instanz an (Drop + Create, idempotent)
  • playwright.backend.config.ts liest Host/Port/User/Passwort für diese Verbindung aus den Umgebungsvariablen E2E_DB_HOST / E2E_DB_PORT / E2E_DB_USER / E2E_DB_PASSWORD (Default: localhost:5432, postgres/postgres) — überschreibbar, falls die lokale Instanz andere Zugangsdaten nutzt
  • CI (e2e-backend.yml) ist unverändert, da dort bereits ein GitHub-Actions-Service-Container statt Docker Compose verwendet wurde
v0.35.0 Juli 2026 Features

Features

Echte Backend-E2E-Tests für die Oberfläche

Zusätzlich zu den gemockten Playwright-Tests aus 0.34.0 gibt es jetzt eine zweite E2E-Testreihe, die gegen die echte API und eine frische, wegwerfbare Postgres-Instanz läuft — inklusive echter Mandanten-Provisionierung.

  • Neues docker-compose.e2e.yml: startet eine tmpfs-basierte Postgres-Instanz für E2E-Läufe (kein persistenter State)
  • Neue playwright.backend.config.ts + Testverzeichnis e2e/backend/: startet API (dotnet run) und Frontend (ng serve) gegen diese Postgres-Instanz
  • e2e/backend/global-setup.ts seedet vor dem Testlauf einen Test-Mandanten über die echte API (Login als bootstrapper SuperAdmin → POST /superadmin/tenants), statt Testdaten per SQL an der Business-Logik vorbei einzuspielen
  • Erster Test tenant-dashboard.spec.ts: loggt sich als frisch angelegter Mandanten-Admin ein und prüft das Dashboard
  • Neue npm-Skripte npm run e2e:backend, npm run e2e:db:up / e2e:db:down
  • Neuer CI-Workflow .github/workflows/e2e-backend.yml mit Postgres-Service-Container

Fixes

Mandanten-Admin konnte sich nach direkter Anlage durch SuperAdmin nie einloggen

MandantService.CreateDirectAsync (der Weg, wie ein SuperAdmin über POST /superadmin/tenants einen Mandanten direkt anlegt) hat beim neuen Admin-User EmailConfirmed nicht gesetzt. Da AuthController.Login unbestätigte E-Mail-Adressen blockt, konnte sich der Admin eines so angelegten Mandanten nie einloggen. Jetzt wird EmailConfirmed = true gesetzt, analog zum bereits bestehenden Verhalten bei admin-angelegten Nutzern in AdminService.

v0.34.0 Juli 2026 Features

Features

E2E-Tests für die Oberfläche (Playwright)

Das Frontend hat jetzt neben den bestehenden Vitest-Komponententests auch echte End-to-End-Tests, die durch den Browser gegen die gerenderte Oberfläche laufen.

  • Neues Testverzeichnis src/revuwork-ui/e2e/ mit playwright.config.ts
  • Playwright startet den Angular-Dev-Server automatisch und mockt Backend-Aufrufe über page.route(...), damit Tests ohne laufendes Backend/DB ausführbar sind
  • Erster Beispieltest e2e/login.spec.ts: Login-Formular mit falschen Zugangsdaten (Fehlermeldung) und erfolgreicher Anmeldung (Weiterleitung zum Dashboard)
  • Neue npm-Skripte npm run e2e / npm run e2e:ui
  • Neuer CI-Workflow .github/workflows/e2e-ui.yml, der die E2E-Tests bei Änderungen am Frontend ausführt
  • Fix: angular.json verwies im serve-Target noch auf den alten Projektnamen amv-ui statt revuwork-ui, wodurch ng serve (und damit auch npm start) nicht mehr startete
v0.32.0 Juli 2026 Features

Features

SuperAdmin-Cross-Tenant-Aggregation per Fan-out (Phase 3 der DSGVO-Datentrennung)

Aufbauend auf 0.31.0: SuperAdmin-Statistiken und der Mandanten-Export aggregierten bisher per einzelner SQL-Query über alle Mandanten hinweg — das funktioniert nicht mehr, sobald Mandanten (ab Phase 2) eigene physische Datenbanken bekommen.

  • Neuer ITenantFanOutService: führt eine Abfrage parallel gegen die Datenbank jedes aktiven Mandanten aus (Task.WhenAll) und liefert die Ergebnisse als Dictionary, keyed by Mandant-ID.
  • InventoryRepository.GetGlobalStatsAsync()/GetCountPerMandantAsync() (SuperAdmin-Dashboard-Kacheln) auf Fan-out umgestellt.
  • MandantExportRepository (GET /superadmin/export/tenants) auf Fan-out umgestellt — außer GetUserCountsAsync(), da Benutzerkonten weiterhin zentral in der Control-Plane-DB liegen.

Fixes

  • MandantExportRepository.GetVisualCheckOverrideCountsAsync() filterte auf Source = 'Tenant', der tatsächliche Wert ist aber 'Mandant' — der Zähler für mandantenspezifische Prüfschritt-Overrides im Export lieferte dadurch seit jeher immer 0.

Noch offen (bewusst zurückgestellt): Fan-out-Schreiben für globale Prüfschritt-Vorlagen (VisualCheckTemplateRepository.ReplaceGlobalAsync), Aufräumen der Cross-Tenant-Ansichten ohne Mandantenauswahl in AuditRepository/CustomerRepository, sowie die physische Migration des Bestandsmandanten (Wartungsfenster).

v0.31.0 Juli 2026 Features

Features

Automatische Mandanten-DB-Provisionierung (Phase 2 der DSGVO-Datentrennung)

Aufbauend auf 0.30.0: Neue Mandanten bekommen ab sofort automatisch eine eigene physische Postgres-Datenbank, sobald sie freigegeben werden.

  • Neuer ITenantProvisioningService: legt bei Approve (und beim direkten SuperAdmin-Create) eine Datenbank amv_tenant_{Id} an und spielt die komplette Migrationshistorie ein. Tenant.DatabaseName wird erst nach erfolgreicher Migration umgestellt — schlägt die Provisionierung fehl, bleibt der Mandant auf der bisherigen DB geroutet und Pending, statt auf eine halb migrierte Datenbank zu zeigen.
  • Provisionierung erfolgt nur bei echter Erstfreigabe (Status: Pending → Active), nicht bei erneutem Freigeben eines bereits aktiven Mandanten.
  • database/migrations/*.sql werden jetzt mit ins Deploy-Artefakt der API übernommen (Amv.Api.csproj), damit die laufende API zur Laufzeit auf die Migrationsskripte zugreifen kann.
  • deploy-migrations.ps1 / deploy-migrations-dev.ps1: ermitteln jetzt automatisch alle existierenden Mandanten-Datenbanken (Control-Plane + jede Tenant-DB) und wenden neue Migrationen auf alle an, statt nur auf eine feste DB.

Manueller Vorschritt (einmalig, außerhalb des Repos): pguser benötigt CREATEDB-Recht auf dem Postgres-Server (ALTER ROLE pguser CREATEDB;), da die API selbst neue Datenbanken anlegt.

v0.30.0 Juli 2026 Features

Features

Fundament für Mandanten-Datentrennung (DSGVO): Control-Plane/Tenant-DB-Architektur

Erster Schritt einer mehrphasigen Umstellung von einer gemeinsamen Datenbank (Zeilenfilterung per TenantId) auf eine eigene Postgres-Datenbank pro Mandant — physische statt logischer Trennung der Mandantendaten. Diese Phase ändert das Laufzeitverhalten nicht: der Bestandsmandant zeigt weiterhin auf dieselbe Datenbank wie zuvor.

  • Neue Spalte Tenant.DatabaseName (Migration 038_tenant_database_name.sql), Default 'amv' für alle bestehenden und neu angelegten Mandanten.
  • IDbConnectionFactory durch zwei spezialisierte Factories ersetzt:
    • IControlPlaneDbConnectionFactory — zentrale DB für Identity/Login, ApiKey, Tenant, LicenseTemplate/MandantLicense, globale Produkt-Tours, globale User-Präferenzen, App-Settings.
    • ITenantDbConnectionFactory — löst die DB des aktuellen Mandanten dynamisch auf (ITenantContext.TenantId, gecacht via ITenantDatabaseResolver); Overload CreateConnection(tenantId) für Pre-Auth-Pfade (z.B. ApiKeyMiddleware) und explizite Cross-Tenant-Zugriffe.
    • Ohne Tenant im Kontext (z.B. SuperAdmin ohne ?tenantId=-Auswahl) fällt ITenantDbConnectionFactory in dieser Phase auf die Control-Plane-Verbindung zurück — identische physische DB, daher keine Verhaltensänderung.
  • Alle ~25 Repositories sowie AmvIdentityDbContext und ApplicationUserClaimsPrincipalFactory auf die passende Factory umgestellt.
  • appsettings*.json: ConnectionStrings:Default ersetzt durch ControlPlane und TenantTemplate.

Folgephasen (noch nicht umgesetzt): automatische DB-Provisionierung neuer Mandanten, Migrations-Pipeline über mehrere Tenant-DBs, SuperAdmin-Cross-Tenant-Aggregation per Fan-out, physische Migration des Bestandsmandanten in einem Wartungsfenster.

v0.25.0 Juli 2026 Fixes

Fixes

Test-Suite: Backend kompilierte nicht mehr

Amv.Api.Tests ließ sich nicht mehr bauen (100 Compile-Fehler in 14 Dateien). Ursache: Die Tests waren nicht mit früheren Refaktorierungen im Hauptprojekt synchron gehalten worden — u.a. die Umbenennung deutscher Property-Namen ins Englische (Raum→Room, Ergebnis→Result, Projektnummer→ProjectNumber, MandantId→TenantId u.v.m.), die Einführung von IAuditService in AdminService/AuthController, die Umstellung von CreateUserRequest/UserAdminDto.Role (string) auf Roles (List<string>), sowie der Umzug der API-Key-Endpunkte vom AdminController in einen eigenen ApiKeyController.

  • Betroffene Test-Dateien an aktuelle Signaturen/Property-Namen angepasst; GefaehrdungsBeurteilungRepositoryTests.cs, InventoryDokumentEntityTests.cs und PruefvorschriftEntityTests.cs in HazardAssessmentTests.cs, InventoryDocumentEntityTests.cs und InspectionRegulationEntityTests.cs umbenannt (Entities heißen inzwischen HazardAssessment, InventoryDocument, InspectionRegulation).
  • Neue ApiKeyControllerTests.cs für die beiden API-Key-Tests, die zuvor fälschlich gegen den AdminController liefen.
  • Zwei echte Verhaltensabweichungen aufgedeckt und in den Tests nachgezogen: AuthController.ConfirmEmail liefert inzwischen einen Redirect auf das Frontend statt eines JSON-Ergebnisses; der Import-Rate-Limiting-Test zielte auf die inzwischen entfernte Route /api/v1/inspection/import/json statt auf /api/v1/import/inspections/json.
  • PdfReportServiceTests fehlte die QuestPDF-Lizenzinitialisierung (QuestPDF.Settings.License = LicenseType.Community), wodurch der Test je nach Ausführungsreihenfolge fehlschlug.

Frontend: veraltete Unit-Test-Erwartungen

  • AuthService-Spec erwartete noch /api/auth/... statt der versionierten Route /api/v1/auth/....
  • ChartColorService-Spec erwartete die alte Fallback-Primärfarbe #0891b2 statt der aktuellen #0369a1.
  • UserBadgeComponent-Spec nutzte noch das alte Feld mandantName statt tenantName und fand dadurch die Mandanten-Pille nicht.

Kein produktiver Code geändert — reine Testkorrekturen. Alle 168 Backend- und 43 Frontend-Unit-Tests sind wieder grün.

Features

Neue Tests für Tenant-Isolation und Lizenz-Endpunkt-Schutz

Coverage-Lücken bei zwei laut CLAUDE.md sicherheitskritischen Regeln geschlossen:

  • InventoryServiceTests.cs: Der zentrale CRUD-Service für Arbeitsmittel hatte bisher keinen Unit-Test. Neu abgedeckt: Mapping von GetPagedAsync/GetByIdAsync, UpdateAsync (inkl. KeyNotFoundException und History-Aufzeichnung), GetFilterOptionsAsync, sowie insbesondere die In-Memory-Tenant-Filterung in GetAssignableUsersAsync/GetInspectorUsersAsync (Admin sieht nur eigene Mandanten-User, SuperAdmin sieht alle, Duplikate über Admin+Editor-Rollen werden dedupliziert).
  • LicenseControllerTests.cs: Test verifiziert per Reflection, dass LicenseController weiterhin [Authorize(Roles = "Admin")] trägt — schützt vor versehentlichem Entfernen/Aufweichen des Rollen-Schutzes im Code. Hinweis: Der externe Zugriffsschutz auf nginx-Ebene (deploy/nginx-revuwork.conf proxied aktuell den gesamten /api/-Pfad ohne Ausschluss für /api/v1/admin/license) ist damit nicht abgedeckt und bleibt eine offene manuelle Aufgabe.
v0.23.2 Juli 2026 Fixes

Fixes

Import-Endpunkt: Fehlerbehandlung und Datenqualität

Ausgelöst durch Auswertung eines Prod-Errorlogs des SharePoint-Import-Scrapers (POST /api/v1/import/json):

  • Lizenz-Limit-Fehler (403) gaben bislang ein rohes {"message": "..."} zurück statt des projektweiten ProblemDetails-Formats (RFC 9457). LicenseExceptionMiddleware liefert jetzt konsistente application/problem+json-Antworten mit title, detail und traceId.
  • Raum ist beim Import kein Pflichtfeld mehr (DB-Spalte, Entity InventoryItem.Room und InventoryItemImportDto.Raum nullable, analog zu Manufacturer/Building/Floor). Bisher führte ein fehlender Raumwert in nur einer Zeile dazu, dass der komplette Datei-Import mit 400 abgelehnt wurde.
  • Datumsfelder (letztePruefung/naechstePruefung): leere oder fehlende Werte erzeugen jetzt eine eindeutige Fehlermeldung (“Datumsfeld ist leer oder fehlt…”) statt der irreführenden Kombination aus "request field is required" und einem kryptischen Parse-Fehler.

Große Importe wurden von nginx blockiert (413)

client_max_body_size war für /api/ nicht gesetzt, sodass nginx’ Default von 1 MB griff. Große Inventarlisten (mehrere tausend Positionen als JSON) erreichten die API nie und scheiterten mit 413. Limit in deploy/nginx-revuwork.conf auf 50 MB angehoben (muss auf dem Prod-Server manuell nachgezogen werden, siehe deploy/nginx-revuwork.conf).

Inventarliste: Paginierung (“Weiter”) funktionierte nicht

Der mat-paginator stand im Template innerhalb des Ladezustand-Blocks (@if (loading()) {...} @else {...}) und wurde bei jedem Seitenwechsel kurz aus dem DOM entfernt und neu erzeugt. Da pageIndex nicht gebunden war, sprang die Paginierung dabei intern immer auf Seite 1 zurück — ein Weiterblättern über Seite 2 hinaus war nicht möglich. pageIndex ist jetzt explizit an das Signal currentPage gebunden. Zusätzlich steht die Seitengröße 100 als Option zur Verfügung.

SuperAdmin-Prüfberichte: Stat-Kacheln zeigten immer 0

InspectionService.getStats() im Frontend hat den tenantId-Query-Parameter nicht mitgeschickt (im Gegensatz zu getFilterOptions() und der Report-Liste). Für SuperAdmins ohne eigenen mandant_id-Claim fiel ITenantContext.TenantId dadurch auf 0 zurück, sodass /inspection/stats immer für einen nicht existierenden Mandanten berechnet wurde (“Gesamt”, “Bestanden”, “Fehler/Mangel”, “Überfällig” = 0). tenantId wird jetzt an getStats() übergeben und die Kacheln aktualisieren sich zudem beim Wechsel des Mandanten in der SuperAdmin-Seitenleiste (ngOnChanges).

Audit-Log: fehlender Benutzername bei API-Key-Aufrufen

Aktionen über einen API-Key (z.B. POST /api/v1/import/json) protokollierten im Audit-Log keinen Benutzernamen — UserEmail blieb leer, da nur wenige Controller (AuthController) diesen Wert überhaupt setzen und die NameIdentifier-Claim bei API-Key-Requests ohnehin nur apikey:{id} enthält, keinen echten Benutzer. AuditService.Log(...) löst UserEmail jetzt zentral auf, wenn sie nicht explizit übergeben wurde:

  • Bei API-Key-Aufrufen wird der Benutzer angezeigt, der den API-Key angelegt hat (ApiKey.CreatedByUserId), z.B. max.mustermann@firma.de (API-Key "SharePoint Import").
  • Bei normalen Logins wird die E-Mail/UserName über UserManager aufgelöst, falls ein Controller nur userId übergeben hat.
  • Neue Repository-Methode IApiKeyRepository.FindByIdAsync (nur für diese interne Anzeige-Auflösung, kein Tenant-Filter).

Neue Migration

  • 037_inventory_room_nullable.sql — macht Inventory.Room nullable (muss per deploy-migrations.ps1 ausgerollt werden).
v0.23.0 Juni 2026 Fixes

Fixes

Import-Endpunkte verschoben

  • POST /api/v1/inspection/import/mxpPOST /api/v1/import/inspections/upload
  • POST /api/v1/inspection/import/jsonPOST /api/v1/import/inspections/json

Beide Endpunkte sind in den ImportController verschoben worden, um eine konsistente Routenstruktur unter /import/ zu gewährleisten.

v0.22.0 Juni 2026 Features

Features

Audit-Journal: Filterfunktion

  • Suchfeld (E-Mail, Detail, IP-Adresse) mit Debounce
  • Filter-Dialog (Aktion, Datum von/bis) analog zur Inventar-Ansicht
  • Aktive Filter werden als entfernbare Chips in der Toolbar angezeigt
  • Backend: neue Query-Parameter search, dateFrom, dateTo am /audit-Endpunkt
v0.21.1 Juni 2026 Fixes

Fixes

Build-Warnungen bereinigt

  • CS0108: InventoryListRequest.Search entfernt — wurde bereits von PagedRequest geerbt
  • CS9113: Ungenutzten IAuditService audit-Parameter aus AdminController-Konstruktor entfernt
  • CS8601: Nullable-Zuweisung in InventoryService.ToDto für Manufacturer, Building und Floor mit ?? string.Empty abgesichert
  • CS8602: Mögliche Nullverweis-Dereferenzierung in InspectionService bei pdfService mit Null-Forgiving-Operator (!) behoben
v0.21.0 Juni 2026 Features

Features

Anpassbares Dashboard

Jeder Benutzer kann sein Dashboard individuell gestalten: Widgets per Drag & Drop im 12-Spalten-Grid anordnen, hinzufügen oder entfernen. Das Layout wird pro Benutzer in der Datenbank gespeichert.

  • 9 verfügbare Widgets: KPI-Karten (Geräte, Mängel, Fälligkeit), Lizenzstatus, Sofortbedarf-Liste, Fälligkeits-Chart, Inventar-nach-Typ-Chart, Dringende Fristen, Zuletzt importiert
  • Neuer Bearbeitungsmodus (✏️ Bearbeiten) mit Widget-Bibliothek, Drag-Handle und Entfernen-Button
  • Speichern und Abbrechen im Edit-Modus
  • Neues API-Endpunkt-Paar GET /dashboard/layout / PUT /dashboard/layout
  • Datenbankmigraton 036_user_dashboard_layouts.sql
v0.20.4 Juni 2026 Fixes

Fixes

Inventory: Nullable Felder

  • Migration 035_inventory_nullable_fields.sql: Manufacturer, Building, Floor erlauben jetzt NULL
  • Entity und DTO entsprechend auf string? umgestellt
v0.20.3 Juni 2026 Features

Features

Kundennummer (CustomerNo)

  • Neues Feld CustomerNo auf der Customer-Entität und im DTO
  • Migration 034_customer_no.sql: Spalte CustomerNo VARCHAR(50) mit Index
  • JSON-Import: customerno wird als dedizierte Kundennummer gespeichert
  • Lookup-Reihenfolge beim Import: erst per CustomerNo, dann per Name; bei Treffer per Name wird CustomerNo nachgepflegt
v0.20.2 Juni 2026 Fixes

Fixes

JSON-Import: Deutsches Datumsformat unterstützt

  • POST /api/v1/import/json-data akzeptiert jetzt Datumsfelder im Format dd.MM.yyyy (z.B. 01.10.2024) zusätzlich zu ISO 8601 (yyyy-MM-dd)
  • Neuer DateOnlyJsonConverter registriert — gilt global für alle DateOnly-Felder in der API
v0.20.1 Juni 2026 Fixes

Fixes

Dashboard-500 für Editor (und Admin) behoben

  • DashboardService.GetStatsAsync: In der “Dringende Fristen”-Query fehlte der Tabellenalias bei TenantId — das JOIN von Inventory i und Customer c führte zu “column reference is ambiguous” in PostgreSQL → 500
  • Fix: WHERE TenantId = @TenantIdWHERE i.TenantId = @TenantId

API-Tokens für alle Mitarbeiter (Editor) verfügbar

  • Neuer ApiKeyController mit [Authorize] auf Klassen-Ebene — Editors sehen und verwalten ausschließlich ihre eigenen Keys (User-ID-Filter im Service)
  • Admins sehen alle Keys ihres Mandanten, SuperAdmins mandantenübergreifend
  • Endpoints aus AdminController entfernt (Route bleibt identisch: /admin/apikeys)
  • Nav-Item “Sicherheit” für Editor wieder aktiviert

Import-Journal: ewiger Spinner behoben

  • ImportLogsComponent lud Daten nur in ngOnChanges — beim direkten Aufruf via Router werden keine Inputs gesetzt, daher wurde load() nie aufgerufen
  • ngOnInit ergänzt, ruft load() beim erstmaligen Rendern auf

Einstellungen-Menüeintrag für Editor entfernt

  • Nav-Item “Einstellungen” war für Editor sichtbar, obwohl der Route-Guard (/admin/settings) bereits nur Admin/SuperAdmin erlaubt
  • Eintrag auf roles: ['Admin'] beschränkt

Prüfberichte für Editor freigegeben

  • InspectionController hatte Controller-weites [Authorize(Roles = "Admin,ApiClient,SuperAdmin")] — Editor wurde blockiert
  • Fix: Controller auf [Authorize] geändert; Import-Endpoints (import/mxp, import/json) und logs behalten eigene Admin-Restriction
  • Betroffene Endpoints für Editor: GET /inspection/reports/paged, GET /inspection/reports/filter-options, GET /inspection/stats, GET /inspection/reports, GET /inspection/reports/{id}

Rate-Limit-Partition auf User-ID umgestellt

  • Rate-Limiter partitioniert jetzt nach User-ID (statt IP-Adresse) für authentifizierte Requests
  • Verhindert, dass Nutzer hinter demselben Proxy (nginx/NAT) das gemeinsame IP-Limit erschöpfen
  • Limit auf 60 Requests/Minute erhöht (Dashboard allein: ~4–5 Calls)
  • Unauthentifizierte Requests bleiben weiterhin IP-basiert limitiert
v0.20.0 Juni 2026 Features

Features

Editor-Rolle: Einstellungen, Sicherheit & Import-Journal

  • Editor-Benutzer sehen jetzt die Navigationseinträge Einstellungen, Sicherheit und Import-Journal
  • Einstellungen: Editor hat vollen Lesezugriff und kann Mandanteneinstellungen bearbeiten
  • Import-Journal (/import/logs): Editor sieht die Import-Logs des eigenen Mandanten (lesend)
  • Sicherheit (/admin/security): Editor sieht und verwaltet ausschließlich eigene API-Keys; Admin sieht alle Keys des Mandanten
  • Ownership-Prüfung beim Deaktivieren: Editor kann nur eigene API-Keys deaktivieren (403 bei fremden Keys)
v0.19.1 Juni 2026 Fixes

Fixes

Farbdesign-Einstellungen werden jetzt korrekt gespeichert und geladen

  • Alle Farb-Tokens (Statusfarben, Rollenfarben) werden nun in der Datenbank persistiert, nicht nur im localStorage
  • Nach einem Seiten-Reload oder auf anderen Geräten/Browsern werden die gespeicherten Farben korrekt wiederhergestellt
  • Beim Laden der Settings-Seite werden die Farbpicker jetzt direkt mit den serverseitig gespeicherten Werten synchronisiert
v0.19.0 Juni 2026 Features

Features

Prüfimport: Projekt löschen

  • Im Aktionsmenü der Prüfberichtsliste kann ein importiertes Projekt (alle Berichte einer Projektnummer) gelöscht werden
  • Die Option erscheint nur, wenn der Filter “Projektnummer” aktiv ist
  • Bestätigungsdialog vor dem unwiderruflichen Löschen
  • Nach dem Löschen wird der Filter zurückgesetzt und die Liste neu geladen
v0.17.0 Juni 2026 Features

Features

UI-Modernisierung — Foundation (Plan 1)

  • Design Tokens: Primärfarbe auf Sky Blue (#0369a1) aktualisiert, neue Tokens --color-primary-hover, --color-primary-subtle, Spacing-Skala (--space-xs bis --space-xl), dunkle Sidebar-Tokens (--color-sidebar-bg: #0f172a)
  • Dark Mode: Vollständige Token-Abdeckung — --color-primary-hover, --color-bg-card, --color-sidebar-text korrigiert
  • Collapsible Sidebar: Sidebar klappt auf Klick zwischen 52px (Icons-only) und 220px (Icons + Labels) zusammen; Zustand wird in localStorage persistiert; Tooltips auf Nav-Items im eingeklappten Zustand; dunkles Theme (#0f172a)
  • Custom Toast Stack: MatSnackBar durch eigene Signal-basierte Komponente ersetzt — volle Breite am unteren Rand, stapelbar, farbiger linker Balken nach Typ (ok/warn/error/info), Fortschrittsbalken bei Auto-close, Dark-Mode-Unterstützung via CSS Custom Properties
  • HelpTooltipComponent: Neue Shared-Komponente <app-help-tooltip text="..."> für Inline-Felderklärungen mit ?-Button und Tooltip
  • WizardStepperComponent: Neue Shared-Komponente <app-wizard-stepper> für horizontale Schritt-Anzeige mit Verbindungslinien und Done/Active-States
  • EditDrawer Readonly-Modus: EditDrawerComponent erhält mode, editRoute und editClicked-Inputs; im Readonly-Modus zeigt der Footer einen „Bearbeiten”-Button statt Speichern/Abbrechen
  • Tour-Styling: Tour-Panel modernisiert — kein farbiger Border mehr, neutrales Card-Design, CSS Custom Properties
  • AppCard-Styling: Status-Indikatoren als border-left: 3px solid statt border-color, Border-Radius und Schatten auf Design-Tokens ausgerichtet
v0.16.0 Juni 2026 Features

Features

Zentrale Mandantenauswahl im SuperAdmin-Bereich

  • Mandanten-Selector wurde aus allen SuperAdmin-Seiten entfernt und zentral in die Sidebar integriert
  • Die Auswahl bleibt beim Navigieren zwischen SuperAdmin-Seiten erhalten
  • Die Auswahl wird im Browser-LocalStorage gespeichert und überlebt einen Seiten-Reload
  • Beim Abmelden wird die gespeicherte Auswahl automatisch geleert
  • Audit-Journal reagiert automatisch auf Änderungen des globalen Mandanten
v0.14.0 Juni 2026 Features

Features

Lizenz – Add-ins

  • Neue Spalte Addins (text[]) auf LicenseTemplate und MandantLicense
  • Lizenz kann nun eine Liste von Add-in-Bezeichnern (z. B. Plugin-IDs) enthalten
  • API: LicenseFeaturesDto enthält neues Feld addins: string[]
  • Migration 030: Spalte Addins in beiden Lizenz-Tabellen (idempotent)
v0.13.0 Juni 2026 Features

Breaking Changes

Umbenennung auf Englisch (API-Felder)

Alle Datenbank-Tabellen und -Spalten, C#-Entitäten, DTOs sowie Angular-Modelle und -Komponenten wurden von deutschen auf englische Bezeichnungen umgestellt. Bestehende Integrationen müssen ihre Feldnamen anpassen.

  • Tabellen umbenannt: mandantTenant, pruefvorschriftenInspectionRegulations, inventory_pruefvorschriftInventoryInspectionRegulation, inventory_dokumenteInventoryDocument, GefaehrdungsBeurteilungHazardAssessment
  • Inventory-Spalten umbenannt (z. B. ArbeitsmitteltypDeviceType, GebaeudeBuilding, ErgebnisResult, u. v. m.)
  • JSON-Antworten liefern nun englische Feldnamen
  • Migration 028 ist idempotent (mehrfach ausführbar)

Features

Drittanbindung (Lizenz-Feature)

  • Neues Lizenz-Feature ExternalIntegration (LicenseFeature-Enum)
  • Entitäten MandantLicense und LicenseTemplate: neues Feld FeatureExternalIntegration
  • DTOs (LicenseFeaturesDto, LicenseTemplateDto, CreateLicenseRequest, CreateTemplateRequest): neues Feld ergänzt
  • LicenseService: Feature-Prüfung, Mapping und Fehlermeldung für Drittanbindung implementiert
  • Migration 029: Spalte FeatureExternalIntegration in LicenseTemplate und MandantLicense

Frontend

  • Angular-Modelle, Services und Komponenten auf englische Feldnamen aktualisiert
  • Import-Center: Serververzeichnis-Scan-Karte entfernt
  • Admin-Sidebar neu strukturiert (Gruppen-Überschriften angepasst)

Migrationen

  • Migration 026: Unique-Constraint-Erstellung idempotent gemacht
  • Migration 028 (neu): Alle Umbenennungen via DO-Blöcke (idempotent)
  • Migration 029 (neu): FeatureExternalIntegration-Spalte in Lizenz-Tabellen
v0.12.0 Juni 2026 Features

Features

Inventar-Detailansicht – Prüfvorschriften

  • Neuer Tab “Prüfvorschriften” in der Inventar-Detailansicht
  • Zuweisung von Prüfvorschriften aus zentralem Katalog per Autocomplete
  • Sortierung per Hoch/Runter-Buttons
  • Aktivieren/Deaktivieren per Checkbox
  • Löschen mit Bestätigung

Inventar-Detailansicht – Dokumente

  • Neuer Tab “Dokumente” in der Inventar-Detailansicht
  • Datei-Upload auf Server
  • Metadaten je Dokument: Beschreibung und Kategorie
  • Listenansicht aller hochgeladenen Dokumente
  • Löschen mit Bestätigung
v0.11.0 Juni 2026 Features

Features

Webhooks & Sicherheit (Superadmin)

  • Webhooks- und Sicherheits-Seite zeigen jetzt eine Mandantenauswahl wenn der Benutzer als SuperAdmin angemeldet ist
  • Inhalte werden erst nach Auswahl eines Mandanten geladen
  • Alle Aktionen (Speichern, Löschen, Testen, API-Key erstellen/deaktivieren) arbeiten mit dem gewählten Mandanten
  • Superadmin-Navigation: Eintrag “Sicherheit” unter Einstellungen hinzugefügt
  • Backend: WebhooksController und AdminController (apikeys) akzeptieren optionalen mandantId Query-Parameter für SuperAdmin-Zugriff
v0.10.0 Juni 2026 Features

Features

AMV API Integration (revuworkVFSPlugin)

  • AmvApiClient — typisierter HTTP-Client gegen AMV REST API mit Polly-8-Retry (3x exponentieller Backoff) und HMAC-Signaturprüfung
  • IAmvApiClient — Interface für Testbarkeit
  • AmvSyncService — Link/Unlink von NextGen-Datensätzen mit AMV-Inventareinträgen via ExternalReference
  • AmvWebhookReceiver — Empfänger für AMV-Webhooks (inspection.report.finalized, inventory.updated) mit HMAC-SHA256-Signaturprüfung
  • Konfiguration via Umgebungsvariablen: AMV_API_BASEURL, AMV_API_KEY, AMV_API_WEBHOOK_SECRET

Changes

AMV API

  • UpdateInventoryRequest um ExternalReference (optional, max. 200 Zeichen) ergänzt
  • InventoryRepository.UpdateAsync persistiert ExternalReference in der Datenbank
v0.9.0 Juni 2026 Features

Features

Prüfberichte-Report

Der Prüfberichte-Report wurde vollständig überarbeitet und bringt die gleichen Features wie der Inventarreport:

  • Server-seitige Filterung & Paginierung: Die Liste lädt Daten paginiert vom Server statt alle Berichte auf einmal
  • Chip-Filter: Aktive Filter werden als Chips in der Toolbar angezeigt und können einzeln entfernt werden. Neue Filter über den „Filter”-Button im Popover hinzufügbar
  • Filtermöglichkeiten: Freitextsuche, Projektnummer, Ergebnis, Prüfer, Standort, Hersteller, Prüfdatum (von/bis), Nächste Prüfung (von/bis), Finalisiert
  • Spalten-Konfigurator: Über den Button „Spalten” können sichtbare Spalten und deren Reihenfolge angepasst werden. Einstellungen werden pro Benutzer gespeichert
  • Standard-Spalten: Gerät / Typ, Standort, Prüfdatum, Nächste Prüfung, Ergebnis, Finalisiert
  • Optionale Spalten: Prüfer, Projektnummer, Inventarnummer, Berichtsnummer, Norm / Standard, Externe Referenz, Hersteller, Gerätekategorie, Importiert am
  • Checkbox-Selektion: Einzelne oder alle Berichte auswählen für selektiven Export
  • Excel-Export: Export aller gefilterten Berichte oder nur der ausgewählten Berichte

Backend

  • Neue DB-Migration 023: Context-Spalte in UserColumnPreference zur Trennung von Inventar- und Prüfberichte-Spalteneinstellungen
  • Neue API-Endpunkte:
    • GET /api/v1/inspection/reports/paged — Paginierte, gefilterte Prüfberichte-Liste
    • GET /api/v1/inspection/reports/filter-options — Dropdown-Werte für alle Filter
    • GET /api/v1/inspection/reports/export/excel — Excel-Export mit Filterunterstützung
  • GET/PUT /api/v1/user/column-preferences um context-Parameter erweitert (inventory / inspection)
v0.8.1 Juni 2026 Features

Features

Inventarliste - Dynamische Spaltenauswahl

  • Inventarliste (Tabellenansicht): Benutzer können über den Button „Spalten” in der Toolbar selbst festlegen, welche Spalten sichtbar sind und in welcher Reihenfolge sie erscheinen. Die Konfiguration wird pro Benutzer serverseitig gespeichert.
  • Neue optionale Spalten verfügbar: Hersteller, Seriennummer, Letzte Prüfung, Schutzklasse, Leitungslänge, Projektnummer, Externe Referenz

Plugin: Neue Reports für Prüfberichte und Wiederholungsprüfungen

  • Neuer Report ReportrevuworkPruefberichte: zeigt alle Prüfberichte aus der AMV API, angereichert via RevuworkPruefberichteAfterLoad-Workflow
  • Neuer Report ReportrevuworkWiederholungspruefungen: zeigt Prüfberichte mit gesetztem Wiederholungstermin (NextInspectionDate), angereichert via RevuworkWiederholungspruefungenAfterLoad-Workflow
  • SQL-Skripte zur Registrierung der Datasources und Workflows (0407)
  • AMV API-Konfiguration (BaseUrl, ApiKey) kommt jetzt aus dem GlobalSettings-Eintrag revuworkVFSconfig statt aus Umgebungsvariablen; SQL-Skript 08_register_globalsettings.sql legt den Eintrag an
  • Neues Formular GLOBALSETTINGS.REVUWORKVFSCONFIG (09_form_globalsettings_revuworkvfsconfig.sql) zur Pflege von BaseUrl und ApiKey direkt in der NextGen-Administration

Backend

  • Neue DB-Tabelle UserColumnPreference (Migration 022) für Speicherung der Spalteneinstellungen pro Benutzer
  • Neuer Controller-Endpunkt PUT/GET /api/v1/users/column-preferences für Speicherung und Abruf der Spalteneinstellungen
  • UserPreferenceService verwaltet die Spalten-Konfiguration pro Benutzer
v0.8.0 Juni 2026 Features

Features

Webhook-Konfiguration

  • Neue Seite /admin/webhooks: Konfigurierbare ausgehende Webhooks für alle Systemereignisse
  • Unterstützte Event-Typen: Inventar angelegt/bearbeitet/gelöscht, Prüfeintrag angelegt/bearbeitet/gelöscht, Prüf-PDF erstellt, Wiederholungsprüfung fällig
  • Beliebig viele Custom HTTP-Header pro Webhook (Key-Value-Paare, Values verschlüsselt gespeichert)
  • Test-Button zum Prüfen der Erreichbarkeit — zeigt HTTP-Statuscode als Rückmeldung
  • Navigation im Admin-Bereich um „Webhooks” ergänzt

Backend

  • Neue DB-Tabellen Webhook und WebhookHeader (Migration 021)
  • Bestehender Notification-Webhook aus NotificationConfig in neue Tabelle migriert
  • Neuer Controller WebhooksController (GET/PUT/DELETE /api/v1/admin/webhooks/{eventType}, POST .../test)
  • WebhookService mit ASP.NET Data Protection für verschlüsselte Header-Values
  • NotificationService liest notification.due-Webhook aus neuer Webhook-Tabelle (unterstützt jetzt beliebig viele Header)
v0.7.2 Juni 2026 Fix

Fehlerbehebungen

Inventar

  • Inventory-API: SQL-Fehler column reference "mandantid" is ambiguous nach Einführung des Customer-Joins behoben — alle WHERE-Bedingungen und ORDER BY mit Tabellen-Alias i. prefixiert
  • Inventory-API: COUNT-Query fehlte JOIN-Alias imissing FROM-clause entry for table "i" behoben
v0.7.0 Juni 2026 Feature

Features

ExternalReference

  • Neue Spalte ExternalReference (VARCHAR 200, nullable) auf den Tabellen Customer, Inventory und InspectionReport
  • Backend: Entitäten, DTOs, Repository-INSERTs und CustomerService aktualisiert
  • Frontend: Modelle customer.model.ts, inventory.model.ts und inspection.model.ts aktualisiert
v0.6.3 Juni 2026 Feature

Features

Kunden

  • Neue Tabelle Customer (mandantenabhängig) mit Name, Straße, PLZ, Ort
  • XLS-Import erkennt Kundenanschrift aus Zeile 3 und legt Kunden automatisch an (find-or-create per MandantId + Name)
  • Inventory.CustomerId FK — Geräte sind einem Kunden zugeordnet
  • CRUD-Verwaltung unter /customers (Admin) und /superadmin/customers
  • Bulk-Zuweisung: Altdaten über Multi-Select in der Inventarliste einem Kunden zuweisen
  • Löschen mit Cascade (nur wenn keine abgeschlossenen Prüfergebnisse)

Import

  • XLS-Import liest jetzt Kundenanschrift aus Zeile 3 (z. B. “Debnar Messtechnik GmbH, …”) und speichert sie im ImportLog
  • ImportResultDto enthält neues Feld Kundenanschrift
  • DB-Migration 017: Spalte Kundenanschrift in Tabelle ImportLog
v0.6.1 Juni 2026 Features

Features

Superadmin Import

  • Neue Seite /superadmin/import: Mandanten-Dropdown + vollständige Import-UI (Datei-Upload & Server-Ordner-Scan) für beliebigen Mandanten
  • Neue Seite /superadmin/import/logs: Globale Import-Log-Übersicht über alle Mandanten mit Filter (Mandant, Datumsbereich)
  • Navigation im Superadmin-Bereich um “Import” und “Import-Logs” ergänzt

Backend

  • ImportController: Alle Endpoints unterstützen nun Authorize(Roles = "Admin,SuperAdmin") mit optionalem ?mandantId Query-Parameter
  • ImportService: Methoden ImportFromStreamAsync, ImportFolderAsync, ScanFoldersAsync, GetConfigAsync und GetLogsAsync erhalten optionalen mandantId-Override für SuperAdmin-Kontext
  • Neues GetSuperAdminLogsAsync mit Mandant-JOIN für globale Log-Ansicht
  • ImportRepository: GetLogsForSuperAdminAsync (LEFT JOIN auf Mandant-Tabelle, optionale Filter), GetLogsByMandantIdAsync (mandantenspezifischer Scan)
  • MandantRepository: neues GetSlugByIdAsync für Pfadberechnung im SuperAdmin-Kontext
  • Neues DTO ImportLogWithMandantDto mit MandantName-Feld

Frontend

  • ImportCenterComponent: neuer optionaler @Input() tenantId — alle API-Calls ergänzen ?mandantId wenn gesetzt
  • ImportLogsComponent: neue Inputs tenantId, showMandantColumn, showFilters, backLink — reaktiv via ngOnChanges
v0.6.0 Juni 2026 Feature

Hilfe & Support-Dashboard

Support-Tickets für alle Benutzer

  • Neuer Sidebar-Eintrag „Hilfe & Support” — sichtbar für alle angemeldeten Rollen, Route /help, visuell durch einen Trennstrich vom Hauptmenü abgesetzt
  • Zwei Ticket-Typen wählbar per Toggle oben im Formular:
    • Fehlermeldung (Bug): Felder Fehlerstelle, Fehlermeldung, Erwartungen
    • Änderungsanforderung (CR): Felder Featurename, Beschreibung
  • Datum wird automatisch serverseitig gesetzt — kein Datumsfeld im Formular
  • Dateianhänge: Drag & Drop, bis zu 3 Dateien pro Nachricht, erlaubte Formate PNG / JPG / GIF / PDF, max. 10 MB je Datei — Validierung client- und serverseitig

Ticket-Liste (rollenbasiert)

  • Viewer / Editor sehen nur eigene Tickets
  • Admin sieht alle Tickets des eigenen Mandanten
  • Filterung nach Status, Typ und Freitext-Suche; Paginierung via PagedResult<T>

Chatverlauf & Status-Workflow

  • Ticket-Detailansicht zeigt alle Nachrichten im Chat-Stil (eigene Nachrichten rechts, andere links)
  • Anhänge erscheinen als Download-Links unter jeder Nachricht
  • Status-Übergänge: OffenInBearbeitungGeloestGeschlossen; zusätzlich Abgelehnt und Zurueckgestellt
  • Ersteller darf ein Ticket nur wieder öffnen (Status Offen setzen); Admin / SuperAdmin dürfen alle Status setzen
  • Antworten sind gesperrt, wenn das Ticket Geschlossen oder Abgelehnt ist

E-Mail-Benachrichtigungen

  • Erstellungs-E-Mail: Bestätigung an den Ersteller + Kopie an support@stratworx-solutions.de mit allen Ticket-Feldern als HTML-Tabelle
  • Antwort-E-Mail: Benachrichtigung an alle Beteiligten (Ersteller + bisherige Antwortgeber + alle SuperAdmins) außer dem Autor der neuen Nachricht

Neue API-Endpunkte (api/v1/support)

MethodePfadBeschreibung
GET/ticketsListe (rollenbasiert gefiltert, paginiert)
GET/tickets/{id}Detail mit Chatverlauf
POST/ticketsTicket + erste Nachricht anlegen
PATCH/tickets/{id}/statusStatus ändern
POST/tickets/{id}/messagesAntwort schreiben
POST/tickets/{id}/messages/{messageId}/attachmentsDatei hochladen
GET/tickets/{id}/messages/{messageId}/attachments/{fileName}Datei herunterladen

Datenbank

  • Neue Migration 009_support.sql mit Tabellen support_tickets und support_ticket_messages
  • Anhang-Metadaten werden als JSONB in support_ticket_messages.attachments gespeichert; Dateien liegen im konfigurierten Upload-Verzeichnis
v0.5.1 Juni 2026 Feature

SuperAdmin Mandanten-Export

Export-Button im SuperAdmin-Dashboard

  • Neuer Button „Export JSON” im SuperAdmin-Dashboard-Header
  • Ein Klick lädt eine JSON-Datei mandanten-export-YYYY-MM-DD.json herunter
  • Enthält alle Mandanten mit Lizenzstatus, Datenmengen und API-Zugriffszahlen
  • Während des Downloads: Spinner im Button, Button deaktiviert

Lizenzdaten pro Mandant

  • Für jeden Mandanten: welche Features lizenziert sind (mxpExport, pdfExport, inspections, import)
  • Limits (maxInventoryItems, maxUsers), Gültigkeitszeitraum, Grace-Days
  • Berechneter Lizenzstatus: Active, Grace (innerhalb Grace-Period) oder Expired
  • Mandanten ohne Lizenzeintrag: license: null

Datenmengen pro Mandant

  • Anzahl Inventar-Artikel, Prüfberichte, Benutzer
  • Benachrichtigungskonfiguration: ob konfiguriert, Anzahl Schwellwerte, Anzahl Empfänger-E-Mails, ob Webhook hinterlegt
  • Anzahl mandantenspezifischer Sichtprüfungs-Vorlagen (Overrides)

Tägliche API-Zugriffszahlen (Migration 015)

  • Neue Tabelle ApiAccessDailySummary — speichert pro Mandant und Tag die Summe der API-Anfragen
  • ApiKeyMiddleware inkrementiert bei jedem authentifizierten API-Key-Request den Tageszähler des Mandanten via UPSERT (race-safe)
  • Export enthält für jeden Mandanten: totalRequests (Gesamtsumme) + dailySummaries (Datum + Anzahl pro Tag)
  • Neue API-Endpunkte:
    • GET /api/v1/superadmin/export/mandanten
v0.5.0 Juni 2026 Feature

Inventarnummer, Qualifikationsprüfung, Templates & Benachrichtigungen

Inventarnummer als Geschäftsschlüssel (Migration 012)

  • Neues Feld Inventarnummer auf Inventory — eindeutiger Geschäftsschlüssel pro Mandant (VARCHAR(100) NOT NULL UNIQUE per MandantId)
  • Bestehende Einträge werden mit CAST(Id AS VARCHAR) migriert
  • XLS-Import liest Inventar-Nr. jetzt als Zeichenkette statt numerische ID
  • Auto-Erstellung: Beim MXP-JSON-Import wird ein neues InventoryItem automatisch angelegt, wenn die Inventarnummer im System nicht bekannt ist — kein manuelles Vorerfassen nötig
  • Import-Center zeigt nach dem Import einen blauen Hinweis mit der Anzahl automatisch angelegter Geräte
  • Inventarliste zeigt neue Spalte „Inventar-Nr.”

Harte Qualifikationsvalidierung

  • Regel: SK I und SK III erfordern zwingend die Qualifikation „Elektrofachkraft” beim Prüfer; SK II erlaubt auch „Unterwiesene Person”
  • FinalizeAsync prüft vor der PDF-Erstellung: (1) Bericht muss einem Inventargerät zugeordnet sein, (2) Qualifikation muss zur Schutzklasse passen
  • Controller gibt bei Verstoß HTTP 422 Unprocessable Entity mit dem Fehlertext aus ProblemDetails.detail zurück
  • Prüfformular zeigt einen roten Warnhinweis und deaktiviert den Finalisieren-Button, solange die Kombination ungültig ist
  • Detailansicht zeigt den 422-Fehlertext direkt im Snackbar

PDF neu generieren

  • Neuer API-Endpunkt POST /api/v1/inspection/reports/{id}/regenerate-pdf (Admin und SuperAdmin)
  • Generiert die PDF eines bereits finalisierten Berichts neu und überschreibt die bestehende Datei — nützlich nach Stammdatenänderungen
  • Gibt HTTP 409 zurück, wenn der Bericht noch nicht finalisiert ist
  • Detailansicht zeigt für Admins einen neuen Button „PDF neu generieren” (nur bei finalisierten Berichten)

Konfigurierbare Sichtprüfungs-Vorlagen (Migration 013)

  • Neue Tabelle VisualCheckTemplate mit 5 globalen DGUV-V3-Standardschritten (Gehäuse, Kabel, Stecker, Beschriftung, Sicherheitseinrichtungen)
  • Merge-Logik: Mandant-Admin kann einzelne Schritte per Order überschreiben; nicht überschriebene Global-Schritte bleiben erhalten; neue Mandant-Orders werden angehängt
  • Manuelles Prüfformular lädt die Vorlage beim Start per API statt aus hartkodierter Konstante — eigene Mandanten-Schritte greifen automatisch
  • Admin-Bereich (neue Seite „Sichtprüfungs-Vorlage”): Globale Schritte können per Klick überschrieben werden, eigene Schritte hinzugefügt, Zurücksetzen auf Global möglich
  • SuperAdmin-Bereich: Globale Standardvorlage direkt bearbeitbar
  • Neue API-Endpunkte:
    • GET /PUT /DELETE /api/v1/admin/visual-check-templates
    • GET /PUT /api/v1/superadmin/visual-check-templates

E-Mail- und Webhook-Benachrichtigungen (Migration 014)

  • Neuer Scheduler-Endpunkt POST /api/v1/notifications/run (API-Key-geschützt) — externer Cron-Job triggert die Benachrichtigungsläufe
  • Fälligkeits-Benachrichtigung: System prüft pro Mandant alle konfigurierten Schwellwerte (z. B. 30 Tage vorher, am Fälligkeitstag, 1 Tag überfällig) und sendet E-Mails
  • Empfänger: Admin-Benutzer des Mandanten (automatisch) + optional hinterlegte Zusatz-E-Mails
  • Duplikat-Guard: Für jede Kombination aus Gerät + Schwellwert wird maximal eine Benachrichtigung pro Tag versendet
  • Ausgehender Webhook: Optional konfigurierbare URL mit verschlüsseltem Authorization-Header (AES via IDataProtectionProvider)
  • Admin-Einstellungen (neue Card „Benachrichtigungen” in den Admin-Einstellungen):
    • Warnstufen als Chips hinzufügen/entfernen (positive = Tage vorher, 0 = Fälligkeitstag, negativ = überfällig)
    • Zusätzliche Empfänger-E-Mails als Chips
    • Webhook-URL und Authorization-Header (Passwort-Feld, leer lassen = bestehenden Wert behalten)
  • Neue API-Endpunkte:
    • GET /PUT /api/v1/admin/notification-config
v0.4.0 Juni 2026 Feature

DGUV V3 Compliance — Normkonforme Elektroprüfungsdokumentation

Datenmodell

  • Inventar: Neue Felder Schutzklasse (SK I/II/III), Leitungslaenge (Meter), Seriennummer — per XLS-Import befüllbar
  • Prüfbericht: Neue Felder InspectorQualification, PruefartNorm (VDE0701/VDE0702), PruefplaketteFaellig, IsFinalized, FinalizedAt, PdfPath
  • Messwerte: Neue Felder MeasurementType, CalculatedLimitValue, MeasuredValue
  • Migration 009_dguv_v3.sql: Alle neuen Spalten; importierte Prüfberichte werden rückwirkend als finalisiert markiert

Grenzwert-Service

  • Automatische Berechnung der VDE 0702 Grenzwerte nach Schutzklasse und Leitungslänge
    • SK I: Schutzleiterwiderstand ≤ 0,3 Ω (≤ 5 m) / +0,1 Ω je 7,5 m bis max. 1,0 Ω; bei Heizelement Isolationswiderstand ≥ 0,3 MΩ statt ≥ 1,0 MΩ
    • SK II: Isolationswiderstand ≥ 2,0 MΩ, kein Schutzleiterwiderstand
    • SK III: Isolationswiderstand ≥ 0,25 MΩ, kein Schutzleiterwiderstand
    • Ableitstrom ≤ 3,5 mA für alle Schutzklassen
  • Neuer API-Endpunkt GET /api/v1/inspection/grenzwerte?schutzklasse=SK_I&leitungslaenge=10

Manuelles Prüfformular

  • Neuer 4-Schritt-Wizard (/inspections/new) mit Angular Material Stepper:
    1. Gerät & Prüfdaten — Schutzklasse, Leitungslänge, Prüfdatum, Prüfer, Qualifikation, Prüfnorm
    2. Sichtprüfung — 5 vordefinierte Prüfpunkte mit Bestanden/Nicht bestanden
    3. Messwerte — Schutzleiterwiderstand, Isolationswiderstand, Ableitstrom mit automatischem Grenzwertvergleich + Funktionsprüfung
    4. Abschluss — Gesamtergebnis, Entwurf speichern oder Bericht abschließen
  • Hinweis bei inkompatiblen Prüfer-Qualifikationen (VDE 0701 erfordert Elektrofachkraft)
  • Dezimalkomma-Direktive: Deutsche Komma-Eingabe wird automatisch zu Dezimalpunkt normalisiert
  • Neue API-Endpunkte:
    • POST /api/v1/inspection/reports — Entwurf anlegen
    • PUT /api/v1/inspection/reports/:id — Entwurf bearbeiten
    • POST /api/v1/inspection/reports/:id/finalize — Bericht abschließen (nur nicht-finalisierte Berichte)

PDF-Export

  • Server-seitige PDF-Erzeugung — normkonformes A4-Prüfprotokoll nach DIN EN 50699
  • PDF wird vor dem Datenbank-Update generiert (atomisch: bei PDF-Fehler bleibt Bericht als Entwurf)
  • Dateispeicherung auf dem Server unter /mnt/amv-pdfs/{mandantId}/{jahr}/{berichtId}.pdf
  • PdfPath wird nie an das Frontend übermittelt — Frontend erhält nur hasPdf: boolean
  • Neuer API-Endpunkt GET /api/v1/inspection/reports/:id/pdf — liefert PDF als Download (nur für finalisierte Berichte)
  • Download-Button in der Prüfbericht-Detailansicht (nur sichtbar wenn isFinalized && hasPdf)
v0.3.2 Juni 2026 Fix

Fehlerbehebungen

  • API-Routen im Frontend korrigiert: doppeltes /api/-Präfix nach Migration auf /api/v1 entfernt (betraf alle Endpoints – Login, Inventar, Admin, Import u.v.m.)
  • Mandantenverwaltung: Route /superadmin/mandanten auf /superadmin/tenants aktualisiert
  • Benutzerverwaltung: Deaktivieren nutzt jetzt POST .../deactivate statt DELETE
  • Benutzer- und API-Key-Listen verarbeiten jetzt das PagedResult-Wrapper-Format des Backends korrekt
  • Fehlermeldungen aus dem Backend (Problem Details) werden nun korrekt angezeigt (.detail statt .message)
v0.3.1 Juni 2026 Neu

Neu

  • SuperAdmin Benutzerliste: Button zum erneuten Senden der Bestätigungs-E-Mail

Verbesserungen

  • Browser-Tab zeigt “revuwork” statt “AmvUi”
  • Favicon auf revuwork-Cube aktualisiert
v0.3.0 Juni 2026 Neu

Neu

  • E-Mail-Verifikation bei Registrierung: Bestätigungslink per E-Mail, Login erst nach Bestätigung möglich
  • Benachrichtigung an register@stratworx-solutions.de bei jeder Neuregistrierung
  • SuperAdmin: Benutzer dauerhaft löschen
  • SuperAdmin Benutzerliste: Badge zeigt ob E-Mail bestätigt ist
  • Bestätigungs-E-Mail mit professioneller HTML-Vorlage (revuwork-Logo, orangener Header, Bestätigungs-Button)

Verbesserungen

  • Login-Screen zeigt aktuelle Versionsnummer
  • Login-Screen: revuwork-Logo, zentrierter Titel, Material Icons fix
  • Registrierung: Fehlermeldung wird beim erneuten Absenden korrekt zurückgesetzt
  • Deploy: appsettings.Production.json wird jetzt aus dem Repo deployed
v0.2.0 Juni 2026 Neu

Neu

  • REST API mit Bearer-Token-Authentifizierung
  • PDF-Export für Prüfprotokolle
  • Inspektionsmodul: Ergebnisse erfassen und signieren

Verbesserungen

  • Dashboard-Performance bei großen Inventaren optimiert
  • Import-Assistent mit Vorschau vor dem Import
v0.1.1 Mai 2026 Neu

Neu

  • Multi-Tenant-Unterstützung: mehrere Mandanten in einer Installation
  • Audit-Trail für alle Datenänderungen
  • JSON-Import-Endpoint

Fehlerbehebungen

  • Datumsformat-Fehler beim XLS-Import behoben
  • Sortierung in der Inventarliste korrigiert
v0.1.1 Mai 2026 Verbesserungen

Version 0.1.1

Was ist neu

  • Mehrere Betriebe in einer Installation — revuwork unterstützt jetzt mehrere unabhängige Organisationen in einem System, ohne dass sich die Daten gegenseitig beeinflussen.

Fehlerbehebungen

  • Datumsangaben wurden beim Excel-Import in bestimmten Fällen falsch erkannt — das ist nun behoben.
  • Die Sortierung in der Inventarliste funktioniert wieder korrekt.
v0.1.0 Mai 2026 Erstveröffentlichung

Initial Release

  • Inventarverwaltung mit Volltextsuche
  • Prüffristen und Fälligkeitsübersicht
  • XLS-Import aus bestehenden Listen
  • Benutzerverwaltung mit Rollensystem