Lots of runs

This commit is contained in:
Christoph Schwörer
2026-08-26 16:37:24 +02:00
parent f349d189c7
commit 844b4e5569
823 changed files with 198980 additions and 125 deletions
@@ -0,0 +1,114 @@
# Analysebericht — V1 Baseline, Iteration 01
## 1. Vorgehen dieser Iteration
Ausgangsbasis: `C:\DEV\MasterArbeit\QuellCode\CentronERP` — 82 Projekte laut `Centron.sln`, ca. 17.300 Quell-/Markup-Dateien (`.cs`, `.xaml`, `.razor`), keine `.sql`-Migrationsdateien (Schema/DDL steckt in Fluent-NHibernate-Mappings bzw. eingebetteten SQL-Skripten in `Centron.BL\Administration\Scripts\`). Es standen weder spezialisierte Agentendateien noch MCP-Server zur Verfügung (Baseline-Bedingung dieses Versuchs); genutzt wurden ausschließlich Read/Glob/Grep/Bash sowie generische Recherche-Subagenten (Claude-Code-interne Explore-Agenten) zur parallelen Erstsichtung, deren Befunde in dieser Sitzung manuell zu den vorliegenden Anforderungsdokumenten verdichtet, quergeprüft und teils korrigiert wurden (siehe Abschnitt 4, Traceability-Konsistenz).
Angesichts des Umfangs (keine Modulbeschränkung laut Auftrag, aber ~85 Top-Level-Module allein in `Centron.BL`) wurde eine **risikobasierte Tiefenpriorisierung** vorgenommen: Domänen mit hoher fachlicher Kritikalität (Fakturierung, Zahlungsverkehr, Rechte-/Authentifizierungssystem, C-Sign/Vertragsabschluss) wurden bis auf Methoden-/Zeilenebene analysiert; breite funktionale Abdeckung (Helpdesk, RMA, Lager, Einkauf, EDI, Web-Kanäle) wurde mit soliden, aber nicht erschöpfenden Belegen abgedeckt; ein großer Teil der Codebasis wurde **nicht** untersucht (siehe Abschnitt 3).
## 2. Analysetiefe je Modul/Bereich
### 2.1 Vollständig/detailliert analysiert (Methoden-/Zeilenebene, mehrere Belege, in StRS/SyRS/SwRS abgebildet)
| Bereich | Repräsentative Klassen | Requirement-Block |
|---|---|---|
| Belegkette (Angebot/Auftrag/Lieferschein/Rechnung) | `ReceiptBL`, `*SpecificLogic`, `AutomaticallyCloseReceiptHelperBL` | Block A |
| C-Sign / WebOffer | `SharedDocumentBL`, `ReceiptBL.AcceptWebReceipt` | Block A |
| Rechnungsfestschreibung, Steuerberechnung | `ReceiptInvoiceBL`, `CalculationUtils` | Block A |
| Helpdesk/Ticketing | `HelpdeskBL`, `HelpdeskCloseBL`, `HelpdeskTimerBL` | Block B |
| RMA | `RmaBL` (2084 Zeilen) | Block B |
| TaskManager (Automatisierung) | `TaskManagementTaskBL`, ActionHandler | Block B |
| Artikelstamm/Rechteschutz | `ArticleBL` | Block C |
| Inventur | `InventoryBL` | Block C |
| Kommissionierung | `PartialCommissionOrderBL`, `OrderCommissionBL` | Block C |
| Bestellvorschlag | `OrderSuggestionListBL` | Block C |
| EDI-Dispatch | `EDIDispatcherBL` | Block C |
| Zahlungen/OnlineBanking | `OnlineBankingAccountTransactionsBL`, `PaymentsBL` | Block D |
| Timer Billing Rechte | `ReceiptWebServiceBL`, `TimerBillingSettingsPageViewModel` | Block D |
| Rechtesystem | `AppRightsBL`, `UserRightsConst`, `UserRightsExt` | Block E |
| Authentifizierung/2FA/Tickets | `AuthenticatorFactory`, `BasicAuthenticator`, `TicketBL`, `TwoFactorAuthBL` | Block E |
| Passwort-Tresor | `PasswordManagementAccessLogBL` | Block E |
| Kundenportal/WebCart | `WebCartShopPage`, `CustomerAuthPage`, `CurrentCartService` | Block F |
| Deployment/CI-CD | `build.yml`, `Dockerfile`, WiX-Setups | Block F |
| Datenmodell (Kern) | `Centron.Entities`/`Centron.DAO` (Sales, CustomerArea, Warehousing, BranchArea — stichprobenartig, ~5 von 75 Domänenordnern gelesen) | quer |
| Web-Service-Schnittstelle | `Centron.Controllers` (Struktur, ~15 von vermutlich 50+ Controllern gelesen), Authorization-Attribute | quer |
### 2.2 Mit reduzierter Tiefe analysiert (Struktur/wenige Dateien gelesen, StRS + leichtere SyRS/SwRS-Abdeckung)
| Bereich | Tiefe | Grund für reduzierte Tiefe |
|---|---|---|
| Externe Produktdaten-APIs (COP, Egis, ITscope, Icecat) | Je 1 Kernklasse gelesen | Vier strukturell ähnliche Klienten; ein Vertreter (ITscope) im Detail, übrige stichprobenartig zur Bestätigung des Patterns |
| Versandintegration (GLS, Shipcloud) | Je 1 Kernklasse gelesen | Analog, geringeres fachliches Risiko als Fakturierung |
| E-Rechnung (ebInterface, ZUGFeRD) | 1 Kernklasse + 1 Controller | Format-Erzeugung/-Import bestätigt, keine Feldvalidierung im Detail geprüft |
| docuFORM (Managed Print Services) | 1 Klient + Konstanten | Randintegration, geringe fachliche Kernrelevanz für ERP-Kernprozesse |
| Accounting (Bankverbindungen) | 1 Datei vollständig | Klein, überschaubar |
| Buying (Distributoren) | 1 Datei vollständig | Sehr dünn/thin, wirkt wie Legacy-Stub |
| Logistics (Lagerstammdaten) | 2 Dateien | Kleiner Bereich |
| TradePool | 2 Kerndateien | B2B-Portal-Funktion, sekundär gegenüber Kernprozessen |
| VoucherManagement | 1 Datei (sehr dünn) | Nur eine Methode vorhanden |
| Storage (Legacy) | Vollständig gelesen, aber **inaktiv** (auskommentiert) | Historischer Beleg für InventoryBL-Ablösung |
| Production | 2 Dateien | Lizenzgeschütztes Zusatzmodul, ohne Rechteprüfung im Code |
| CPra, Time, Mail, Mailings, BusinessPartner, Projects, TicketProjects | Je 1-4 Dateien | Sekundäre Module, keine erkennbare hohe fachliche Kritikalität |
### 2.3 Nicht analysiert (nur über Verzeichnislisting bekannt, keine Datei gelesen)
Aus `Centron.BL` (≈85 Top-Level-Module) wurden folgende **nicht inhaltlich untersucht**: `Administration` (außer Rights/Logins), `Accounts`, `AppointmentRequests`, `ArtificialIntelligence`, `Calendar`, `Chats`, `CheckListArea`, `Customizations`, `Devices`, `DocuBoard`, `DocumentationArea`, `ExpectedEvents`, `ExternalHelpdesk`, `ExternalToolsBL`, `Gateway`, `IndexSearch`, `Integrations`, `ItPlanner`, `Mobile`, `Modules`, `MyCentron`, `MyDay`, `NexusNotifications`, `NexusTicketViews`, `Notifications`, `ObjectExternalReferences`, `Outlook`, `Processes`, `ProductMatrix`, `Reporting`, `ReportEngine`, `RiverDivo`, `SelfCare`, `Services`, `SocialMedia`, `Statistics`, `SystemArea`, `Tags`, `TextModuleArea`, `Tools`, `Transactions`, `Urls`, `VideoPortal`, `WebLinks`, `WebServices` (generisch), `WebSuite`, `WebVersion`.
Ebenfalls nicht untersucht: die überwiegende Mehrheit der `Centron.Entities`/`Centron.DAO`-Domänenordner (nur ~5 von ~75 gelesen), die überwiegende Mehrheit der Web-Service-Controller und -DTOs (`Centron.WebServices.Core\Entities`, hunderte Dateien), die überwiegende Mehrheit der 1066 WPF-`.xaml`-Views (nur Ribbon-Merging und einzelne Rechteprüfungs-Fundstellen im Detail), der Großteil von `docs\reference\` (nur stichprobenartig zusammengefasst, nicht jede Datei einzeln gelesen), sowie sämtliche `tests\`-Inhalte auf Ebene einzelner Testfälle (nur Projektstruktur/-anzahl erhoben).
**Konsequenz:** Diese Iteration deckt einen für eine Erstaufnahme soliden, aber keinen vollständigen Querschnitt der Codebasis ab. Für ca. 55-60 von ~85 BL-Modulen liegt **keine** Anforderung in StRS/SyRS/SwRS vor.
## 3. Bekannte Lücken (Auszug, priorisiert für Folge-Iteration)
1. **Reporting/ReportEngine** — vollständig unanalysiert, vermutlich hohe fachliche Relevanz (Auswertungen für Vertrieb/Finance).
2. **Statistics** — vollständig unanalysiert; `ManagementInfoBL` wurde nur im Security-Survey am Rande als Beispiel für einschränkende Rechte erwähnt, nicht fachlich untersucht.
3. **Reporting-/Statistik-Rechte** und **Mobile**-Modul — keine Aussage möglich.
4. **Integrations**, **Gateway**, **ObjectExternalReferences** — Namen deuten auf weitere externe Schnittstellen hin, die nicht erfasst wurden.
5. **DocuBoard**, **DocumentationArea** — Dokumentenmanagement-Funktionalität außerhalb der bereits erfassten `SharedDocumentBL`/C-Sign-Logik unbekannt.
6. **ArtificialIntelligence** (BL-Modul, zusätzlich zu den in Nexus gefundenen KI-Chat-Features) — nicht untersucht, obwohl KI-Funktionen laut Verzeichnisnamen offenbar mehrfach im System vorkommen (`Centron.BL\ArtificialIntelligence`, `CentronNexus\ServiceBoard\TicketAiSummary`, `AIAssist.razor`).
7. Vollständige Controller-/DTO-Landschaft der Web-Service-Schicht (nur ~15 von vermutlich 50+ Controllern gesichtet).
8. Vollständige WPF-UI-Maskenebene (nur 1 von 1066 `.xaml`-Dateien im Detail betrachtet — die Ribbon-Merging-Logik).
## 4. Konsistenzcheck
Durchgeführt am fertigen Anforderungs-Set (StRS-001…028, SyRS-001…028, SwRS-001…040):
- **Doppelt/mehrfach vergebene IDs:** Keine gefunden. Jede ID (StRS-/SyRS-/SwRS-Präfix + laufende Nummer) kommt in ihrer jeweiligen Datei genau einmal als Anforderungs-Header vor.
- **Anforderungen ohne Beleg:** Keine gefunden. Jede der 96 Anforderungen führt mindestens einen klassifizierten Beleg (PRIMÄR/SEKUNDÄR/KONTEXT).
- **Risikoklassen ohne PRIMÄR-Beleg:** Keine gefunden. Alle als Sicherheit/Abrechnung/Berechtigung klassifizierten Anforderungen (u. a. StRS-003, -004, -015, -016, -018 bis -021; SyRS-003 bis -005, -016 bis -023; SwRS-004, -005, -007, -008, -024, -026, -028, -031, -034) führen mindestens einen PRIMÄR-Beleg; keine dieser Anforderungen musste als vollständige `[HYPOTHESE]` markiert werden (einzelne, engere Detailfragen innerhalb sonst PRIMÄR-belegter Anforderungen wurden dennoch als `[HYPOTHESE]` in Prüfidee/Status vermerkt, siehe Hypothesen.md).
- **Tracelinks auf nicht existierende IDs:** Bei der Erstformulierung wurden **drei Inkonsistenzen** identifiziert und vor Abgabe korrigiert:
1. StRS-005 verwies zunächst nur auf SyRS-001, obwohl die zugehörige Aussage (automatischer Status-Übergang) auch in SyRS-002 behandelt wird → ergänzt.
2. StRS-007 verwies fälschlich zusätzlich auf SyRS-021 (Authentifizierungs-Ticket-Ausstellung), was fachlich nicht zusammenhängt → entfernt.
3. SyRS-010, SyRS-021 und SyRS-027 wiesen unvollständige Vorwärtsreferenzen zu SwRS-017, SwRS-031 bzw. bereits vorhandenen SwRS auf → ergänzt; zugehörige Rückwärtsreferenzen in StRS-020/StRS-022 wurden zur Bidirektionalität ergänzt.
Nach diesen Korrekturen sind alle Tracelinks bidirektional konsistent (jede StRS↔SyRS- und SyRS↔SwRS-Referenz ist in beiden Richtungen auffindbar); eine erneute Stichprobenprüfung von 15 zufällig gewählten IDs nach der Korrektur ergab keine weiteren offenen Verweise.
## 5. Selbstbewertung
**Vollständig analysiert** (im Sinne von: alle vorhandenen Dateien des Bereichs gelesen): Accounting, Buying, VoucherManagement, Logistics, TradePool (Kerndateien), Storage (Legacy, inaktiv), CentronRights.md, `docs\`-Indexstruktur (Dateinamen/Übersicht, nicht jede Datei vollständig).
**Stichprobenhaft analysiert** (repräsentative Auswahl innerhalb eines großen Bereichs): Warehousing (38 Dateien, davon ~6 im Detail), Sales (248 Dateien, davon ~15 im Detail), Centron.Entities/Centron.DAO (~75 Domänenordner, davon 5 im Detail), Centron.WPF.UI (1066 `.xaml`, davon 1 Mechanismus im Detail), Centron.Controllers (~50+ Controller, davon ~15 benannt), Finances (9 Dateien, 3 im Detail), Purchasing (4 Dateien, 2 im Detail).
**Gar nicht analysiert:** ca. 55-60 von 85 BL-Top-Level-Modulen (siehe Abschnitt 3), der überwiegende Teil der Entity-/DTO-Landschaft, der überwiegende Teil der WPF-Maskenebene, alle Testfälle im Detail (nur Projektstruktur).
**Stellen mit dünner Beleglage** (hoher Anteil SEKUNDÄR/KONTEXT bzw. verbleibende `[HYPOTHESE]`-Detailfragen trotz insgesamt PRIMÄR-belegter Kernanforderung):
- Timer-Billing-Rechteprüfung im tatsächlichen Schreibpfad (H-001).
- Serverseitiges Scoping einzelner Kundenportal-Endpunkte (H-002).
- Verhalten des `AuthorizeLicense`-Attributs im Detail (H-003).
- Resilience-/Retry-Verhalten externer Integrationen (H-004, Block G generell — hier ist die Beleglage über alle vier StRS-025..028 hinweg strukturell dünner als in Block A-E, da nur je 1-2 Kernklassen statt vollständiger Aufrufketten gelesen wurden).
- Zwei-Faktor-Authentifizierung: zwei parallele Implementierungen, Verhältnis ungeklärt (H-007).
**Erkenntnisse, die einen Nachschlag in einer Folge-Iteration nahelegen:**
1. **Reporting/Statistics/Integrations/Mobile** vollständig neu erschließen — diese Bereiche fehlen komplett und sind für eine SaaS-Neuimplementierung vermutlich hoch relevant (Reporting typischerweise eine der am stärksten migrationsrelevanten Funktionsgruppen).
2. **Vollständige Controller-/DTO-Landschaft** der Web-Service-Schicht systematisch erfassen (aktuell nur ~30 % der vermuteten Controller benannt) — Grundlage für eine belastbare SyRS-Schnittstellenspezifikation einer Web-/SaaS-Neuimplementierung.
3. **Sicherheitsbefunde vertiefen und Fachexperten vorlegen:** unsalted SHA-1 bei Passwort-Hashing (SwRS-031), `IsAdmin()`-Bypass über Gruppennamen-String, hartkodierte `true`-Rückgaben in mindestens einer `*SpecificLogic`-Klasse (H-008), fehlende strukturierte Audit-Protokollierung für Logins/Rechteänderungen (H-009) — diese vier Punkte sollten vor einer Zielarchitektur-Entscheidung priorisiert von Fachexperten bewertet werden, da sie über reine Anforderungsdokumentation hinaus sicherheitsrelevante Entscheidungen für die Neuimplementierung beeinflussen.
4. **Konsolidierungskandidaten vertiefen:** GLS/Shipcloud (StRS-025/026), OnlineBanking/PaymentsBL (SyRS-016/017), zwei 2FA-Implementierungen (H-007) — je ein Kandidat für Zusammenführung im Zielsystem, aber noch nicht bis zur Entscheidungsreife untersucht.
5. **WPF-Maskenebene vs. Web-Service-Rechte-Konsistenz**: systematische Prüfung, ob jede der 1066 WPF-Masken eine äquivalente serverseitige Rechteprüfung besitzt (Stichprobe H-010 deutet auf mögliche Lücken hin).
## 6. Ergebnisumfang dieser Iteration
- StRS.md: 28 Anforderungen
- SyRS.md: 28 Anforderungen
- SwRS.md: 40 Anforderungen
- Traceability.md: 40 Traceability-Zeilen (StRS↔SyRS↔SwRS) + 2 ergänzende StRS/SyRS-Paare ohne eigene SwRS
- Hypothesen.md: 12 Hypothesen + 1 Prozess-Hinweis
- Glossar.md: 26 Begriffe
@@ -0,0 +1,32 @@
# Glossar
Domänenbegriffe, wie sie in StRS/SyRS/SwRS dieser Iteration verwendet werden. Herkunft: Code, `CentronRights.md`, `docs/`. Deutsche Fachbegriffe dominieren, da die Codebasis überwiegend deutschsprachige Domänenobjekte verwendet (z. B. Tabellen `RechKopf`, `AngKopf`, `AufKopf`, `LiefKopf`).
| Begriff | Definition | Quelle |
|---|---|---|
| **Beleg / Receipt** | Sammelbegriff für alle kaufmännischen Dokumente einer Kette: Angebot (Offer), Auftrag (Order), Lieferschein (DeliveryList), Rechnung (Invoice), Gutschrift (CreditVoucher), Abholliste (PickupList), Vertragsliste (ContractList). Alle Belegarten teilen sich eine gemeinsame Basis-Engine (`ReceiptBL`) und einen gemeinsamen Status (`ReceiptState`), unterscheiden sich aber je Belegart durch eine `*SpecificLogic`-Strategieklasse. | `Centron.Interfaces\Sales.Receipts\ReceiptState.cs`, `Centron.BL\Sales\Receipts\*SpecificLogic.cs` |
| **ReceiptState** | Grobstatus eines Belegs: `Active` (offen), `Completed` (abgeschlossen), `Canceled` (storniert). Nicht zu verwechseln mit `IsFixed` (Festschreibung, nur Rechnungen). | `Centron.Interfaces\Sales.Receipts\ReceiptState.cs` |
| **Festschreibung (IsFixed)** | Unumkehrbare Fixierung einer Rechnung: Nach Setzen des Flags `IsFixed = 1` auf `RechKopf` sind keine Änderungen mehr möglich. Getrennt vom `ReceiptState`. | `Centron.BL\Sales\Receipts\Invoices\ReceiptInvoiceBL.cs` (`FixInvoice`) |
| **C-Sign / WebOffer** | Web-basierter Signatur- und Freigabeprozess, bei dem ein Kunde ein Angebot über einen tokenbasierten Link ohne Login öffnet, signiert (Eingeben/Hochladen/Zeichnen) oder ohne Unterschrift annimmt; die Annahme wandelt das Angebot in einen Auftrag um. | `CentronNexus\Office\SharedDocumentSignPage.razor`, `Centron.BL\Sales\Receipts\ReceiptBL.cs` (`AcceptWebReceipt`) |
| **SharedDocument** | Backend-Entität für einen tokenbasierten, zeitlich befristeten Freigabe-/Signaturvorgang eines Dokuments (z. B. C-Sign-Angebot). Trägt Ablaufdatum, Signaturstatus und Historie. | `Centron.BL\Administration\FileManagement\SharedDocumentBL.cs` |
| **Helpdesk / Ticket** | Zentrale Supportvorgang-Einheit; verwaltet Status (datengetrieben über `HelpdeskState`, nicht als hartkodiertes Enum), Zuständigkeit, Fälligkeit, Zeiterfassung, Checklisten. | `Centron.BL\Sales\Support\HelpdeskBL.cs`, `CentronRights.md` |
| **RMA** | Return Merchandise Authorization; Rücksende-/Reparaturvorgang zu einem Ticket, mit eigenem Artikel-Statusmodell (`RmaArticleState`) und Reparatur-Workflow (`RmaForthAction`). | `Centron.BL\CustomerArea\RmaBL.cs` |
| **UserRightsConst** | Zentrale Konstanten-Klasse mit ca. 751 Rechte-IDs, hierarchisch nach Modul/Bildschirm/Aktion organisiert (z. B. `Sales.Customer.Helpdesk.SHOW_HELPDESK`); daneben ältere flache `RIGHT_XXX`-Konstanten. | `Centron.WebServices.Core\EntitiesWrongPlace\Administration\Rights\UserRightsConst.cs` |
| **Restricting Right (einschränkendes Recht)** | Ein Recht, das ein bereits vergebenes (umfassenderes) Recht auf eine Teilmenge einschränkt, z. B. „nur eigene Filiale“ zusätzlich zu einem generellen Anzeige-Recht. | `CentronRights.md` |
| **Mandator** | Mandant/Firma in einem Mehrmandanten-Betrieb; referenziert über `Branch.MandatorI3D`. | `Centron.Entities\Entities\BranchArea\Branch.cs` |
| **I3D** | Primärschlüssel-Namenskonvention (int-Identity) für praktisch alle Entitäten; historisch aus dem Delphi/InterBase-Erbe des Systems. | `Centron.Entities\BaseEntity.cs` |
| **WebCart** | Web-Shop-Funktion für Kunden von c-entron-Kunden: Login als Web-Account, Anzeige der für den Kunden hinterlegten „Sonderpreise“-Artikel, Warenkorb/Bestellung. | `README.md`, `CentronNexus\WebCart\*` |
| **CustomerPortal** | Übergeordnetes Self-Service-Webportal für Web-Accounts (Kunden), das u. a. WebCart, Ticketansicht, Dokumente und Formulare bündelt. | `CentronNexus\CustomperPortalHomePage.razor` |
| **ServiceBoard** | Interner Web-Arbeitsbereich (Nexus) für Support-/Ticketbearbeitung: Kanban, Scheduler, Dashboard, Kundenansicht 360°. | `CentronNexus\ServiceBoard\*` |
| **Nexus** | Blazor-basierte Web-Anwendung „c-entron Nexus“ (interner Arbeitsbereich + Kundenportal), containerisiert deploybar. | `src\nexus\CentronNexus*`, `README.md` |
| **c-entron.NET** | WPF-Desktop-Client, der Hauptarbeitsoberfläche des ERP für interne Anwender. | `src\centron\Centron.WPF.UI` |
| **Web-Service (c-entron Web-Service)** | Backend-Dienst (Windows Service / ASP.NET Core Host), an den sowohl WPF-Client als auch Nexus über REST/SignalR angebunden sind. | `src\webservice\Centron.Host*` |
| **Timer Billing** | Abrechnungsfunktion für erfasste (Ticket-)Zeiten; erzeugt Rechnungen/Lieferscheine aus Zeiterfassungen, mit einstellbarem Abrechnungsdatum. | `Centron.WPF.UI\Modules\Finances\TimerBilling\*` |
| **EDI** | Electronic Data Interchange; automatisierter Bestell-/Auftragsdatenaustausch mit Distributoren (ALSO, Egis, Komsa, Alltron, ITScope, OpenTrans 2.1). | `Centron.BL\EDI\EDIDispatcherBL.cs` |
| **docuFORM (MPS)** | Externe Integration für „Managed Print Services“: Geräteflottenüberwachung (Zähler, Verbrauchsmaterial) und Druckauftragsverwaltung. | `Centron.Api.docuFORM\*` |
| **ZUGFeRD / ebInterface / XRechnung** | Elektronische Rechnungsformate (Deutschland/Österreich); ZUGFeRD-Import über eigenen Controller, ebInterface-Export als lokale XML-Erzeugung. | `docs\reference\zugferd-field-mapping.md`, `Centron.Api.EbInterface\EbInterfaceLogic.cs` |
| **AppRightsBL** | Zentrale Business-Logic-Klasse zur Rechteprüfung; liest Gruppenrechte aus den (legacy benannten) Tabellen `Sichtrus`/`Sichmemb`, cached pro Benutzer. | `Centron.BL\Administration\Rights\AppRightsBL.cs` |
| **Ticket (Auth)** | Zeitlich befristetes, nach erfolgreicher Anmeldung ausgestelltes Session-Artefakt (nicht zu verwechseln mit Helpdesk-„Ticket“); Grundlage des benutzerdefinierten `TicketAuthenticationHandler`-Schemas. | `Centron.BL\Administration\Logins\TicketBL.cs`, `Centron.Host\AspNetCore\TicketAuthenticationHandler.cs` |
| **Lizenz (License)** | Feature-Gate über GUID (`LicenseGuids.*`), unabhängig vom Rechtesystem; steuert Verfügbarkeit ganzer Module (z. B. Produktionsmanagement, WebCart2). | `docs\reference\security\licensing-system.md` |
| **Distributor / Trade Pool** | Externe Großhändler-/Herstellerkataloge, die per XML-Feed importiert werden; eigenes B2B-Login-Portal für Handelskunden. | `Centron.BL\TradePool\TradePoolBL.cs` |
| **OnlineBanking-Abgleich** | Automatischer Import und Zuordnung von Kontoauszugsbuchungen zu offenen Rechnungen/Gutschriften über FinAPI. | `Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs` |
@@ -0,0 +1,71 @@
# Hypothesen
Sammlung aller mit `[HYPOTHESE]` markierten Aussagen aus StRS/SyRS/SwRS sowie zusätzlicher, im Rahmen der Recherche aufgefallener offener Punkte, die für eine Validierung durch Fachexperten bzw. für eine Folge-Iteration relevant sind. Jeder Eintrag nennt die betroffene Anforderung, die offene Frage und die fehlende Information zur Bestätigung.
---
### H-001 — Durchsetzung der Rechteprüfung im tatsächlichen Schreibpfad für Abrechnungsdaten
**Betrifft:** SyRS-018, SwRS-027 (Timer-Billing-Datumsrechte)
**Aussage:** Es ist unklar, ob die serverseitig berechneten Flags `CanChangeDateInInvoices`/`CanChangeDateInDeliveryLists` auch im eigentlichen Speicherpfad (nicht nur bei der Anzeige-Berechnung in `ReceiptWebServiceBL`) erneut geprüft werden.
**Fehlende Information:** Nachverfolgung des konkreten Save-Aufrufs für Rechnungs-/Lieferschein-Datum bis zur tatsächlichen Persistierung, um zu bestätigen, dass eine Umgehung über einen direkten API-Aufruf (unter Auslassung der UI) nicht möglich ist.
### H-002 — Serverseitiges Scoping pro Kundenportal-Endpunkt
**Betrifft:** SyRS-024 (Isolierung Web-Account-Sitzungen), StRS-022
**Aussage:** Es wird angenommen, dass jeder Kundenportal-Endpunkt die Datenabfrage auf den angemeldeten Web-Account beschränkt.
**Fehlende Information:** Einzelverifikation der Scoping-Logik in den ~15 identifizierten Kundenportal-Controllern/-Komponenten (`ServiceBoard\Customers\*`, `Office\*`, `WebCart\*`); in dieser Iteration wurde nur das Vorhandensein getrennter Login-Pfade, nicht die serverseitige Datenfilterung jedes einzelnen Endpunkts geprüft.
### H-003 — Verhalten des Attributs `AuthorizeLicense` bei fehlender Lizenz
**Betrifft:** SyRS-025, SwRS-036 (WebCart-Lizenzprüfung)
**Aussage:** Es wird angenommen, dass `[AuthorizeLicense(...)]` den Zugriff serverseitig vollständig verweigert (kein Datenleck vor Umleitung).
**Fehlende Information:** Quellcode der Attributimplementierung selbst (nicht nur ihre Verwendung) wurde nicht gelesen; Verhalten bei fehlender Lizenz (Redirect/Fehlerseite/Exception, Zeitpunkt der Prüfung im Blazor-Circuit-Lebenszyklus) ist nicht im Detail bestätigt.
### H-004 — Fehlendes einheitliches Timeout-/Retry-Verhalten bei externen Integrationen
**Betrifft:** SyRS-028, SwRS-040 (docuFORM u. a.)
**Aussage:** Da kein expliziter `HttpClient.Timeout`-Override und keine Resilience-Bibliothek gefunden wurden, wird angenommen, dass die .NET-Standardwerte (100 s Default-Timeout) greifen und kein automatischer Retry bei transienten Fehlern erfolgt.
**Fehlende Information:** Laufzeitverhalten wurde nicht getestet (nur statische Codeanalyse); ein Retry könnte z. B. über eine übergeordnete Aufruferschicht (Scheduler, Hintergrunddienst) realisiert sein, die in dieser Iteration nicht untersucht wurde.
### H-005 — Transaktionsisolation bei Bestellvorschlagsberechnung
**Betrifft:** SyRS-014, SwRS-022 (OrderSuggestionListBL)
**Aussage:** Es ist unklar, unter welcher Transaktionsisolationsstufe die ca. 10 Einzel-SQL-Abfragen ausgeführt werden und ob sie einen konsistenten Datenstand (gleicher Zeitpunkt) garantieren oder bei hoher Nebenläufigkeit inkonsistente Zwischenstände liefern können.
**Fehlende Information:** NHibernate-/`RawSqlAccess`-Konfiguration der Transaktionsisolationsstufe wurde nicht recherchiert.
### H-006 — Bestätigungsmöglichkeit für erkannte Duplikat-Transaktionsimporte
**Betrifft:** SwRS-024 (OnlineBanking-Duplikatserkennung)
**Aussage:** Die Duplikatsprüfung liefert laut Code eine Warnung, keinen Hard-Block; unklar ist, ob der Anwender den Import trotz Warnung bestätigen und damit eine Rechnung doppelt verbuchen kann.
**Fehlende Information:** UI-seitiger Umgang mit der Warnmeldung (WPF-ViewModel-Ebene) wurde nicht zurückverfolgt.
### H-007 — Verhältnis zweier augenscheinlich überlappender 2FA-Implementierungen
**Betrifft:** StRS-020, SwRS-033
**Aussage:** Im Code existieren zwei separate Namespaces für Zwei-Faktor-Authentifizierung: `Centron.BL\Administration\Logins\TwoFactor\TwoFactorAuthBL.cs` und `Centron.BL\TwoFactorAuthenticator\TwoFactorAuthenticationBL.cs`. Unklar ist, ob es sich um (a) eine historische Migration mit totem Altcode, (b) zwei unterschiedliche Anwendungsfälle (z. B. Mitarbeiter- vs. Kunden-2FA) oder (c) eine unbeabsichtigte Duplikation handelt.
**Fehlende Information:** Aufrufer beider Klassen wurden nicht vollständig ermittelt; Klärung durch Fachexperten/Entwicklerteam erforderlich.
### H-008 — Umfang der Rechteprüfung in `*SpecificLogic`-Klassen der Belegverarbeitung
**Betrifft:** StRS-018, SyRS-019 (Rechtesystem, allgemein)
**Aussage:** Bei der Sicherheitsrecherche wurde festgestellt, dass mindestens eine `*SpecificLogic`-Methode (`SupplierOrderSpecificLogic.HasRightToEditReceipt`, Zeile ~685) unbedingt `return true;` liefert, statt ein tatsächliches Recht zu prüfen — im Gegensatz zum sonst konsistent durchgesetzten Muster. Es ist unklar, ob dies eine bewusste Design-Entscheidung (z. B. weil das Recht an anderer Stelle bereits geprüft wurde) oder eine Sicherheitslücke ist.
**Fehlende Information:** Vollständige Durchsicht aller 13 `*SpecificLogic.cs`-Dateien unter `Sales\Receipts\` auf weitere hartkodierte `true`/`false`-Rückgaben; Abgleich mit vorgelagerten Prüfpunkten in `ReceiptBL`.
### H-009 — Fehlende strukturierte Audit-Protokollierung für Login-Ereignisse und Rechteänderungen
**Betrifft:** StRS-018, StRS-019 (Rechtesystem, Authentifizierung)
**Aussage:** Außer den Passwort-Tresor-Zugriffsprotokollen (`PasswordManagementAccessLogBL`) und unstrukturierten NLog-Einträgen wurde keine dedizierte, abfragbare Tabelle für Login-Historie oder Änderungen an Rechtegruppen (`AppRightsBL.AddRightToRightGroup`) gefunden. Angesichts des vorhandenen `DsgvoModule`-Rechte-Namensraums ist unklar, ob dies für Compliance-Zwecke (DSGVO/GoBD) ausreicht.
**Fehlende Information:** Vollständigere Suche nach Audit-/Protokolltabellen außerhalb der in dieser Iteration durchsuchten Muster (`LoginLog`, `AuditLog`, `AuditTrail`, `Protokoll`); Rückfrage beim Entwicklungs-/Compliance-Team.
### H-010 — Client-seitiges Rechte-Caching im WPF-Client als Defense-in-Depth-Lücke
**Betrifft:** StRS-018, SwRS-028
**Aussage:** `FrontWindowViewModel.HasCurrentUserRight` prüft gegen eine beim Login einmalig geladene, clientseitig gecachte Rechteliste (`CentronCache.Instance.CurrentUserAppRights`), die während der Sitzung nicht erneut serverseitig abgeglichen wird. Wird einem Benutzer während einer laufenden Sitzung ein Recht entzogen, bleibt die UI ggf. bis zum nächsten Login inkonsistent — sofern die entsprechende BL-Methode nicht selbst nochmals serverseitig prüft.
**Fehlende Information:** Für jede WPF-UI-Aktion, die nur clientseitig geprüft wird, müsste bestätigt werden, dass die zugehörige BL-Methode dieselbe Prüfung serverseitig wiederholt (wie es z. B. bei `HelpdeskBL.CheckUserRigths` der Fall ist) — dies wurde nicht für alle WPF-Module systematisch verifiziert.
### H-011 — Umgang mit historisch eingebetteten Klartext-Zugangsdaten in `app.config`
**Betrifft:** SyRS-027 (Konfigurationsmanagement/Deployment), allgemeine Sicherheitsbewertung
**Aussage:** `src\webservice\Centron.Host.Console\app.config` enthält ein aktives Klartext-SQL-Passwort sowie mehrere auskommentierte historische Zugangsdatensätze. Unklar ist, ob dies ausschließlich für lokale Entwicklungsumgebungen ohne Produktionsbezug verwendet wird (dann geringes Risiko) oder ob vergleichbare Muster auch in produktiv genutzten Konfigurationspfaden vorkommen.
**Fehlende Information:** Abgleich mit tatsächlichen Produktions-Deployment-Konfigurationen (liegen ggf. außerhalb des Repositories, z. B. in einem Secrets-Management-System) — in dieser Iteration nicht einsehbar.
### H-012 — Sum-Null-Schutz bei Rechnungsfestschreibung
**Betrifft:** StRS-003, SwRS-007
**Aussage:** Es wurde keine explizite Prüfung gefunden, die eine Rechnung mit Summe null gegen Festschreibung sperrt (nur eine mögliche UI-Warnung, kein bestätigter BL-/DB-Guard).
**Fehlende Information:** Vollständige Durchsicht von `ReceiptInvoiceBL.FixInvoice` auf weitere, in dieser Iteration nicht zitierte Vorbedingungen sowie Prüfung der UI-Schicht (WPF/Nexus) auf eine entsprechende Warnung.
---
## Hinweis zu nicht verifizierbaren Prozessartefakten
Der Analyseauftrag verlangt auch die Auswertung von Commit-Messages, Tickets und Release Notes. Ticket-Nummern (z. B. „Ticket 168496“, „Ticket 150766“) konnten über Git-Commit-Titel referenziert werden (`git log`-Kurzhistorie), eine inhaltliche Verknüpfung einzelner Codeänderungen zu genauen Commit-SHAs über `git log --grep` war im Rahmen einzelner Rechercheagenten technisch nicht möglich (interaktive Bestätigung erforderlich, im Sandbox-Kontext nicht verfügbar). Wo Ticketnummern in dieser Spezifikation auftauchen, stammen sie entweder aus Commit-Titeln (Kontext-Beleg) oder aus Code-Kommentaren, die die jeweilige Ticketnummer selbst referenzieren (z. B. „Ticket 161840“ in `TimerBillingSettingsDTO.cs`) — nicht aus einer verifizierten Commit-zu-Code-Zuordnung.
@@ -0,0 +1,559 @@
# Stakeholder Requirements Specification (StRS)
Reverse-engineert aus der c-entron-ERP-Codebasis. Ebene: fachliche Sicht, Akteure, Geschäftsziele. Format je Anforderung siehe Vorgabe im Auftrag. Alle Belege sind Datei-/Codereferenzen aus `C:\DEV\MasterArbeit\QuellCode\CentronERP` (Pfade relativ dazu angegeben).
---
## Block A — Order-to-Cash / Belegkette (Angebot–Auftrag–Lieferschein–Rechnung)
```
ID: StRS-001
Titel: Durchgängige Belegkette Angebot–Auftrag–Lieferschein–Rechnung
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter
Vorbedingung: Kundendaten und mind. ein Artikel sind erfasst.
Fakt: Alle Belegarten (Offer, Order, DeliveryList, Invoice, CreditVoucher, PickupList, ContractList) implementieren dieselbe abstrakte Basis `CustomerAssetExtended<T>` und werden über eine gemeinsame Engine (`ReceiptBL`) verarbeitet; die belegartspezifischen Regeln stecken in austauschbaren `*SpecificLogic`-Klassen (Strategy-Pattern), die das Interface `IReceiptSpecificLogic` implementieren.
Aussage: Das System soll Angebote, Aufträge, Lieferscheine und Rechnungen als eine zusammenhängende, weiterverarbeitbare Belegkette abbilden, sodass ein Beleg aus einem vorangehenden Beleg abgeleitet ("weitergeführt") werden kann, ohne Daten erneut erfassen zu müssen.
Ergebnis: Ein Folgebeleg (z. B. Auftrag aus Angebot) übernimmt Kunden-, Positions- und Preisdaten des Vorgängerbelegs.
Belege:
- [PRIMÄR] src\backend\Centron.Entities\Entities\Sales\CustomerAssets\ - Begründung: gemeinsame Basisklasse `CustomerAssetExtended<T>` zeigt, dass alle Belegarten strukturell als eine Familie behandelt werden.
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\ReceiptBL.cs - Begründung: zentrale Verarbeitungslogik für alle Belegarten (u. a. `AcceptWebReceipt`, Weiterführungslogik).
- [SEKUNDÄR] src\backend\Centron.BL\Sales\Receipts\Offers\OfferSpecificLogic.cs, Orders\OrderSpecificLogic.cs, Invoices\InvoiceSpecificLogic.cs - Begründung: belegartspezifische Ausprägung derselben Kette, belegt Wiederverwendung eines gemeinsamen Mechanismus.
Prüfidee: Ein Angebot mit n Positionen wird zu einem Auftrag weitergeführt; Kunde und Positionsdaten müssen identisch übernommen werden (Stichprobe über UI oder Integrationstest).
Tracelinks: SyRS-001, SyRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-002
Titel: Digitale Angebotsannahme per C-Sign (WebOffer)
Ebene: StRS
Typ: funktional
Akteur: Kunde (ohne Login, tokenbasiert)
Vorbedingung: Ein Angebot wurde als Web-Angebot freigegeben; ein Signaturvorgang (`SharedDocument`) wurde erzeugt.
Fakt: `ReceiptBL.AcceptWebReceipt` erzeugt über `SharedDocumentBL.GenerateTokenForDocument` einen Signier-Token und setzt `WebReceiptState = WebOfferSign`; die Blazor-Seite `SharedDocumentSignPage.razor` bietet dem Kunden drei Signaturmodi (Eingeben/Hochladen/Zeichnen) und ruft `SignSharedDocument` auf; bei Angebotsdokumenten wird der Button "Kostenpflichtig bestellen" angezeigt.
Aussage: Das System soll es Kunden ermöglichen, ein Angebot ohne Benutzerkonto über einen personalisierten, zeitlich befristeten Link online zu signieren oder ohne Unterschrift anzunehmen, wodurch das Angebot in einen kostenpflichtigen Auftrag überführt wird.
Ergebnis: Nach erfolgreicher Signatur/Annahme wechselt der Beleg in den Zustand `WebOfferSign`/`WebOfferSignedWithoutSignature`; ein Folgeauftrag kann erzeugt werden.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\ReceiptBL.cs (Methoden AcceptWebReceipt, AcceptWebReceiptWithoutSignature) - Begründung: enthält die durchgesetzte Zustandsänderung und ist keine reine UI-Beschriftung.
- [PRIMÄR] src\backend\Centron.Interfaces\Sales.Receipts\WebReceipt\WebReceiptState.cs - Begründung: definiert die tatsächlich im Code verwendeten Zustandswerte WebOfferSign/WebOfferSignedWithoutSignature.
- [SEKUNDÄR] src\nexus\CentronNexus\Office\SharedDocumentSignPage.razor - Begründung: UI-Ausprägung des Vorgangs, zeigt Signaturmodi und den Beschriftungswechsel auf "Kostenpflichtig bestellen".
Prüfidee: Signaturprozess mit gültigem Token durchlaufen; danach Prüfen, dass `WebReceiptState` gesetzt ist und ein erneuter Aufruf desselben Tokens als "bereits signiert" abgelehnt wird.
Tracelinks: SyRS-003, SyRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-003
Titel: Unveränderlichkeit festgeschriebener Rechnungen
Ebene: StRS
Typ: funktional
Akteur: Finanzbuchhaltung
Vorbedingung: Eine Rechnung existiert und ist noch nicht festgeschrieben (`IsFixed = 0`).
Fakt: `ReceiptInvoiceBL.FixInvoice` prüft über `CheckIfInvoiceIsFixed`, ob die Rechnung bereits festgeschrieben ist, und bricht in diesem Fall mit Fehlermeldung ab; bei Erfolg wird `RechKopf.IsFixed` per SQL auf 1 gesetzt (Spalte `NOT NULL DEFAULT(0)`, migriert über Skript `CreateIsFixedColumnInRechKopfTable`) und ein unveränderlicher Protokolleintrag (`ReceiptLogKind.FixedState`) geschrieben.
Aussage: Das System soll eine Rechnung nach ihrer Festschreibung dauerhaft vor inhaltlichen Änderungen schützen und diesen Vorgang nachvollziehbar protokollieren, um die Anforderungen ordnungsgemäßer Buchführung (Unveränderlichkeit gebuchter Belege) zu erfüllen.
Ergebnis: Rechnung ist nach Festschreibung nicht mehr editierbar; Protokolleintrag mit Zeitstempel und Benutzer ist vorhanden.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\Invoices\ReceiptInvoiceBL.cs (FixInvoice, CheckIfInvoiceIsFixed) - Begründung: durchgesetzte Zustandsprüfung und -änderung im Code, nicht nur UI-Hinweis.
- [PRIMÄR] src\backend\Centron.BL\Administration\Scripts\ScriptMethods\SqlStatements\SQLScriptCollection2.xml (Skript CreateIsFixedColumnInRechKopfTable, #10208) - Begründung: DB-Constraint `NOT NULL DEFAULT(0)` auf `RechKopf.IsFixed` — technischer Durchsetzungsmechanismus auf Datenbankebene.
- [SEKUNDÄR] src\backend\Centron.DAO\Mappings\...\ReceiptInvoiceBaseMaps.cs (Zeile ~175, Not.Nullable() auf IsFixed) - Begründung: bestätigt Pflichtfeld-Mapping in der ORM-Schicht.
Prüfidee: Rechnung festschreiben, danach Änderungsversuch an Position/Kopf durchführen → muss abgelehnt werden; erneutes Festschreiben → muss abgelehnt werden ("Die Rechnung ist festgeschrieben...").
Tracelinks: SyRS-005
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-004
Titel: Automatische Umsatzsteuerberechnung auf Belegen
Ebene: StRS
Typ: funktional
Akteur: System
Vorbedingung: Ein Beleg mit Nettobetrag und gültigem Steuersatz liegt vor.
Fakt: `CalculationUtils.CalculateTaxTotalPrice`/`CalculateGrossPrice` berechnen Steuerbetrag bzw. Bruttopreis aus Netto- und Steuersatzangaben (kaufmännisch gerundet, `MidpointRounding.AwayFromZero`); `InvoiceSpecificLogic.GetDateTimeForVATCalculation` legt das für die Steuersatzermittlung maßgebliche Datum fest (Belegdatum), `TakeoverVATWhenForwarding` steuert, ob beim Weiterführen (z. B. Auftrag→Rechnung) die USt neu berechnet oder übernommen wird.
Aussage: Das System soll die Umsatzsteuer für jeden Beleg automatisch und nach einer für alle Belegarten einheitlichen Regel berechnen, wobei bei der Weiterführung von Belegen konfigurierbar ist, ob der ursprüngliche Steuersatz übernommen oder neu berechnet wird.
Ergebnis: Steuerbetrag und Bruttopreis sind für jede Belegposition konsistent zur zentralen Berechnungslogik.
Belege:
- [PRIMÄR] src\backend\Centron.Interfaces\DataExchange.BookKeeping\CalculationUtils.cs - Begründung: zentrale, für alle Belegarten wiederverwendete Berechnungsfunktion.
- [SEKUNDÄR] src\backend\Centron.BL\Sales\Receipts\Invoices\InvoiceSpecificLogic.cs (GetDateTimeForVATCalculation, TakeoverVATWhenForwarding) - Begründung: belegt fachliche Sonderregel bei Belegübergängen, ergänzt aber die Kernberechnung nur.
Prüfidee: Für Netto=100, Steuersatz=19 → Steuerbetrag=19.00, Brutto=119.00 (kaufmännisch gerundet); Test mit Rabatt und Fremdwährungsfaktor.
Tracelinks: SyRS-006
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-005
Titel: Automatisches Öffnen/Schließen von Belegen nach Restmenge
Ebene: StRS
Typ: funktional
Akteur: System
Vorbedingung: Ein Beleg mit Positionen und gebuchten Teilmengen existiert.
Fakt: `AutomaticallyCloseReceiptHelperBL` (Methoden `TryAutomaticallyCloseReceipt`/`TryAutomaticallyOpenReceipt`) steuert den Übergang zwischen `ReceiptState.Active` und `ReceiptState.Completed` automatisiert anhand verbleibender Restmengen.
Aussage: Das System soll einen Beleg automatisch als abgeschlossen markieren, sobald alle Positionen vollständig weiterverarbeitet (z. B. geliefert/fakturiert) sind, und ihn bei nachträglicher Änderung wieder öffnen können.
Ergebnis: `ReceiptState` wechselt ohne manuellen Eingriff korrekt zwischen Active und Completed.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\Internal\AutomaticallyCloseReceiptHelperBL.cs - Begründung: enthält die tatsächliche Zustandsübergangslogik.
- [SEKUNDÄR] src\backend\Centron.Interfaces\Sales.Receipts\ReceiptState.cs - Begründung: definiert die beteiligten Zustandswerte (Active=1, Completed=2, Canceled=3).
Prüfidee: Beleg mit 2 Positionen anlegen, eine Position vollständig weiterverarbeiten (Beleg bleibt Active), zweite Position vollständig weiterverarbeiten (Beleg wechselt zu Completed).
Tracelinks: SyRS-001, SyRS-002
Konsolidierung: Kandidat: StRS-001 (Teil derselben Belegketten-Logik)
Status: belegt
```
---
## Block B — Helpdesk / Support / RMA
```
ID: StRS-006
Titel: Ticket-basierte Kundenservice-Bearbeitung (Helpdesk)
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ein Kunde und ein Anliegen liegen vor.
Fakt: `HelpdeskBL` (1043 Zeilen) implementiert CRUD, Pflichtfeldprüfung (`DoValidateMandatoryFields`), Textfeldlängenprüfung und eine mandatorische Rechteprüfung vor jedem Speichervorgang (`CheckUserRigths`); der Ticketstatus ist datengetrieben über die Entität `HelpdeskState` (kein hartkodiertes Enum), Standard-/Abschluss-Zustände stammen aus `AppSettingsBL`.
Aussage: Das System soll Kundenanliegen als Tickets mit konfigurierbarem Status, Zuständigkeit, Fälligkeit und Zeiterfassung verwalten und dabei alle Änderungen an eine Rechteprüfung koppeln.
Ergebnis: Ticket ist angelegt, hat einen gültigen Status aus der konfigurierten Statusliste und eine dokumentierte Historie.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (Save/DoBeforeSave, Zeilen ~298-326) - Begründung: durchgesetzte Validierung im Speicherpfad.
- [SEKUNDÄR] CentronRights.md (Abschnitt Helpdesk) - Begründung: fachliche Beschreibung der zugehörigen Rechte durch das Entwicklerteam selbst.
Prüfidee: Ticket ohne Pflichtfeld anlegen → muss abgelehnt werden; Ticket mit allen Pflichtfeldern anlegen → muss erfolgreich sein und Historieneintrag erzeugen.
Tracelinks: SyRS-007, SyRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-007
Titel: Rollenbasierte Sichtbarkeits- und Zuständigkeitssteuerung von Tickets
Ebene: StRS
Typ: Sicherheit
Akteur: Support-Mitarbeiter
Vorbedingung: Benutzer ist angemeldet und einer Abteilung/Filiale zugeordnet.
Fakt: `HelpdeskBL.CheckUserRigths` (Zeilen ~410-466) wertet u. a. `SHOW_HELPDESK_ONLY_OWN`, `SHOW_HELPDESK_ONLY_OWN_BRANCH` und `ASSIGN_HELPDESK_ONLY_TO_OWN_DEPARTMENTS` aus und schränkt Sichtbarkeit bzw. zulässige Zuweisungsziele (`ResponsiblePerson`) entsprechend ein; `CentronRights.md` beschreibt dieselben Rechte explizit als "restricting rights".
Aussage: Das System soll es erlauben, den Zugriff auf Tickets granular auf "nur eigene", "nur eigene Filiale" oder "nur eigene Abteilung" einzuschränken, unabhängig vom allgemeinen Anzeige-/Bearbeitungsrecht.
Ergebnis: Ein Benutzer mit einschränkendem Recht sieht/bearbeitet ausschließlich die für ihn zulässige Teilmenge an Tickets.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (CheckUserRigths, GetLoggedInUserShowHelpdeskRight) - Begründung: durchgesetzte Filterlogik im Code.
- [KONTEXT] CentronRights.md, Abschnitte 1.1/1.2/4 - Begründung: fachliche Definition durch das Entwicklerteam, bestätigt Intention der einschränkenden Rechte.
Prüfidee: Benutzer mit `SHOW_HELPDESK_ONLY_OWN_BRANCH` darf Ticket anderer Filiale nicht in der Liste sehen (Integrationstest mit zwei Filialen).
Tracelinks: SyRS-008
Konsolidierung: Kandidat: StRS-018 (allgemeines Rechtesystem, hier domänenspezifische Ausprägung)
Status: belegt
```
```
ID: StRS-008
Titel: RMA-Rücksende- und Reparaturabwicklung
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ein Helpdesk-Ticket existiert, zu dem ein RMA-Vorgang angelegt werden soll.
Fakt: `RmaBL.SaveRma` (2084 Zeilen Gesamtdatei) erzwingt über `ResultException("Rma not coneccted to helpdesk", ...)`, dass ein RMA-Vorgang zwingend mit einem Ticket verknüpft ist (`rma.HelpdeskI3D <= 0` → Fehler); Artikelzustände durchlaufen ein feingranulares Enum `RmaArticleState` (Open, SendForth, SendBack, Invoice, Scapped, Rebooked, ...) und ein Reparatur-Workflow-Enum `RmaForthAction` (Repair, UnRepair, EqualChange, ForeignChange, Scapped, ...).
Aussage: Das System soll Rücksendungen und Reparaturen (RMA) ausschließlich im Kontext eines Helpdesk-Tickets zulassen und den Bearbeitungsfortschritt über ein definiertes Artikel-Zustandsmodell inklusive Lagerrückbuchung nachvollziehbar abbilden.
Ergebnis: RMA-Vorgang ist mit Ticket verknüpft; Artikel durchläuft dokumentierte Zustände bis Abschluss (z. B. Rebooked/Invoice/Scapped).
Belege:
- [PRIMÄR] src\backend\Centron.BL\CustomerArea\RmaBL.cs (SaveRma, Zeilen 347-521) - Begründung: durchgesetzte Verknüpfungsprüfung und Zustandsübergänge im Code.
Prüfidee: RMA ohne HelpdeskI3D anlegen → muss mit DependencyCheckFailed-Fehler abgelehnt werden.
Tracelinks: SyRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-009
Titel: Automatisierte Ticketerzeugung über Aufgabenplaner
Ebene: StRS
Typ: funktional
Akteur: System (geplante Aufgabe)
Vorbedingung: Eine wiederkehrende Aufgabe (Tages-/Wochen-/Monats-/Jahresrhythmus) ist konfiguriert.
Fakt: `TaskManagementTaskBL.ExecuteTask` wertet Wiederholungsregeln aus (интern über DevExpress `OccurrenceCalculator`) und führt bei Fälligkeit eine pluggable Aktion aus (`TaskManagementHelpdeskActionHandler` erzeugt automatisch ein Ticket, gesichert durch das Recht `ADD_NEW_HELPDESK`); ein verteilter DB-Lock (`sp_getapplock`) verhindert Doppelausführung bei parallelen Prozessen.
Aussage: Das System soll wiederkehrende Aufgaben (z. B. regelmäßige Wartungstickets) automatisiert und ohne Doppelausführung ausführen und dabei dieselben Rechteprüfungen anwenden wie eine manuelle Ticketerstellung.
Ergebnis: Zur Fälligkeit wird genau ein Ticket erzeugt; Status der Aufgabe (`ProjectStatus`: Started/Paused/Finished) steuert, ob weiter ausgeführt wird.
Belege:
- [PRIMÄR] src\backend\Centron.BL\TaskManager\TaskManagementTaskBL.cs (ExecuteTask, sp_getapplock-Aufruf) - Begründung: technisch durchgesetzter Sperrmechanismus gegen Doppelausführung.
- [SEKUNDÄR] src\backend\Centron.BL\TaskManager\ActionHandler\TaskManagementHelpdeskActionHandler.cs (Zeile 57) - Begründung: zeigt Wiederverwendung der Helpdesk-Rechteprüfung bei automatisierter Erstellung.
Prüfidee: Zwei parallele Ausführungsversuche derselben fälligen Aufgabe → nur ein Ticket darf entstehen.
Tracelinks: SyRS-007, SyRS-010
Konsolidierung: nein
Status: belegt
```
---
## Block C — Warehousing / Purchasing
```
ID: StRS-010
Titel: Zentrale Artikelstammdatenverwaltung mit Preis- und Rechteschutz
Ebene: StRS
Typ: funktional
Akteur: Lagermitarbeiter / Einkauf
Vorbedingung: Artikel existiert oder wird neu angelegt.
Fakt: `ArticleBL.CheckUserRightBeforeSave` (Zeilen ~991-1055) blockiert Preisänderungen ohne Recht `CHANGE_ARTICLE_PRICE`, Änderungen der Barcode-Pflicht ohne `CHANGE_SERIALNUMBER_REQUIRED_FLAG` und erkennt konkurrierende Änderungen ("ChangedByOtherInstance"); `CheckSpecialUserRightBeforeSave` (Zeilen ~1058-1089) setzt bestimmte Felder (Warengruppe u. a.) stillschweigend auf den ursprünglichen DB-Wert zurück, wenn dem Benutzer das entsprechende Recht fehlt oder er `NOT_CHANGEABLE_ARTICLE_PROPERTIES` besitzt.
Aussage: Das System soll Änderungen an sicherheits- und preisrelevanten Artikeleigenschaften nur berechtigten Benutzern erlauben und nicht berechtigte Änderungen automatisch verwerfen statt sie stillschweigend zu übernehmen.
Ergebnis: Preis-/Sicherheitsfelder bleiben unverändert, wenn der speichernde Benutzer nicht berechtigt ist; entsprechende Felder werden auf DB-Stand zurückgesetzt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\ArticleBL.cs (CheckUserRightBeforeSave, CheckSpecialUserRightBeforeSave) - Begründung: durchgesetzte serverseitige Prüfung, kein reiner UI-Schutz.
Prüfidee: Benutzer ohne `CHANGE_ARTICLE_PRICE` versucht Preisänderung zu speichern → Preis bleibt auf altem DB-Wert.
Tracelinks: SyRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-011
Titel: Physische Inventur mit Bestandsabgleich
Ebene: StRS
Typ: funktional
Akteur: Lagermitarbeiter
Vorbedingung: Eine Inventur (`Inventory`) wurde angelegt und erwartete Artikelmengen sind bekannt.
Fakt: `InventoryBL` verwendet die Zustände `InventoryState` (Open, OpenWithoutBC, Deleted) sowie einen berechneten `CloseState` (Counted, Ok, Risk, problem) pro Inventurposition, ermittelt aus gezählter vs. erwarteter Menge und Barcode-Zustandskonflikten; `DeleteInventory` erlaubt Löschen/Wiederherstellen nur mit Recht `DROP_INVENTORY`.
Aussage: Das System soll den Abschluss einer Inventur nur zulassen, wenn Zähl- und Sollmengen abgeglichen sind, Abweichungen (Risk/problem) sichtbar kennzeichnen und das Löschen einer Inventur an ein eigenes Recht koppeln.
Ergebnis: Inventurpositionen sind mit korrektem `CloseState` markiert; gelöschte Inventuren sind wiederherstellbar (Statuswechsel Deleted→Open), sofern berechtigt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\InventoryManagement\InventoryBL.cs (DeleteInventory Zeilen 98-109, CloseState-Berechnung Zeilen ~694-750) - Begründung: durchgesetzte Statuslogik und Rechteprüfung im Code.
- [KONTEXT] src\backend\Centron.BL\Storage\StorageBL.cs (vollständig auskommentiert, Kommentar "SKA 2014-07-17: Obsolete... Replaced with InventoryBL") - Begründung: dokumentiert Historie/Ablösung einer Altimplementierung, keine aktive Regel mehr.
Prüfidee: Inventurposition mit abweichender Zählmenge anlegen → `CloseState` muss "Risk" oder "problem" ergeben, nicht "Ok".
Tracelinks: SyRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-012
Titel: Auftragskommissionierung (Picking)
Ebene: StRS
Typ: funktional
Akteur: Lagermitarbeiter
Vorbedingung: Ein Auftrag mit lagerpflichtigen Positionen liegt vor.
Fakt: `OrderCommissionBL`/`PartialCommissionOrderBL` steuern Kommissioniervorgänge inkl. Barcodegenerierung, geschützt durch Rechte `CREATE_PARTIAL_COMMISSION_FOR_ORDER`, `DELETE_PARTIAL_COMMISSION_FOR_ORDER`, `Logistic.Commissioning.ID`, `GENERATE_BARCODES`.
Aussage: Das System soll die (Teil-)Kommissionierung eines Auftrags rechtegeschützt ermöglichen und dabei Barcodes für die kommissionierten Artikel bereitstellen.
Ergebnis: Kommissionierte Positionen sind als (teil-)kommissioniert markiert; nicht berechtigte Benutzer können keine Teilkommissionierung anlegen/löschen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\Commissions\PartialCommissionOrderBL.cs (Zeilen 135, 170, 426, 453) - Begründung: durchgesetzte Rechteprüfung vor Kommissionsänderung.
- [SEKUNDÄR] src\backend\Centron.BL\Warehousing\Commissions\OrderCommissionBL.cs (Zeilen 431, 438) - Begründung: ergänzende Rechteprüfung für Barcodegenerierung.
Prüfidee: Benutzer ohne `CREATE_PARTIAL_COMMISSION_FOR_ORDER` versucht Teilkommission anzulegen → Ablehnung.
Tracelinks: SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-013
Titel: Automatisierte Bestellvorschlagsermittlung
Ebene: StRS
Typ: funktional
Akteur: Einkauf
Vorbedingung: Mindestbestände, offene Aufträge und offene Bestellungen sind im System erfasst.
Fakt: `OrderSuggestionListBL` (~1145 Zeilen) kombiniert über ca. 10 umfangreiche Roh-SQL-Statements (`_sqlArticle`, `_sqlOrder`, `_sqlWH`, u. a., ausgeführt via `RawSqlAccess.ExecuteQuery<T>`) Lagerbestand, Mindestbestandseinstellungen, offenen Auftragsbedarf und offenen Bestellbestand zu einer Vorschlagsliste je Artikel/Lager.
Aussage: Das System soll dem Einkauf automatisiert eine Liste nachzubestellender Artikel auf Basis von Mindestbestand, offenem Bedarf und offenem Zulauf vorschlagen.
Ergebnis: Bestellvorschlagsliste enthält je Artikel die rechnerisch benötigte Nachbestellmenge.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Purchasing\OrderSuggestionList\OrderSuggestionListBL.cs - Begründung: enthält die tatsächliche, technisch durchgesetzte Berechnungslogik (SQL-Aggregation über mehrere Legacy-Tabellen).
Prüfidee: Artikel mit Mindestbestand 10, aktuellem Bestand 3, offenem Auftragsbedarf 5 → Vorschlagsmenge muss ≥ 12 ergeben (rechnerische Nachvollziehung, exakte Formel im Quellcode zu verifizieren).
Tracelinks: SyRS-014
Konsolidierung: nein
Status: belegt; Workaround (starke Abhängigkeit von Legacy-DB-Ansichten/-Tabellen: AufPos, AufKopf, BestPos2, BestKopf2, Artik)
```
```
ID: StRS-014
Titel: EDI-Anbindung an Distributoren für Bestelldatenaustausch
Ebene: StRS
Typ: Schnittstelle
Akteur: System (automatisierter Bestellprozess)
Vorbedingung: Ein Bestellvorschlag existiert und eine EDI-Konfiguration für den Distributor ist hinterlegt.
Fakt: `EDIDispatcherBL.CreateEDISuggestionOrderAsync` wählt anhand `EDIMultidistributors`/`EdiDataType` einen distributorspezifischen Dokumentenersteller aus (u. a. ALSO, EGIS, Komsa, Alltron, ITScope, OpenTrans 2.1).
Aussage: Das System soll Bestellungen automatisiert im jeweils vom Distributor geforderten elektronischen Format erzeugen und übermitteln können, ohne dass der Anwender das Format manuell wählen muss.
Ergebnis: Für einen gewählten Distributor wird automatisch das korrekte EDI-Dokumentformat erzeugt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\EDI\EDIDispatcherBL.cs (Zeilen 56-70) - Begründung: enthält die Dispatch-Entscheidung basierend auf Konfigurationsdaten.
- [KONTEXT] docs\reference\edi\edi-architecture.md - Begründung: vom Entwicklerteam verfasste Architekturbeschreibung, keine erzwungene Regel, aber Bestätigung der Absicht.
Prüfidee: EDI-Konfiguration mit Distributor "EGIS" → erzeugtes Dokument muss dem EGIS-spezifischen Format entsprechen (Format-Validierung).
Tracelinks: SyRS-015
Konsolidierung: nein
Status: belegt
```
---
## Block D — Finances / Zahlungen
```
ID: StRS-015
Titel: Automatischer Zahlungsabgleich über Online-Banking-Integration
Ebene: StRS
Typ: funktional
Akteur: Finanzbuchhaltung
Vorbedingung: Bankkontoverbindung über FinAPI ist konfiguriert; Rechnungen mit offenem Betrag liegen vor.
Fakt: `OnlineBankingAccountTransactionsBL` importiert Kontoumsätze und ordnet sie heuristisch Kunden/Rechnungen zu (`AutoCompleteSingleAccountTransaciton`); `BookAmountToAssignedInvoice` (Zeilen ~1042-1086) verbucht nur, wenn die Rechnung `Active` ist (oder `Completed` beim Rückgängigmachen, oder der Betrag negativ ist/Rückbuchung) und markiert die Rechnung als bezahlt, sobald `PaidFC >= DemandedGrossAmount`; `SaveOnlineBankingAccountTransactions` (Zeilen ~294-340) weist doppelte Transaktionen (gleiche Kombination aus Konfiguration/Datum/Betrag/IBAN/Beschreibung) mit einer Warnung zurück.
Aussage: Das System soll importierte Bankumsätze automatisiert offenen Rechnungen zuordnen, doppelte Importe erkennen und den Zahlstatus einer Rechnung korrekt aktualisieren.
Ergebnis: Rechnung ist nach vollständigem Zahlungseingang als bezahlt markiert; doppelte Transaktionsimporte werden abgewiesen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (BookAmountToAssignedInvoice, SaveOnlineBankingAccountTransactions) - Begründung: durchgesetzte Buchungs- und Duplikatsprüfungslogik, hohe fachliche Kritikalität (Zahlungsverkehr) → PRIMÄR-Beleg erforderlich und vorhanden.
Prüfidee: Zwei identische Transaktionsimporte (gleiche IBAN/Datum/Betrag/Beschreibung) → zweiter Import muss als Duplikat markiert werden, nicht doppelt verbucht werden.
Tracelinks: SyRS-016, SyRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-016
Titel: Manuelle Zahlungserfassung mit Rechteschutz
Ebene: StRS
Typ: funktional
Akteur: Finanzbuchhaltung
Vorbedingung: Ein- oder Ausgangszahlung soll manuell erfasst/storniert werden.
Fakt: `PaymentsBL.DeleteIncomingPayment` prüft das Recht `UserRightsConst.Controlling.Finances.INCOMING_PAYMENT_TRANSACTIONS`, bevor eine erfasste Zahlung storniert und der bezahlte Betrag auf der zugehörigen Rechnung zurückgenommen wird.
Aussage: Das System soll das Löschen/Stornieren einer erfassten Zahlung nur berechtigten Benutzern erlauben und dabei den bezahlten Betrag auf dem zugehörigen Beleg konsistent zurücksetzen.
Ergebnis: Nicht berechtigter Löschversuch wird mit Fehlermeldung "Sie haben nicht das Recht 'Zahlungseingang'" abgelehnt; bei Erfolg ist der Rechnungsbetrag korrekt zurückgesetzt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\Payments\PaymentsBL.cs (Zeilen 43-44) - Begründung: durchgesetzte Rechteprüfung vor sicherheitskritischer Finanzoperation.
Prüfidee: Benutzer ohne Recht versucht Zahlung zu löschen → Ablehnung mit definierter Fehlermeldung; Rechnungsbetrag bleibt unverändert.
Tracelinks: SyRS-016
Konsolidierung: Kandidat: StRS-015 (beide betreffen Zahlungsbuchung auf Rechnungen)
Status: belegt
```
```
ID: StRS-017
Titel: Timer-basierte Leistungsabrechnung (Timer Billing)
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter / Finanzbuchhaltung
Vorbedingung: Zeiten wurden auf einem Ticket erfasst und sollen abgerechnet werden.
Fakt: `TimerBillingSettingsPageViewModel.UpdateBillingDateIsEnabled` aktiviert das Feld "Abrechnungsdatum" nur, wenn der Benutzer laut `CentronCache.Instance.ReceiptSettings` das Recht `CanChangeDateInInvoices` bzw. `CanChangeDateInDeliveryLists` besitzt; diese Werte werden serverseitig in `ReceiptWebServiceBL` aus `UserRightsConst.Sales.Customer.CustomerCommon.Invoice.CAN_CHANGE_DATE` (ID 20400143) bzw. `.DeliveryList.CAN_CHANGE_DATE` (ID 20400141) berechnet.
Aussage: Das System soll das Ändern des Abrechnungsdatums bei aus Zeiterfassungen erzeugten Rechnungen/Lieferscheinen nur Benutzern mit dem jeweils spezifischen Recht erlauben.
Ergebnis: Abrechnungsdatum-Feld ist für nicht berechtigte Benutzer deaktiviert/serverseitig nicht änderbar.
Belege:
- [PRIMÄR] src\backend\Centron.WebServices.Core\WebServices\Sales.Receipts\ReceiptWebServiceBL.cs (Zeilen 994-1000) - Begründung: serverseitig berechnete Berechtigung, nicht nur Client-Anzeige.
- [SEKUNDÄR] src\centron\Centron.WPF.UI\Modules\Finances\TimerBilling\Pages\TimerBillingSettingsPageViewModel.cs (Zeile 567) - Begründung: UI-Ausprägung derselben Regel.
Prüfidee: Benutzer ohne `CAN_CHANGE_DATE`-Recht öffnet Timer-Billing-Einstellungen → Datumsfeld ist deaktiviert; direkter Web-Service-Aufruf mit geänderten Datum ohne Recht muss serverseitig abgelehnt werden (nicht nur UI-Test!).
Tracelinks: SyRS-018
Konsolidierung: nein
Status: belegt
```
---
## Block E — Security / Rechte / Authentifizierung
```
ID: StRS-018
Titel: Rollenbasiertes Rechtesystem für alle Module
Ebene: StRS
Typ: Sicherheit
Akteur: Systemadministrator / alle internen Benutzer
Vorbedingung: Benutzer ist einer oder mehreren Rechtegruppen zugeordnet.
Fakt: `UserRightsConst` definiert ca. 751 Rechte-Konstanten, hierarchisch nach Modul/Bildschirm/Aktion organisiert; `AppRightsBL.HasUserRight` liest Gruppenrechte aus den Tabellen `Sichtrus`/`Sichmemb` und cached das Ergebnis pro Benutzer; Aufrufe finden sich konsistent über praktisch alle BL-Module (Sales, Finances, Warehousing, TaskManager, Security) verteilt.
Aussage: Das System soll jede sicherheits- oder datenrelevante Aktion serverseitig gegen ein zentral verwaltetes, granular definiertes Recht prüfen, bevor die Aktion ausgeführt wird.
Ergebnis: Aktionen ohne ausreichendes Recht werden serverseitig abgelehnt, unabhängig vom verwendeten Client (WPF, Web, API).
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Rights\AppRightsBL.cs (HasUserRight, ~Zeile 644) - Begründung: zentrale, technisch durchgesetzte Prüfimplementierung.
- [PRIMÄR] src\webservice\Centron.WebServices.Core\EntitiesWrongPlace\Administration\Rights\UserRightsConst.cs - Begründung: vollständige Liste der durchsetzbaren Rechte-IDs, Grundlage jeder Einzelprüfung.
Prüfidee: Für eine Stichprobe von 10 unterschiedlichen Modulaktionen: Benutzer ohne jeweiliges Recht → serverseitige Ablehnung (nicht nur UI-Ausblendung).
Tracelinks: SyRS-019, SyRS-020
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-019
Titel: Mehrverfahren-Authentifizierung (Basic/AD/OIDC/Web-Account)
Ebene: StRS
Typ: Sicherheit
Akteur: Alle Benutzer (intern und Kunde)
Vorbedingung: Benutzer verfügt über gültige Zugangsdaten in mindestens einem unterstützten Verfahren.
Fakt: `AuthenticatorFactory` wählt zwischen `BasicAuthenticator` (Benutzername/Passwort), `ActiveDirectoryAuthenticator`, `OpenIdConnectAuthenticator` (Microsoft Entra ID/SSO) und `WebAccountAuthenticator` (Kundenportal); nach erfolgreicher Anmeldung wird über `TicketBL`/`AuthenticationTicketBL` ein zeitlich befristetes Ticket ausgestellt.
Aussage: Das System soll mehrere Authentifizierungsverfahren parallel unterstützen und nach erfolgreicher Anmeldung eine zeitlich befristete Sitzung ausstellen.
Ergebnis: Benutzer ist nach erfolgreicher Anmeldung über eines der Verfahren mit gültigem, befristetem Ticket angemeldet.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\Auth\AuthenticatorFactory.cs, BasicAuthenticator.cs, ActiveDirectoryAuthenticator.cs, OpenIdConnectAuthenticator.cs, WebAccountAuthenticator.cs - Begründung: enthalten die tatsächlich ausgeführte Verfahrensauswahl und -prüfung.
- [SEKUNDÄR] src\nexus\CentronNexus\Shared\Auth\AUTHENTICATION.md - Begründung: vom Entwicklerteam verfasste Dokumentation des JWT-/SSO-Ablaufs, ergänzt aber die Codebelege nur.
Prüfidee: Anmeldung über jedes der vier Verfahren mit gültigen Testdaten → gültiges Ticket wird ausgestellt; ungültige Zugangsdaten → Ablehnung.
Tracelinks: SyRS-021, SyRS-022
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-020
Titel: Zwei-Faktor-Authentifizierung
Ebene: StRS
Typ: Sicherheit
Akteur: Alle internen Benutzer (sofern aktiviert)
Vorbedingung: 2FA ist über `WebServiceConfigHelper.Current.TwoFactorAuthEnabled` aktiviert.
Fakt: `TwoFactorAuthBL` orchestriert die zweite Faktorprüfung über austauschbare Validatoren (`EmailTwoFactorValidator`, `RadiusTwoFactorValidator` inkl. eigenem RADIUS-Client/-Parser); die Aktivierung ist konfigurationsgesteuert, nicht global fest verdrahtet.
Aussage: Das System soll optional eine zweite Authentifizierungsstufe (E-Mail-Code oder RADIUS-Hardwaretoken) verlangen, bevor der erste Faktor als vollständige Anmeldung akzeptiert wird.
Ergebnis: Bei aktivierter 2FA ist eine Anmeldung ohne erfolgreiche zweite Faktorprüfung nicht möglich.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\TwoFactor\TwoFactorAuthBL.cs, EmailTwoFactorValidator.cs, RadiusTwoFactorValidator.cs - Begründung: durchgesetzte zweite Prüfstufe im Anmeldeprozess.
Prüfidee: Anmeldung mit korrektem ersten Faktor, aber ohne/mit falschem zweiten Faktor → Anmeldung muss abgelehnt werden.
Tracelinks: SyRS-021
Konsolidierung: nein
Status: belegt; Workaround (zwei augenscheinlich überlappende 2FA-Implementierungen im Code vorhanden: `Administration\Logins\TwoFactor\` und separat `TwoFactorAuthenticator\` — Verhältnis ungeklärt, siehe Hypothesen.md)
```
```
ID: StRS-021
Titel: Zentrale Passwortverwaltung (Vault) für Kunden-/Systemzugänge
Ebene: StRS
Typ: Sicherheit
Akteur: Support-/Administrationsmitarbeiter
Vorbedingung: Ein Zugang (z. B. Kunden-Systemzugang) soll sicher hinterlegt werden.
Fakt: `PasswordManagementArea` (u. a. `PasswordManagementBL`, `PasswordManagementAccessLogBL`) verwaltet hinterlegte Zugangsdaten und protokolliert jeden Zugriff (`PasswordManagementAccessLog`: ActionType, Date, EmployeeI3D) sowie jede Änderung (`PasswordManagementLog`).
Aussage: Das System soll Zugriffe auf und Änderungen an im Passwort-Tresor gespeicherten Zugangsdaten vollständig protokollieren, um Zugriffe im Nachhinein nachvollziehen zu können.
Ergebnis: Jeder Lese-/Änderungszugriff auf ein gespeichertes Passwort erzeugt einen Protokolleintrag mit Benutzer und Zeitstempel.
Belege:
- [PRIMÄR] src\backend\Centron.BL\PasswordManagementArea\PasswordManagementAccessLogBL.cs, PasswordManagementLogBL.cs - Begründung: durchgesetzte, nicht abschaltbare Protokollierung im Zugriffs-/Änderungspfad.
Prüfidee: Gespeichertes Passwort einsehen → Protokolleintrag mit ActionType "Zugriff" muss entstehen.
Tracelinks: SyRS-023
Konsolidierung: nein
Status: belegt
```
---
## Block F — Web-Kanäle (Kundenportal, WebCart, Multi-Channel-Betrieb)
```
ID: StRS-022
Titel: Kundenportal für Web-Accounts (Self-Service)
Ebene: StRS
Typ: funktional
Akteur: Kunde (Web-Account)
Vorbedingung: Für den Kunden ist ein Web-Account in der Adressstammverwaltung angelegt.
Fakt: `CentronNexus` bietet unter `/customerportal` ein Self-Service-Portal (`CustomperPortalHomePage.razor`) mit Formularen (`CustomerPortalFormsPage.razor`), öffentlichen Dokumenten, Ticketansicht (`CustomerTicketDetailsPage.razor`, `CustomerTicketHistoryPage.razor`) und Zeiterfassungseinsicht (`CustomerPortalCustomerTicketTimeRecordsPage.razor`); Authentifizierung separat über `CustomerAuthPage.razor`.
Aussage: Das System soll Kunden mit Web-Account einen eigenständigen Web-Zugang bieten, über den sie ihre Tickets, Dokumente und Formulare einsehen können, getrennt von der internen Mitarbeiteranmeldung.
Ergebnis: Angemeldeter Web-Account-Kunde sieht ausschließlich seine eigenen Tickets/Dokumente.
Belege:
- [PRIMÄR] src\nexus\CentronNexus\CustomperPortalHomePage.razor, CustomerTicketDetailsPage.razor - Begründung: enthält die tatsächliche Portal-Logik/Routen.
- [SEKUNDÄR] src\nexus\CentronNexus\Shared\Auth\CustomerAuthPage.razor - Begründung: separate Login-Oberfläche, bestätigt getrennten Zugangsweg.
Prüfidee: Kunde A meldet sich an und darf keine Tickets von Kunde B sehen (Mandanten-/Kundentrennungstest).
Tracelinks: SyRS-024, SyRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-023
Titel: WebCart – Web-Shop für Sonderpreiskunden
Ebene: StRS
Typ: funktional
Akteur: Kunde (Web-Account, Kunde eines c-entron-Kunden)
Vorbedingung: Web-Account ist angelegt; für den zugehörigen Kunden sind Sonderpreisartikel hinterlegt; Lizenz `WebCart2` ist aktiv.
Fakt: `WebCartShopPage.razor` ist mit `[AuthorizeLicense(nameof(LicenseGuids.WebCart2))]` lizenzgeschützt und lädt Artikel über `ICentronService.SearchArticles`; `CurrentCartService` verwaltet den Warenkorb (`ReceiptCartDTO`) inkl. automatischer Neuanlage.
Aussage: Das System soll Kunden von c-entron-Kunden ermöglichen, über einen lizenzpflichtigen Web-Zugang die für sie freigegebenen Sonderpreisartikel zu durchsuchen und in einem Warenkorb zu bestellen.
Ergebnis: Warenkorb enthält nur für den jeweiligen Kunden freigegebene Sonderpreisartikel.
Belege:
- [PRIMÄR] src\nexus\CentronNexus\WebCart\WebCartShopPage.razor - Begründung: enthält Lizenzprüfung und Preislogik-Aufruf.
- [SEKUNDÄR] README.md (Abschnitt "1. WebCart") - Begründung: Entwicklerteam-Beschreibung des fachlichen Zwecks, bestätigt Code-Befund.
Prüfidee: Web-Account ohne WebCart2-Lizenz ruft `/webcart/shop` auf → Zugriff muss verweigert werden.
Tracelinks: SyRS-024, SyRS-025
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-024
Titel: Multi-Channel-Bereitstellung (Desktop, Web, Containerisiert) und Betrieb
Ebene: StRS
Typ: nicht-funktional
Akteur: Systemadministrator (Kunde/Betreiber), NEXOWARE-Betrieb
Vorbedingung: Zielumgebung (On-Premises-Windows oder Container-Host) ist vorbereitet.
Fakt: Drei Auslieferungsformen sind belegt: WPF-Client + Windows-Service als signierte MSI (WiX, `deployment\centron\*\Product.wxs`), sowie Nexus als containerisiertes Blazor-Server-Deployment (`docker\Dockerfile`, .NET-10-Alpine-Basis, Push nach Azure Container Registry `centron.azurecr.io`).
Aussage: Das System soll sowohl als klassische Windows-Desktop-/Service-Installation als auch als containerisierte Web-Anwendung betreibbar sein, um unterschiedliche Kundenumgebungen (On-Premises, Cloud) zu bedienen.
Ergebnis: Für jede der drei Komponenten existiert ein eigenständiger, automatisiert erstellter und signierter Auslieferungsartefakt-Typ.
Belege:
- [PRIMÄR] docker\Dockerfile, deployment\centron\CentronSetupProject\Product.wxs, deployment\centron\WebServiceSetupProject\Product.wxs - Begründung: konkrete, tatsächlich verwendete Build-/Paketierungsartefakte.
- [KONTEXT] .github\workflows\build.yml - Begründung: CI-Pipeline bestätigt automatisierten, signierten Build aller drei Artefakte, ist aber Prozess- und kein Laufzeitbeleg.
Prüfidee: CI-Pipeline-Lauf erzeugt alle drei signierten Artefakte (MSI ×2, Container-Image) ohne manuellen Eingriff.
Tracelinks: SyRS-026, SyRS-027
Konsolidierung: nein
Status: belegt
```
---
## Block G — Externe Integrationen (leichtere Analysetiefe, siehe Analysebericht.md)
```
ID: StRS-025
Titel: Produktdatenanreicherung über externe Kataloganbieter
Ebene: StRS
Typ: Schnittstelle
Akteur: Einkauf / System
Vorbedingung: Artikel mit Hersteller-/EAN-Kennung liegt vor; Zugangsdaten für externen Dienst sind konfiguriert.
Fakt: Vier eigenständige API-Clients (COP – SOAP, Egis, ITscope – XML/HTTP mit API-Key, Icecat) liefern Produktbeschreibungen, Bilder, Preise/Verfügbarkeit; jeder Client kapselt Fehler in einer eigenen Exception-Klasse mit deutschsprachiger Meldung (z. B. `ITscopeException("Der API-Key ist ungültig.")`).
Aussage: Das System soll Artikelstammdaten wahlweise über mehrere unabhängige externe Katalogdienste anreichern können, ohne dass ein Ausfall eines Dienstes die anderen beeinträchtigt.
Ergebnis: Artikeldaten (Bild, Beschreibung, Preis/Verfügbarkeit) werden aus dem jeweils konfigurierten Dienst geladen; Fehler eines Dienstes werden isoliert behandelt.
Belege:
- [PRIMÄR] src\apis\Centron.APIs.ITscopeDataAccess\ITscopeApi.cs (Zeilen 293-314) - Begründung: durchgesetzte Fehlerbehandlung pro Dienst.
- [SEKUNDÄR] src\apis\Centron.APIs.IcecatDataAccess\IcecatApi.cs, Centron.APIs.CopDataAccess\CopApi.cs, Centron.APIs.EgisDataAccess\EgisApi.cs - Begründung: bestätigen paralleles, unabhängiges Client-Design.
Prüfidee: Ein Dienst liefert HTTP 401 → nur dieser Dienst wird als fehlgeschlagen markiert, übrige Anreicherungsquellen bleiben nutzbar.
Tracelinks: SyRS-028
Konsolidierung: Kandidat: strukturell ähnliches Client-Pattern wie StRS-026 (Versanddienstleister)
Status: belegt
```
```
ID: StRS-026
Titel: Versanddienstleister-Integration (Paketversand)
Ebene: StRS
Typ: Schnittstelle
Akteur: Lagermitarbeiter / Versand
Vorbedingung: Sendung mit Empfängerdaten ist bereit zum Versand.
Fakt: `CentronGlsLogic.UploadShipment` sendet eine `ShippmentRequest` an GLS und liefert Tracking-ID/-URL sowie Label zurück; `CentronShipcloudLogic` bietet eine mehrere Carrier umfassende Alternative (Shipcloud) inkl. Webhook-Empfang für Statusupdates (`WebhookSecurity`).
Aussage: Das System soll Versandaufträge elektronisch an mindestens einen Paketdienstleister übermitteln und die zurückgelieferte Sendungsverfolgung sowie das Versandlabel dem Beleg zuordnen.
Ergebnis: Beleg enthält nach erfolgreichem Versandauftrag Tracking-Referenz und Label.
Belege:
- [PRIMÄR] src\apis\Centron.Api.Gls\CentronGlsLogic.cs (UploadShipment) - Begründung: durchgesetzter Aufruf- und Rückgabepfad.
- [SEKUNDÄR] src\apis\Centron.Api.Shipcloud\CentronShipcloudLogic.cs - Begründung: alternative/ergänzende Umsetzung desselben fachlichen Ziels.
Prüfidee: Versandauftrag mit gültigen Empfängerdaten auslösen → Tracking-ID und Label müssen im System hinterlegt sein.
Tracelinks: SyRS-028
Konsolidierung: Kandidat: GLS und Shipcloud bilden dieselbe fachliche Funktion "Versandauftrag erstellen" redundant ab.
Status: belegt
```
```
ID: StRS-027
Titel: Elektronischer Rechnungsaustausch (ZUGFeRD/ebInterface/XRechnung)
Ebene: StRS
Typ: Schnittstelle
Akteur: Finanzbuchhaltung
Vorbedingung: Eine Rechnung soll in einem elektronischen, normierten Format ausgetauscht werden.
Fakt: `EbInterfaceLogic` erzeugt lokal ebInterface-4.3-konforme XML aus einem `ReceiptInfo`-Objekt (österreichischer E-Rechnungsstandard); ein separater `ZugferdImportController` importiert ZUGFeRD-Rechnungen; `docs\reference\zugferd-field-mapping.md` dokumentiert das Feldmapping.
Aussage: Das System soll Eingangsrechnungen im ZUGFeRD-Format importieren und ausgehende Rechnungen im ebInterface-Format exportieren können, um gesetzliche/branchenübliche E-Rechnungsanforderungen in Deutschland und Österreich zu erfüllen.
Ergebnis: Import einer gültigen ZUGFeRD-Datei überführt deren Daten in einen Beleg; Export einer Rechnung erzeugt eine schemakonforme ebInterface-XML.
Belege:
- [PRIMÄR] src\apis\Centron.Api.EbInterface\EbInterfaceLogic.cs - Begründung: durchgesetzte XML-Erzeugung nach Zielschema.
- [SEKUNDÄR] src\webservice\Centron.Controllers\Controllers\v1\Receipts\ZugferdImportController.cs, docs\reference\zugferd-field-mapping.md - Begründung: Import-Endpunkt bzw. Entwicklerdokumentation als ergänzender Beleg.
Prüfidee: ebInterface-Export einer Testrechnung gegen offizielles XSD-Schema validieren.
Tracelinks: SyRS-028
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-028
Titel: Druckerflottenmanagement (Managed Print Services / docuFORM)
Ebene: StRS
Typ: Schnittstelle
Akteur: System / Administrator (Gerätemonitoring)
Vorbedingung: Geräte sind im externen docuFORM-System (MPS-Dienstleister) registriert; OAuth2-Zugangsdaten sind konfiguriert.
Fakt: `DocuFormRestApiClient` authentifiziert sich per OAuth2 (`OAuthHelper`) gegen `/auth/v2/token` und ruft anschließend `/dfmserver/v2/devices` u. a. für Zählerstände (`DeviceCounters`), Verbrauchsmaterial (`DeviceSupplies`) und Ereignisse (`DeviceEvent`) ab; Konfiguration über `DocuFormApiSettingsController`.
Aussage: Das System soll Zählerstände, Verbrauchsmaterialstatus und Ereignisse angebundener Drucker-/Kopierergeräte über die docuFORM-Schnittstelle automatisiert abrufen können.
Ergebnis: Gerätestatus (Zähler, Verbrauchsmaterial) ist im System aktuell verfügbar, ohne manuelle Ablesung.
Belege:
- [PRIMÄR] src\apis\Centron.Api.docuFORM\DocuFormRestApiClient.cs, DocuFormRestApiConstants.cs - Begründung: durchgesetzter Abruf-Client mit versionierten Endpunktpfaden.
- [SEKUNDÄR] src\webservice\Centron.Controllers\Controllers\v1\DataExchange\DocuFormApiSettingsController.cs - Begründung: Konfigurationsoberfläche für die Integration.
Prüfidee: Abruf von `GetDeviceCounters` für ein Testgerät liefert plausible Zählerwerte zurück.
Tracelinks: SyRS-028
Konsolidierung: nein
Status: belegt
```
@@ -0,0 +1,761 @@
# Software Requirements Specification (SwRS)
Ebene: Komponenten, Datenmodelle, software-interne Regeln. Tracelinks verweisen auf die zugehörige(n) SyRS-Anforderung(en).
---
## Block A — Belegkette / Order-to-Cash
```
ID: SwRS-001
Titel: IReceiptSpecificLogic als Erweiterungspunkt je Belegart
Ebene: SwRS
Typ: Daten
Akteur: Komponente ReceiptBL
Vorbedingung: Beleg einer bestimmten Art (Offer/Order/DeliveryList/Invoice/...) wird verarbeitet.
Fakt: `IReceiptSpecificLogic` wird von `OfferSpecificLogic`, `OrderSpecificLogic`, `DeliveryListSpecificLogic`, `InvoiceSpecificLogic` u. a. implementiert; `ReceiptBL` erhält die passende Implementierung injiziert statt Typprüfungen (`is`/`switch` auf Belegart) durchzuführen.
Aussage: Die Komponente `ReceiptBL` soll belegartspezifisches Verhalten ausschließlich über die injizierte `IReceiptSpecificLogic`-Instanz beziehen.
Ergebnis: Neue Belegart erfordert nur eine neue `IReceiptSpecificLogic`-Implementierung, keine Änderung an `ReceiptBL` selbst.
Belege:
- [PRIMÄR] src\backend\Centron.Interfaces\Sales.Receipts\IReceiptSpecificLogic.cs - Begründung: definiert den Erweiterungsvertrag.
- [SEKUNDÄR] src\backend\Centron.BL\Sales\Receipts\Offers\OfferSpecificLogic.cs, Invoices\InvoiceSpecificLogic.cs - Begründung: konkrete Implementierungen belegen konsistente Nutzung des Patterns.
Prüfidee: Statische Codeanalyse: keine belegartspezifische Fallunterscheidung außerhalb der `*SpecificLogic`-Klassen in `ReceiptBL`.
Tracelinks: SyRS-001
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-002
Titel: CustomerAssetExtended<T> als gemeinsame Entitätsbasis
Ebene: SwRS
Typ: Daten
Akteur: Datenmodell (Centron.Entities)
Vorbedingung: Entität einer Belegart wird modelliert.
Fakt: `Order`, `Invoice`, `Offer` erben (mittelbar über belegartspezifische Basisklassen) von `CustomerAssetExtended<T>`; Belegart-Diskriminierung erfolgt über `CentronObjectKindNumeric` (`AssetKindOa = ...OrderClass`/`InvoiceClass`).
Aussage: Das Datenmodell soll alle Belegarten strukturell als Ausprägungen derselben abstrakten Basis führen, um gemeinsame Felder (Kunde, Datum, Status) nur einmal zu definieren.
Ergebnis: Gemeinsame Felder sind für alle Belegarten strukturell identisch benannt/typisiert.
Belege:
- [PRIMÄR] src\backend\Centron.Interfaces\CentronObjectKindNumeric.cs - Begründung: enthält die tatsächlich verwendete Diskriminator-Enumeration.
- [SEKUNDÄR] src\backend\Centron.Entities\Entities\Sales\CustomerAssets\Orders\Order.cs, Invoices\Invoice.cs - Begründung: konkrete Vererbungshierarchie.
Prüfidee: Reflection-Test: alle Belegart-Entitäten erben von derselben Basisklasse.
Tracelinks: SyRS-001
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-003
Titel: AutomaticallyCloseReceiptHelperBL steuert ReceiptState-Übergänge
Ebene: SwRS
Typ: funktional
Akteur: Komponente AutomaticallyCloseReceiptHelperBL
Vorbedingung: Belegposition wurde vollständig oder teilweise weiterverarbeitet.
Fakt: `TryAutomaticallyCloseReceipt` setzt `ReceiptState = Completed`, wenn keine offene Restmenge mehr vorhanden ist; `TryAutomaticallyOpenReceipt` macht dies bei nachträglicher Änderung rückgängig.
Aussage: Die Komponente soll nach jeder Mengenänderung an einem Beleg prüfen, ob ein automatischer Statuswechsel erforderlich ist, und diesen ausführen.
Ergebnis: `ReceiptState` ist nach jeder Mengenänderung konsistent mit der tatsächlichen Restmenge.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\Internal\AutomaticallyCloseReceiptHelperBL.cs - Begründung: enthält die tatsächliche Übergangslogik.
Prüfidee: Letzte offene Position eines Belegs vollständig verarbeiten → `ReceiptState` wechselt automatisch zu `Completed`.
Tracelinks: SyRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-004
Titel: Ein-aktiver-Vorgang-Regel bei SharedDocumentBL.GenerateTokenForDocument
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente SharedDocumentBL
Vorbedingung: Für einen Beleg soll ein neuer Signiervorgang gestartet werden.
Fakt: `GenerateTokenForDocument` (Zeilen 128-130) ruft `GetActiveAndUnsignedSharedDocumentForReceipt` auf; existiert bereits ein solcher, wird `Result<SharedDocument>.AsError("Es existiert bereits ein aktiver Signierungs-Ablauf", ...)` zurückgegeben statt eines neuen Tokens.
Aussage: Die Methode soll für einen Beleg maximal einen aktiven, unsignierten Vorgang gleichzeitig zulassen.
Ergebnis: Zweiter Aufruf für denselben Beleg bei bestehendem aktivem Vorgang liefert einen Fehler statt eines zweiten Tokens.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\FileManagement\SharedDocumentBL.cs (Zeilen 128-130) - Begründung: sicherheits-/rechtsverbindlichkeitsrelevant, PRIMÄR-Beleg vorhanden (durchgesetzte Prüfung).
Prüfidee: Zweiten `GenerateTokenForDocument`-Aufruf für denselben `receiptI3D` bei aktivem Vorgang → `Result.AsError`.
Tracelinks: SyRS-003
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-005
Titel: Ablauf- und Einmaligkeitsprüfung in SharedDocumentBL.GetSharedDocumentByToken
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente SharedDocumentBL
Vorbedingung: Ein Token wird zum Abrufen eines Signiervorgangs verwendet.
Fakt: Zeilen 405-406: `if (foundByToken.ExpiredDate.HasValue && foundByToken.ExpiredDate.Value < DateTime.Now) return Result<int>.AsError("Die Signierungsanfrage ist bereits abgelaufen.", ...)`; Zeile 408-409: `if (foundByToken.IsSigned) return Result<int>.AsError("Dokument wurde bereits signiert.", ...)`.
Aussage: Die Methode soll Zugriffe mit abgelaufenem oder bereits verwendetem Token serverseitig ablehnen, bevor Dokumentinhalte ausgeliefert werden.
Ergebnis: Abgelaufener/verwendeter Token liefert einen definierten Fehler, keine Dokumentdaten.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\FileManagement\SharedDocumentBL.cs (Zeilen 405-409) - Begründung: durchgesetzte serverseitige Prüfung.
Prüfidee: Abgelaufenen Token per direktem Methodenaufruf/HTTP-Request verwenden → definierter Fehlercode, keine Nutzdaten.
Tracelinks: SyRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-006
Titel: Zustandssetzung durch ReceiptBL.AcceptWebReceipt / AcceptWebReceiptWithoutSignature
Ebene: SwRS
Typ: funktional
Akteur: Komponente ReceiptBL
Vorbedingung: Kunde signiert oder akzeptiert ein Web-Angebot ohne Unterschrift.
Fakt: `AcceptWebReceipt` (~Zeile 6256) setzt `receiptPdfDocument.WebReceiptState = WebReceiptState.WebOfferSign` (Zeile 6302); `AcceptWebReceiptWithoutSignature` (~Zeile 6311) setzt `WebOfferSignedWithoutSignature` (Zeile 6360) und leitet die Weiterführung zum Auftrag ein.
Aussage: Die Methoden sollen den Belegstatus abhängig vom gewählten Annahmeweg (mit/ohne Signatur) eindeutig und unterscheidbar setzen.
Ergebnis: `WebReceiptState` zeigt nach Annahme eindeutig, ob mit oder ohne Signatur akzeptiert wurde.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\ReceiptBL.cs (Zeilen 6256-6360) - Begründung: enthält die tatsächliche Zustandssetzung.
- [PRIMÄR] src\backend\Centron.Interfaces\Sales.Receipts\WebReceipt\WebReceiptState.cs - Begründung: definiert die verwendeten Enumwerte.
Prüfidee: Annahme mit Signatur → `WebOfferSign`; Annahme ohne Signatur → `WebOfferSignedWithoutSignature`.
Tracelinks: SyRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-007
Titel: ReceiptInvoiceBL.FixInvoice mit Guard CheckIfInvoiceIsFixed
Ebene: SwRS
Typ: funktional
Akteur: Komponente ReceiptInvoiceBL
Vorbedingung: Rechnung soll festgeschrieben werden.
Fakt: `FixInvoice` (Zeile 86) ruft `CheckIfInvoiceIsFixed` (Zeile 273) auf; ist die Rechnung bereits fixiert, wird die Warnung "Die Rechnung ist festgeschrieben. Änderungen nicht möglich." in einen harten Fehler umgewandelt, bevor der eigentliche Festschreibungs-Schreibvorgang beginnt; bei Erfolg wird ein Protokolleintrag `ReceiptLogKind.FixedState` mit Zeitstempel und Benutzer erzeugt.
Aussage: Die Methode soll eine bereits festgeschriebene Rechnung nicht erneut festschreiben und jede erfolgreiche Festschreibung mit einem unveränderlichen Protokolleintrag versehen.
Ergebnis: Zweite Festschreibung derselben Rechnung wird abgelehnt; jede erfolgreiche Festschreibung ist protokolliert.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\Invoices\ReceiptInvoiceBL.cs (FixInvoice Zeile 86, CheckIfInvoiceIsFixed Zeile 273) - Begründung: Fakturierungslogik, PRIMÄR-Beleg zwingend und vorhanden.
Prüfidee: Bereits fixierte Rechnung erneut festschreiben → Ablehnung mit definierter Meldung.
Tracelinks: SyRS-005
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-008
Titel: DB-Constraint RechKopf.IsFixed NOT NULL DEFAULT(0)
Ebene: SwRS
Typ: Daten
Akteur: Datenbank
Vorbedingung: Neue Rechnungszeile (`RechKopf`) wird angelegt.
Fakt: Migrationsskript `CreateIsFixedColumnInRechKopfTable` (#10208, `SQLScriptCollection2.xml`) definiert `IsFixed bit NOT NULL CONSTRAINT DF_RechKopf_IsFixed DEFAULT(0)`, gespiegelt auf `RechKopfVersions`.
Aussage: Die Spalte `IsFixed` soll auf Datenbankebene nie NULL sein, unabhängig davon, ob die Anwendungsschicht den Wert explizit setzt.
Ergebnis: Jede Rechnungszeile hat nach dem Anlegen `IsFixed = 0` (Standardwert), sofern nicht explizit anders gesetzt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Scripts\ScriptMethods\SqlStatements\SQLScriptCollection2.xml (Skript #10208) - Begründung: DB-Constraint, höchste Evidenzstufe.
- [SEKUNDÄR] src\backend\Centron.DAO\Mappings\...\ReceiptInvoiceBaseMaps.cs (Not.Nullable() auf IsFixed) - Begründung: ORM-seitige Bestätigung des Pflichtfelds.
Prüfidee: INSERT ohne explizite Angabe von `IsFixed` → DB setzt automatisch 0, NULL wird von der DB abgelehnt.
Tracelinks: SyRS-005
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-009
Titel: CalculationUtils.CalculateTaxTotalPrice / CalculateGrossPrice
Ebene: SwRS
Typ: Daten
Akteur: Komponente CalculationUtils
Vorbedingung: Netto-Betrag und Steuersatz liegen vor.
Fakt: `CalculateTaxTotalPrice(netTotalPrice, taxRate) = Math.Round(netTotalPrice * (taxRate/100), 2, MidpointRounding.AwayFromZero)`; `CalculateGrossPrice` berechnet zunächst den Nettopreis unter Berücksichtigung von Währungsfaktor und Rabatt, dann den Bruttopreis mit Steueraufschlag, gerundet mit konfigurierbarer Präzision.
Aussage: Die Funktionen sollen Steuer- und Bruttobeträge nach einer festen, kaufmännischen Rundungsregel (2 Nachkommastellen, `AwayFromZero`) berechnen.
Ergebnis: Für identische Eingabewerte liefert die Funktion stets dasselbe, deterministische Ergebnis.
Belege:
- [PRIMÄR] src\backend\Centron.Interfaces\DataExchange.BookKeeping\CalculationUtils.cs - Begründung: enthält die tatsächliche Berechnungs-/Rundungslogik.
Prüfidee: Netto=100,005, Steuersatz=19 → erwarteter, kaufmännisch gerundeter Wert (Unit-Test mit Grenzwerten wie x,xx5).
Tracelinks: SyRS-006
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-010
Titel: InvoiceSpecificLogic.TakeoverVATWhenForwarding steuert USt-Übernahme bei Belegübergängen
Ebene: SwRS
Typ: funktional
Akteur: Komponente InvoiceSpecificLogic
Vorbedingung: Ein Beleg wird zu einem Folgebeleg weitergeführt (z. B. Auftrag → Rechnung).
Fakt: `TakeoverVATWhenForwarding() => TakeoverVatMode.Yes`; `GetDateTimeForVATCalculation(receipt) => receipt.Date` legt fest, welches Datum für die Steuersatzermittlung bei Neuberechnung herangezogen wird.
Aussage: Die Komponente soll bei Belegweiterführung explizit steuern, ob die Umsatzsteuer vom Vorgängerbeleg übernommen oder anhand des Belegdatums neu berechnet wird.
Ergebnis: Weitergeführter Beleg hat einen nachvollziehbar (Übernahme oder Neuberechnung) bestimmten Steuersatz.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\Invoices\InvoiceSpecificLogic.cs (TakeoverVATWhenForwarding, GetDateTimeForVATCalculation) - Begründung: enthält die tatsächliche Steuerungslogik.
Prüfidee: Auftrag mit Steuersatz X zu Rechnung mit späterem Datum (nach Steuersatzänderung) weiterführen → Ergebnis muss mit `TakeoverVatMode.Yes`-Regel übereinstimmen (Übernahme statt Neuberechnung).
Tracelinks: SyRS-006
Konsolidierung: nein
Status: belegt
```
---
## Block B — Helpdesk / RMA / TaskManager
```
ID: SwRS-011
Titel: HelpdeskBL.Save/DoBeforeSave Validierungspipeline
Ebene: SwRS
Typ: funktional
Akteur: Komponente HelpdeskBL
Vorbedingung: Ticket wird gespeichert.
Fakt: `Save`/`DoBeforeSave` (Zeilen ~298-326) führen sequenziell `DoValidateMandatoryFields`, `CheckUserRigths`, `CheckTextFieldLengths` und eine Zeilenumbruch-Normalisierung aus, bevor der eigentliche Speichervorgang beginnt.
Aussage: Die Methode soll ein Ticket nur speichern, wenn alle Pflichtfelder gesetzt, der Benutzer berechtigt und Textfeldlängen eingehalten sind.
Ergebnis: Speicherversuch mit fehlendem Pflichtfeld oder überlanger Texteingabe wird abgelehnt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (Zeilen 298-326) - Begründung: durchgesetzte Validierungskette im Speicherpfad.
Prüfidee: Ticket ohne Pflichtfeld "Kunde" speichern → Ablehnung vor Persistierung.
Tracelinks: SyRS-007
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-012
Titel: HelpdeskBL.CheckUserRigths differenziert nach Aktion (Anlage/Bearbeitung/Schließen/Zuweisung)
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente HelpdeskBL
Vorbedingung: Ticket-Änderung mit bestimmter Aktion (neu/bearbeiten/schließen/zuweisen/Fälligkeit ändern) wird angestoßen.
Fakt: `CheckUserRigths` (Zeilen 410-466) prüft je nach Aktion ein spezifisches Recht: `ADD_NEW_HELPDESK` (Neuanlage), `EDIT_HELPDESK` (Bearbeitung), `CLOSE_REQUEST` (Schließen, sonst wird `entity.ClosedAt = null` zurückgesetzt), `MATURITY_CHANGE` (Fälligkeitsänderung, geprüft über `HelpdeskRepositoryDAO.IsDueDateChanged`), `ASSIGN_HELPDESK_ONLY_TO_OWN_DEPARTMENTS` (Einschränkung von `ResponsiblePerson` auf eigene Abteilung, Zeilen 454-462).
Aussage: Die Methode soll für jede Art der Ticketänderung ein eigenständiges, spezifisches Recht prüfen statt ein einzelnes generisches "Bearbeiten"-Recht für alle Aktionen zu verwenden.
Ergebnis: Benutzer mit `EDIT_HELPDESK`, aber ohne `CLOSE_REQUEST`, kann Ticket bearbeiten, aber nicht schließen (Schließversuch wird durch Zurücksetzen von `ClosedAt` neutralisiert).
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (Zeilen 410-466) - Begründung: durchgesetzte, aktionsspezifische Rechteprüfung.
Prüfidee: Benutzer mit `EDIT_HELPDESK` ohne `CLOSE_REQUEST` versucht `ClosedAt` zu setzen → Feld wird serverseitig zurückgesetzt.
Tracelinks: SyRS-007
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-013
Titel: Sichtbarkeitsfilter SHOW_HELPDESK_ONLY_OWN / _ONLY_OWN_BRANCH in Abfragekonstruktion
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente HelpdeskBL
Vorbedingung: Ticketliste wird für einen Benutzer mit einschränkendem Recht abgefragt.
Fakt: `GetLoggedInUserShowHelpdeskRight` (Zeilen ~271-284) bestimmt den anzuwendenden Scope (own/own branch/all) und dieser fließt in den Abfrageaufbau ein, bevor Daten aus der DB gelesen werden; `RmaBL.GetNamedQueryParams` (Zeilen 653-669) delegiert dieselbe Scope-Logik für RMA-Sichtbarkeit an `HelpdeskBL`.
Aussage: Die Abfragekonstruktion soll den Sichtbarkeits-Scope bereits vor dem Datenbankzugriff anwenden, nicht als Post-Filter auf einer bereits vollständig geladenen Ergebnismenge.
Ergebnis: Datenbankabfrage enthält bereits die Scope-Einschränkung als Teil des WHERE-Kriteriums bzw. der Query-Parameter.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (GetLoggedInUserShowHelpdeskRight) - Begründung: durchgesetzte Scope-Bestimmung vor Datenzugriff.
- [SEKUNDÄR] src\backend\Centron.BL\CustomerArea\RmaBL.cs (GetNamedQueryParams, Zeilen 653-669) - Begründung: Wiederverwendung derselben Scope-Logik in einem zweiten Modul, stützt die Aussage zur konsistenten Durchsetzung.
Prüfidee: SQL-Profiling der Abfrage eines eingeschränkten Benutzers → WHERE-Klausel enthält bereits die Scope-Bedingung.
Tracelinks: SyRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-014
Titel: RmaBL.SaveRma erzwingt HelpdeskI3D > 0
Ebene: SwRS
Typ: Daten
Akteur: Komponente RmaBL
Vorbedingung: RMA-Datensatz wird gespeichert.
Fakt: Zeilen 352-353: `if (rma.HelpdeskI3D <= 0) throw new ResultException("Rma not coneccted to helpdesk", DependencyCheckFailed);` vor jeglicher weiterer Verarbeitung.
Aussage: Die Methode soll die Ticketverknüpfung als erste Prüfung im Speicherpfad durchführen, bevor weitere (aufwändigere) Verarbeitungsschritte wie Lagerbuchungen ausgeführt werden.
Ergebnis: RMA ohne gültige Ticketreferenz wird abgelehnt, bevor Nebenwirkungen (z. B. Lagerbuchungen) eintreten.
Belege:
- [PRIMÄR] src\backend\Centron.BL\CustomerArea\RmaBL.cs (Zeilen 352-353) - Begründung: durchgesetzte Prüfung als erster Schritt des Speicherpfads.
Prüfidee: RMA mit `HelpdeskI3D = 0` speichern → `ResultException` vor jeder Nebenwirkung, keine Teilverarbeitung.
Tracelinks: SyRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-015
Titel: RmaArticleState-Zustandsmodell und Reparatur-Workflow RmaForthAction
Ebene: SwRS
Typ: Daten
Akteur: Komponente RmaBL
Vorbedingung: RMA-Artikelposition durchläuft den Reparatur-/Rücksendeprozess.
Fakt: `RmaArticleState` (u. a. `none`, `Open`, `SendForth`, `SendBack`, `BackDeliveryList`, `Invoice`, `Scapped`, `Rebooked`) und `RmaForthAction` (u. a. `Repair`, `UnRepair`, `EqualChange`, `ForeignChange`, `Scapped`) werden in `SaveRma` (Zeilen 378-521) und `HistoryCanceled` (825-879) als Zustandsübergänge durchgesetzt.
Aussage: Die Komponente soll den Bearbeitungsfortschritt einer RMA-Artikelposition ausschließlich über die definierten Enum-Zustände abbilden und Übergänge nachvollziehbar in der Historie (`RmaArticleHistory`) festhalten.
Ergebnis: Jede RMA-Artikelposition hat zu jedem Zeitpunkt einen der definierten `RmaArticleState`-Werte; Zustandswechsel sind über Historieneinträge nachvollziehbar.
Belege:
- [PRIMÄR] src\backend\Centron.BL\CustomerArea\RmaBL.cs (SaveRma Zeilen 378-521, HistoryCanceled Zeilen 825-879) - Begründung: enthält die tatsächlichen Zustandsübergänge.
Prüfidee: Artikel von `SendForth` zu `Invoice` überführen → Historieneintrag mit korrektem Alt-/Neu-Zustand entsteht.
Tracelinks: SyRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-016
Titel: TaskManagementTaskBL.ExecuteTask mit sp_getapplock-Sperre
Ebene: SwRS
Typ: nicht-funktional
Akteur: Komponente TaskManagementTaskBL
Vorbedingung: Fällige wiederkehrende Aufgabe wird ausgewertet.
Fakt: Private Overload (Zeilen ~673-687) führt `DECLARE @result int; EXEC @result = sp_getapplock @Resource = :resource, @LockMode = 'Exclusive', @LockOwner = 'Transaction', @LockTimeout = 0; SELECT @result` aus, bevor die eigentliche Aktion (`TaskManagementHelpdeskAction`/`TaskManagementReportAction`) ausgeführt wird.
Aussage: Die Methode soll vor Ausführung einer fälligen Aufgabe ein exklusives, transaktionsgebundenes Datenbank-Lock mit Timeout 0 erwerben und bei Nichterhalt die Ausführung nicht durchführen.
Ergebnis: Bei parallelem Zugriff zweier Prozesse erhält nur einer das Lock; der andere überspringt die Ausführung.
Belege:
- [PRIMÄR] src\backend\Centron.BL\TaskManager\TaskManagementTaskBL.cs (sp_getapplock-Aufruf) - Begründung: DB-seitig durchgesetzter, prozessübergreifender Sperrmechanismus.
Prüfidee: Zwei parallele Prozessaufrufe für dieselbe Aufgaben-ID → nur ein Prozess erhält das Lock (LockTimeout=0 lässt zweiten sofort fehlschlagen).
Tracelinks: SyRS-010
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-017
Titel: TaskManagementHelpdeskActionHandler prüft ADD_NEW_HELPDESK vor automatischer Ticketerstellung
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente TaskManagementHelpdeskActionHandler
Vorbedingung: Automatisierte Aufgabe erzeugt ein Helpdesk-Ticket.
Fakt: Zeile 57 prüft `UserRightsConst.Sales.Customer.Helpdesk.ADD_NEW_HELPDESK`, bevor das Ticket erzeugt wird — dieselbe Rechteprüfung wie bei manueller Ticketerstellung in `HelpdeskBL`.
Aussage: Der Action-Handler soll dieselbe Rechteprüfung wie der manuelle Ticket-Anlagepfad verwenden, um zu verhindern, dass automatisierte Aufgaben Rechteprüfungen umgehen.
Ergebnis: Automatisierte Ticketerstellung ohne konfigurierten, berechtigten Ausführungsbenutzer schlägt fehl statt das Recht zu umgehen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\TaskManager\ActionHandler\TaskManagementHelpdeskActionHandler.cs (Zeile 57) - Begründung: identische Rechteprüfung wie im manuellen Pfad, verhindert Umgehung.
Prüfidee: Aufgabe mit Ausführungskontext ohne `ADD_NEW_HELPDESK`-Recht fällig werden lassen → Ticketerstellung schlägt fehl statt das Recht zu ignorieren.
Tracelinks: SyRS-010
Konsolidierung: Kandidat: SwRS-012 (gleiche zugrundeliegende Rechteklasse ADD_NEW_HELPDESK)
Status: belegt
```
---
## Block C — Warehousing / Purchasing
```
ID: SwRS-018
Titel: ArticleBL Feldschutz: Blockade vs. stiller Rollback je Feld
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente ArticleBL
Vorbedingung: Artikel wird mit geänderten Feldern gespeichert.
Fakt: `CheckUserRightBeforeSave` (Zeilen 991-1055) blockiert den gesamten Speichervorgang bei fehlendem Recht für Preis/Barcode-Pflicht-Änderung; `CheckSpecialUserRightBeforeSave` (Zeilen 1058-1089) hingegen setzt nur die betroffenen Felder (Warengruppe, Nebenwarengruppe, `MailToCollection`, `ClassI3D2`) auf den ursprünglichen DB-Wert zurück und lässt den restlichen Speichervorgang zu, wenn `NOT_CHANGEABLE_ARTICLE_PROPERTIES` gesetzt ist oder `EDIT_MaterialGroup` fehlt.
Aussage: Die Komponente soll zwei unterschiedliche Schutzstrategien anwenden: harte Ablehnung für hochkritische Felder (Preis), stiller Feld-Rollback für weniger kritische Klassifikationsfelder, um den restlichen Speichervorgang nicht unnötig zu blockieren.
Ergebnis: Speichervorgang mit gemischt berechtigten/nicht berechtigten Feldänderungen führt zu partiellem Erfolg (erlaubte Felder gespeichert, geschützte zurückgesetzt) statt Totalausfall.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\ArticleBL.cs (Zeilen 991-1089) - Begründung: enthält beide durchgesetzten Schutzmechanismen im Detail.
Prüfidee: Speichervorgang mit geänderter Warengruppe (ohne Recht) und geändertem Namen (mit Recht) → Name wird gespeichert, Warengruppe bleibt auf DB-Wert.
Tracelinks: SyRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-019
Titel: Berechnung von CloseState (Counted/Ok/Risk/problem) je Inventurposition
Ebene: SwRS
Typ: funktional
Akteur: Komponente InventoryBL
Vorbedingung: Inventurposition wurde gezählt.
Fakt: Berechnungslogik (Zeilen ~694-750) vergleicht gezählte mit erwarteter Menge und berücksichtigt Barcode-Zustandskonflikte zur Ableitung von `CloseState`.
Aussage: Die Berechnung soll deterministisch aus Zähl-/Sollmenge und Barcode-Zustand erfolgen, ohne manuelle Nacherfassung durch den Anwender.
Ergebnis: Jede gezählte Position hat unmittelbar nach der Zählung einen berechneten `CloseState`.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\InventoryManagement\InventoryBL.cs (Zeilen 694-750) - Begründung: enthält die tatsächliche Berechnungslogik.
Prüfidee: Zählmenge = Sollmenge, kein Barcode-Konflikt → `CloseState = Ok`; Zählmenge ≠ Sollmenge → `Risk`/`problem`.
Tracelinks: SyRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-020
Titel: InventoryBL.DeleteInventory: Statuswechsel Open⇄Deleted mit Rechteprüfung
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente InventoryBL
Vorbedingung: Inventur soll gelöscht oder wiederhergestellt werden.
Fakt: Zeilen 98-109: Wechsel von `Open`/`OpenWithoutBC` zu `Deleted` (und zurück, als Undo-Delete), gesichert durch `UserRightsConst.Purchase.Inventory.DROP_INVENTORY`.
Aussage: Die Methode soll sowohl das Löschen als auch das Wiederherstellen einer Inventur an dasselbe Recht koppeln, da beide Operationen denselben fachlichen Eingriff (Statusänderung) darstellen.
Ergebnis: Benutzer ohne `DROP_INVENTORY` kann weder löschen noch wiederherstellen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\InventoryManagement\InventoryBL.cs (Zeilen 98-109) - Begründung: durchgesetzte Rechteprüfung bei beiden Richtungen des Statuswechsels.
Prüfidee: Benutzer ohne Recht versucht gelöschte Inventur wiederherzustellen → Ablehnung.
Tracelinks: SyRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-021
Titel: PartialCommissionOrderBL: getrennte Rechteprüfung für Anlage und Löschung
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente PartialCommissionOrderBL
Vorbedingung: Teilkommissionierung wird angelegt oder gelöscht.
Fakt: Zeilen 135/170 prüfen `CREATE_PARTIAL_COMMISSION_FOR_ORDER` bei Anlage; Zeilen 426/453 prüfen `DELETE_PARTIAL_COMMISSION_FOR_ORDER` bei Löschung — zwei unabhängige Prüfpunkte.
Aussage: Die Komponente soll Anlage- und Löschrecht getrennt und unabhängig voneinander prüfen.
Ergebnis: Ein Benutzer kann eines der beiden Rechte besitzen, ohne automatisch auch das andere zu haben.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\Commissions\PartialCommissionOrderBL.cs (Zeilen 135, 170, 426, 453) - Begründung: enthält beide unabhängigen Prüfpunkte.
Prüfidee: Benutzer mit nur Anlage-Recht versucht Löschung → Ablehnung; umgekehrter Test analog.
Tracelinks: SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-022
Titel: OrderSuggestionListBL: SQL-Aggregation aus Bestand/Bedarf/Zulauf
Ebene: SwRS
Typ: Daten
Akteur: Komponente OrderSuggestionListBL
Vorbedingung: Bestellvorschlagsliste wird berechnet.
Fakt: Ca. 10 vordefinierte Roh-SQL-Strings (`_sqlArticle`, `_sqlSpec`, `_sqlOrder`, `_sqlOrderComplete`, `_sqlWH`, `_sqlFreeSpec`, `_sqlFreeArticlePerWH`, `_sqlDistri`, `_sqlLastArticlUse`, `_sqlImprtedPM`, `_sqlAktionsPreis`, `_sqlPPStockIntake`) werden über `Session.Advanced.RawSqlAccess.ExecuteQuery<T>()` gegen Legacy-Tabellen/-Views (`AufPos`, `AufKopf`, `BestPos2`, `BestKopf2`, `Artik`, `NebenlagerArtikel`, `cvw_ArticleCount`, `cvw_ConsignmentArticleQuantity`) ausgeführt.
Aussage: Die Komponente soll Bestand, offenen Auftragsbedarf und offenen Bestellzulauf über SQL-Abfragen gegen die produktiven Legacy-Tabellen kombinieren, statt über die NHibernate-ORM-Abstraktion.
Ergebnis: Bestellvorschlagsliste enthält je Artikel eine berechnete Nachbestellmenge.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Purchasing\OrderSuggestionList\OrderSuggestionListBL.cs - Begründung: enthält die tatsächlichen SQL-Strings und deren Ausführung.
Prüfidee: Vergleich der berechneten Vorschlagsmenge gegen manuell nachgerechneten Erwartungswert für einen Testartikel.
Tracelinks: SyRS-014
Konsolidierung: nein
Status: belegt; Workaround (Legacy-DB-Schema-Abhängigkeit statt ORM)
```
```
ID: SwRS-023
Titel: EDIDispatcherBL.CreateEDISuggestionOrderAsync Distributor-Dispatch
Ebene: SwRS
Typ: Schnittstelle
Akteur: Komponente EDIDispatcherBL
Vorbedingung: EDI-Bestellvorschlag soll an konfigurierten Distributor übermittelt werden.
Fakt: Zeilen 56-70 selektieren anhand `ediConfigurations.EdiDataType`/`EDIMultidistributors` den passenden distributorspezifischen Dokumentersteller.
Aussage: Die Methode soll den zu verwendenden Dokumentersteller ausschließlich aus der Konfiguration ableiten, ohne fest verdrahtete Distributor-Logik im Aufrufer.
Ergebnis: Änderung der Distributor-Konfiguration führt ohne Codeänderung zu korrektem Zielformat.
Belege:
- [PRIMÄR] src\backend\Centron.BL\EDI\EDIDispatcherBL.cs (Zeilen 56-70) - Begründung: enthält die tatsächliche konfigurationsgesteuerte Dispatch-Logik.
Prüfidee: Konfigurationswechsel auf anderen Distributor → anderer Dokumentersteller wird aufgerufen (Unit-Test mit Mock).
Tracelinks: SyRS-015
Konsolidierung: nein
Status: belegt
```
---
## Block D — Finances
```
ID: SwRS-024
Titel: OnlineBankingAccountTransactionsBL.SaveOnlineBankingAccountTransactions Duplikatserkennung
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente OnlineBankingAccountTransactionsBL
Vorbedingung: Bankumsatz wird importiert.
Fakt: Zeilen 294-340 prüfen auf bereits vorhandene Transaktion mit identischer Kombination aus Konfiguration/Datum/Betrag/IBAN/Beschreibung und geben bei Fund eine Warnung statt eines Fehlers zurück (kein Hard-Reject, sondern Soft-Warnung — Import wird nicht automatisch verhindert).
Aussage: Die Methode soll doppelte Transaktionsimporte erkennen und den Anwender warnen; die endgültige Entscheidung über den Doppelimport verbleibt beim Anwender (Soft-Check, kein Hard-Block).
Ergebnis: Import einer bereits vorhandenen Transaktion erzeugt eine Warnmeldung.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (Zeilen 294-340) - Begründung: Fakturierungs-/Zahlungsverkehrslogik, PRIMÄR-Beleg zwingend und vorhanden.
Prüfidee: Identischen Transaktionsdatensatz zweimal importieren → zweiter Import löst Warnung aus; [HYPOTHESE]: ob der Anwender den Doppelimport trotzdem bestätigen kann, wurde nicht bis zur UI-Ebene zurückverfolgt — siehe Hypothesen.md.
Tracelinks: SyRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-025
Titel: OnlineBankingAccountTransactionsBL.BookAmountToAssignedInvoice Verbuchungsregel
Ebene: SwRS
Typ: funktional
Akteur: Komponente OnlineBankingAccountTransactionsBL
Vorbedingung: Transaktion ist einer Rechnung zugeordnet und soll verbucht werden.
Fakt: Zeilen 1042-1086: Verbuchung erfolgt nur, wenn Rechnung `Active` ist, oder `Completed` während eines Undo-Vorgangs, oder der Betrag negativ ist (Rückbuchung/Chargeback); berechnet `newPaidFC` und markiert die Rechnung als bezahlt, sobald `newPaidFC >= DemandedGrossAmount`.
Aussage: Die Methode soll eine Verbuchung nur unter den drei definierten Bedingungen zulassen und den Zahlstatus ausschließlich anhand der berechneten Summe, nicht anhand eines einzelnen Zahlungsereignisses, bestimmen.
Ergebnis: Verbuchung außerhalb der drei zulässigen Fälle wird nicht durchgeführt; Zahlstatus berücksichtigt kumulierte Zahlungen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (Zeilen 1042-1086) - Begründung: PRIMÄR-Beleg für Fakturierungslogik, durchgesetzte Bedingungsprüfung.
Prüfidee: Verbuchungsversuch auf eine bereits `Canceled`-Rechnung mit positivem Betrag → muss abgelehnt werden.
Tracelinks: SyRS-016, SyRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-026
Titel: PaymentsBL.DeleteIncomingPayment Rechteprüfung vor Stornierung
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente PaymentsBL
Vorbedingung: Erfasste Eingangszahlung soll gelöscht/storniert werden.
Fakt: Zeilen 43-44: `if (loggedInUser.User.HasUserRight(UserRightsConst.Controlling.Finances.INCOMING_PAYMENT_TRANSACTIONS) == false) return Result.AsError("Sie haben nicht das Recht 'Zahlungseingang.", DefaultMessageCodes.RightCheckFailed);` — vor jeder weiteren Verarbeitung.
Aussage: Die Methode soll die Rechteprüfung als ersten Schritt durchführen, bevor der bezahlte Betrag auf der Rechnung zurückgesetzt wird.
Ergebnis: Nicht berechtigter Löschversuch hinterlässt die Rechnung unverändert.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\Payments\PaymentsBL.cs (Zeilen 43-44) - Begründung: PRIMÄR-Beleg, Fakturierungslogik.
Prüfidee: Benutzer ohne Recht versucht Löschung → Rechnung/`PaidFC` bleibt exakt unverändert (nicht nur Fehlermeldung prüfen, sondern Datenzustand).
Tracelinks: SyRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-027
Titel: ReceiptWebServiceBL berechnet CanChangeDateInInvoices/CanChangeDateInDeliveryLists serverseitig
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente ReceiptWebServiceBL
Vorbedingung: Client fragt Berechtigungsstatus für Datumsänderung ab.
Fakt: Zeilen 994-1000: `result.CanChangeDateInDeliveryLists = rights.Any(f => f.I3D == UserRightsConst...DeliveryList.CAN_CHANGE_DATE)`; `result.CanChangeDateInInvoices = rights.Any(f => f.I3D == UserRightsConst...Invoice.CAN_CHANGE_DATE)` — Rechte-IDs 20400141 bzw. 20400143.
Aussage: Die Komponente soll die Berechtigung serverseitig aus den tatsächlichen Benutzerrechten berechnen und dem Client als Ergebnis übergeben, statt dem Client die Prüfung zu überlassen.
Ergebnis: Client erhält ein serverseitig berechnetes Berechtigungsflag, das nicht durch Client-Manipulation veränderbar ist (der Flag-Wert selbst schon; siehe SyRS-018 zur offenen Frage der Durchsetzung im Schreibpfad).
Belege:
- [PRIMÄR] src\backend\Centron.WebServices.Core\WebServices\Sales.Receipts\ReceiptWebServiceBL.cs (Zeilen 994-1000) - Begründung: serverseitige Berechnung.
Prüfidee: Vergleich der von zwei unterschiedlich berechtigten Testbenutzern gelieferten Flag-Werte.
Tracelinks: SyRS-018
Konsolidierung: nein
Status: belegt
```
---
## Block E — Security / Rechte / Authentifizierung
```
ID: SwRS-028
Titel: AppRightsBL.HasUserRight mit Caching und Fail-Closed-Erweiterung UserRightsExt
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente AppRightsBL / UserRightsExt
Vorbedingung: BL-Methode prüft ein Benutzerrecht.
Fakt: `AppRightsBL.HasUserRight(appUserI3D, rightID)` liest via `Session.Advanced.Cache.GetOrAdd($"AllRightsFromAppUser{appUserI3D}", ...)` gecachte Rechte-IDs aus SQL gegen `Sichtrus`/`Sichmemb`; `UserRightsExt.HasUserRight` (Erweiterungsmethode) kapselt den Aufruf in try/catch und liefert bei Exception `false`.
Aussage: Die Komponenten sollen Rechteprüfungen mit Caching beschleunigen, dabei aber im Fehlerfall (Exception, z. B. DB-Verbindungsproblem) grundsätzlich `false` (kein Recht) statt einer Exception oder eines optimistischen `true` liefern.
Ergebnis: Ausnahmesituationen während der Rechteprüfung führen zu Zugriffsverweigerung.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Rights\AppRightsBL.cs (~Zeile 644) - Begründung: zentrale Prüfimplementierung.
- [PRIMÄR] src\backend\Centron.BL\Administration\Rights\UserRightsExt.cs (try/catch → false) - Begründung: sicherheitskritisches Fail-Closed-Verhalten, PRIMÄR-Beleg zwingend und vorhanden.
Prüfidee: Rechteprüfung mit simuliertem DB-Fehler → Rückgabewert `false`.
Tracelinks: SyRS-019
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-029
Titel: UserRightsConst: manuell inkrementierter ID-Zähler für neue Rechte
Ebene: SwRS
Typ: nicht-funktional
Akteur: Entwicklungsteam
Vorbedingung: Neues Recht wird der Konstantenklasse hinzugefügt.
Fakt: Header-Kommentar "NEW .NET MODULE RIGHTS START AT 20800000 / NEXT ID: 20800174" in `UserRightsConst.cs`; keine automatisierte (z. B. DB-Sequenz-basierte) ID-Vergabe gefunden.
Aussage: Die Klasse soll neue Rechte-IDs eindeutig vergeben; der aktuelle Mechanismus (manuell gepflegter Kommentar) erreicht dies nur, solange alle Entwickler diszipliniert den Kommentar aktuell halten.
Ergebnis: Eindeutigkeit ist aktuell durch Konvention, nicht durch technischen Zwang sichergestellt.
Belege:
- [PRIMÄR] src\webservice\Centron.WebServices.Core\EntitiesWrongPlace\Administration\Rights\UserRightsConst.cs (Header-Kommentar) - Begründung: unmittelbarer, technischer Beleg für den Vergabemechanismus.
Prüfidee: Code-Review-Historie prüfen: gab es je einen ID-Kollisionsfall bei parallelen Pull-Requests? (retrospektive Prüfidee)
Tracelinks: SyRS-020
Konsolidierung: nein
Status: belegt; Workaround
```
```
ID: SwRS-030
Titel: AuthenticatorFactory wählt Authentifizierungsverfahren nach Konfiguration
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente AuthenticatorFactory
Vorbedingung: Anmeldeversuch wird entgegengenommen.
Fakt: `AuthenticatorFactory` liefert eine von `BasicAuthenticator`, `ActiveDirectoryAuthenticator`, `OpenIdConnectAuthenticator`, `WebAccountAuthenticator` (sowie `FailingAuthenticator`/`FallbackAuthenticator` für Fehlerfälle).
Aussage: Die Factory soll das zu verwendende Authentifizierungsverfahren eindeutig und konfigurationsgesteuert bestimmen.
Ergebnis: Für eine gegebene Konfiguration wird immer dasselbe Verfahren verwendet.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\Auth\AuthenticatorFactory.cs - Begründung: enthält die tatsächliche Auswahllogik.
Prüfidee: Konfigurationswechsel AD → OIDC → Verhalten der Factory ändert sich entsprechend (Unit-Test).
Tracelinks: SyRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-031
Titel: BasicAuthenticator verwendet unsalted SHA-1 zur Passwortprüfung [Sicherheitsrisiko]
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente BasicAuthenticator
Vorbedingung: Benutzer meldet sich mit Benutzername/Passwort an.
Fakt: Zeile 46: `var decodedPassword = SHA1Decoder.GetDecodedSHA1String(Auth.Password.ToString());`, verglichen gegen `AppUser.Password`; Zeile 48 trägt den Code-Kommentar `// TODO the password should be salted!!!`. Implementierung: `src\backend\Centron.Common\TextCoding\SHA1Decoder.cs` — unsalted SHA-1. Derselbe Mechanismus in `UsersBL.cs` (Zeilen 65, 88) bei Passwortänderung.
Aussage: Die Komponente soll Passwörter mit einem Verfahren speichern/prüfen, das gegen Rainbow-Table- und GPU-Brute-Force-Angriffe widerstandsfähig ist (z. B. gesalzenes, iteriertes Hashing wie PBKDF2/bcrypt/Argon2). Der aktuelle Zustand (unsalted SHA-1, vom Entwicklerteam selbst als TODO markiert) erfüllt dies **nicht** und stellt eine dokumentierte Sicherheitslücke dar.
Ergebnis: Aktuell: identische Passwörter erzeugen identische Hashes ohne Salt, wodurch Rainbow-Table-Angriffe bei DB-Kompromittierung erleichtert werden. Soll-Zustand für Zielsystem: gesalzenes, adaptives Hashverfahren.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\Auth\BasicAuthenticator.cs (Zeilen 46, 48) - Begründung: unmittelbar durchgesetzte, schwache Hash-Prüfung; Authentifizierung ist höchste Sicherheitsstufe, PRIMÄR-Beleg zwingend und vorhanden.
- [PRIMÄR] src\backend\Centron.Common\TextCoding\SHA1Decoder.cs - Begründung: technische Implementierung des unsalted SHA-1.
- [KONTEXT] BasicAuthenticator.cs Zeile 48 (Code-Kommentar "TODO the password should be salted!!!") - Begründung: bestätigt, dass das Entwicklerteam die Schwäche selbst kennt, aber noch nicht behoben hat.
Prüfidee: Sicherheitsreview/Penetrationstest: identische Testpasswörter zweier Benutzer erzeugen identischen gespeicherten Hash (Nachweis fehlenden Salts).
Tracelinks: SyRS-021
Konsolidierung: nein
Status: belegt; Workaround (bekannte, vom Team selbst markierte Sicherheitslücke — hohe Priorität für Migrationsentscheidung)
```
```
ID: SwRS-032
Titel: TicketBL: gerätegebundener Salt und konfigurierbare Ablaufzeit für Session-Tickets
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente TicketBL
Vorbedingung: Nach erfolgreicher Authentifizierung wird ein Ticket ausgestellt.
Fakt: Zeilen 166-169: `CryptoUtils.CreateSalt(32)` + `CryptoUtils.CreatePasswordHash(deviceId, salt)`; Ablaufzeit über `ExpirationKind.FromSettings`/`OneDay`.
Aussage: Die Komponente soll jedes Ticket an ein Gerät binden (Salt-basiert) und nach konfigurierbarer Zeit ungültig werden lassen.
Ergebnis: Ticket ist nach Ablauf oder bei Verwendung von einem anderen Gerät ungültig.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\TicketBL.cs (Zeilen 166-169) - Begründung: durchgesetzte Salt-/Ablaufmechanik.
Prüfidee: Ticket auf simuliertem Fremdgerät verwenden → Ablehnung; Ticket nach Ablaufzeit verwenden → Ablehnung.
Tracelinks: SyRS-021, SyRS-022
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-033
Titel: TwoFactorAuthBL: austauschbare Validatoren (E-Mail/RADIUS)
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente TwoFactorAuthBL
Vorbedingung: 2FA ist aktiviert und erster Faktor wurde erfolgreich geprüft.
Fakt: `TwoFactorAuthBL` orchestriert `ITwoFactorValidator`-Implementierungen (`EmailTwoFactorValidator`, `RadiusTwoFactorValidator` mit eigenem `RadiusClient`/`RadiusPaketParser`); Aktivierung über `WebServiceConfigHelper.Current.TwoFactorAuthEnabled`.
Aussage: Die Komponente soll den zweiten Faktor über eine austauschbare Validator-Schnittstelle prüfen, sodass weitere Verfahren ergänzt werden können, ohne die Orchestrierungslogik zu ändern.
Ergebnis: Bei aktivierter 2FA wird erst nach erfolgreicher Validator-Prüfung eine vollständige Anmeldung gewährt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\TwoFactor\TwoFactorAuthBL.cs, EmailTwoFactorValidator.cs, RadiusTwoFactorValidator.cs - Begründung: durchgesetzte zweite Prüfstufe.
Prüfidee: 2FA aktiv, korrekter erster Faktor, falscher zweiter Faktor → Anmeldung wird verweigert.
Tracelinks: SyRS-021
Konsolidierung: Kandidat: Verhältnis zu separatem Modul `TwoFactorAuthenticator\TwoFactorAuthenticationBL.cs` ungeklärt — siehe Hypothesen.md.
Status: belegt
```
```
ID: SwRS-034
Titel: PasswordManagementAccessLogBL protokolliert jeden Zugriff mit ActionType/Date/EmployeeI3D
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente PasswordManagementAccessLogBL
Vorbedingung: Gespeichertes Passwort wird gelesen.
Fakt: Bei jedem Zugriff wird ein `PasswordManagementAccessLog`-Datensatz mit `ActionType`, `Date`, `EmployeeI3D` erzeugt, als Teil des Zugriffspfads (nicht optional/deaktivierbar laut Codebefund).
Aussage: Die Komponente soll jeden Lesezugriff auf ein gespeichertes Passwort unmittelbar und vollständig protokollieren.
Ergebnis: Nach jedem Zugriff existiert ein Protokolleintrag mit Benutzer- und Zeitreferenz.
Belege:
- [PRIMÄR] src\backend\Centron.BL\PasswordManagementArea\PasswordManagementAccessLogBL.cs - Begründung: durchgesetzte Protokollierung im Zugriffspfad.
Prüfidee: Zugriff auf Testpasswort → Protokolleintrag mit korrektem `EmployeeI3D` und aktuellem Zeitstempel.
Tracelinks: SyRS-023
Konsolidierung: nein
Status: belegt
```
---
## Block F — Web-Kanäle
```
ID: SwRS-035
Titel: Getrennte Login-Komponenten CustomerAuthPage / AuthPage / OutlookAuthPage
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente Nexus-Auth-Subsystem
Vorbedingung: Benutzer (intern, Kunde oder Outlook-Add-In) meldet sich an Nexus an.
Fakt: Drei getrennte Blazor-Seiten (`AuthPage.razor`, `OutlookAuthPage.razor`, `CustomerAuthPage.razor`) mit jeweils eigenem Authentifizierungspfad (`WebAccountAuthenticator` für Kunden).
Aussage: Die Komponenten sollen sicherstellen, dass ein Kundenzugang nicht denselben Anmeldepfad wie ein interner Mitarbeiterzugang durchläuft.
Ergebnis: Kunde kann sich ausschließlich über `CustomerAuthPage` mit dem `WebAccountAuthenticator`-Pfad anmelden.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\Auth\WebAccountAuthenticator.cs - Begründung: eigenständiger Authentifizierungspfad.
- [SEKUNDÄR] src\nexus\CentronNexus\Shared\Auth\CustomerAuthPage.razor, AuthPage.razor, OutlookAuthPage.razor - Begründung: UI-seitige Bestätigung der Trennung.
Prüfidee: Versuch, sich als Kunde über den internen Login-Pfad anzumelden → muss fehlschlagen bzw. ist technisch nicht vorgesehen.
Tracelinks: SyRS-024
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-036
Titel: WebCartShopPage.razor: [AuthorizeLicense(WebCart2)] als serverseitige Blazor-Server-Prüfung
Ebene: SwRS
Typ: Sicherheit
Akteur: Komponente WebCartShopPage
Vorbedingung: Web-Account ruft die WebCart-Shop-Seite auf.
Fakt: Attribut `[AuthorizeLicense(nameof(LicenseGuids.WebCart2))]` auf der Seite; Blazor Server führt die Seitenlogik serverseitig aus (kein clientseitig umgehbarer WebAssembly-Code).
Aussage: Die Komponente soll den Seitenaufruf bereits serverseitig verweigern, bevor Seiteninhalte an den Client übertragen werden.
Ergebnis: Client ohne gültige Lizenz erhält keine Shop-Inhalte, unabhängig vom Aufrufweg (Navigation oder direkter URL-Aufruf).
Belege:
- [PRIMÄR] src\nexus\CentronNexus\WebCart\WebCartShopPage.razor (Attribut) - Begründung: serverseitig wirksame Zugriffsprüfung im Blazor-Server-Modell.
Prüfidee: Direkter URL-Aufruf `/webcart/shop` ohne Lizenz → keine Artikel-/Preisdaten werden übertragen (Netzwerk-Mitschnitt).
Tracelinks: SyRS-025
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-037
Titel: CurrentCartService bindet Warenkorb an Sitzung/Kunde
Ebene: SwRS
Typ: Daten
Akteur: Komponente CurrentCartService
Vorbedingung: Kunde nutzt WebCart-Warenkorb.
Fakt: `ICurrentCartService` wählt den aktuellsten `ReceiptCartDTO` des Kunden oder legt automatisch einen neuen an (`CreateNewReceiptCart`), ohne dass der Kunde explizit einen Warenkorb anlegen muss.
Aussage: Die Komponente soll jedem Kunden automatisch genau einen aktiven Warenkorb zuordnen, ohne manuellen Anlageschritt.
Ergebnis: Kunde findet beim Aufruf von WebCart stets einen nutzbaren Warenkorb vor.
Belege:
- [PRIMÄR] src\nexus\CentronNexus\WebCart\Helpers\CurrentCartService.cs - Begründung: enthält die tatsächliche Auswahl-/Anlagelogik.
Prüfidee: Erster Aufruf ohne bestehenden Warenkorb → neuer Warenkorb wird automatisch angelegt und zurückgegeben.
Tracelinks: SyRS-025
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-038
Titel: CI/CD-Pipeline build.yml erzeugt und signiert alle Auslieferungsartefakte
Ebene: SwRS
Typ: nicht-funktional
Akteur: CI/CD-Komponente (GitHub Actions)
Vorbedingung: Push/Merge auf relevanten Branch.
Fakt: `.github\workflows\build.yml` baut WPF-Client, Web-Service-Host (+Connection Manager) und Nexus-Host, erzeugt WiX-MSIs bzw. Docker-Image, verifiziert Authenticode-Signaturen, lädt Artefakte in die "SoftwareBuilds"-Umgebung hoch.
Aussage: Die Pipeline soll bei jedem relevanten Push alle drei Artefakttypen ohne manuellen Eingriff bauen, signieren und verifizieren.
Ergebnis: Nach jedem erfolgreichen Pipeline-Lauf liegen signierte, verifizierte Artefakte vor.
Belege:
- [PRIMÄR] .github\workflows\build.yml - Begründung: enthält den tatsächlichen automatisierten Ablauf.
- [SEKUNDÄR] docker\Dockerfile, deployment\centron\*\Product.wxs - Begründung: konkrete Paketierungsdefinitionen, die die Pipeline referenziert.
Prüfidee: Pipeline-Lauf beobachten: Signaturverifikation muss für alle drei Artefakte grün sein, sonst Pipeline-Abbruch.
Tracelinks: SyRS-026, SyRS-027
Konsolidierung: nein
Status: belegt
```
---
## Block G — Externe Integrationen (leichtere Analysetiefe)
```
ID: SwRS-039
Titel: ITscopeApi kapselt HTTP-Statuscodes in clientspezifische Exceptions
Ebene: SwRS
Typ: Schnittstelle
Akteur: Komponente ITscopeApi
Vorbedingung: Externer Aufruf an itscope.com liefert einen Fehlerstatus.
Fakt: Zeilen 293-314: `HttpStatusCode.Unauthorized` → `ITscopeException("Der API-Key ist ungültig.")`; `HttpStatusCode.NotFound` → leeres Ergebnis (Soft-Fail, kein Retry).
Aussage: Die Komponente soll HTTP-Fehlerstatuscodes in aussagekräftige, deutschsprachige Exceptions bzw. definiertes Leerergebnis übersetzen, statt die rohe HTTP-Exception weiterzureichen.
Ergebnis: Aufrufende Module erhalten eine domänenspezifische Fehlerauskunft statt eines rohen `WebException`.
Belege:
- [PRIMÄR] src\apis\Centron.APIs.ITscopeDataAccess\ITscopeApi.cs (Zeilen 293-314) - Begründung: durchgesetzte Fehlerübersetzung.
Prüfidee: Simulierter 401-Response → `ITscopeException` mit definierter Meldung; simulierter 404 → leere Liste statt Exception.
Tracelinks: SyRS-028
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-040
Titel: DocuFormRestApiClient: OAuth2-Token-Beschaffung vor jedem Geräteabruf
Ebene: SwRS
Typ: Schnittstelle
Akteur: Komponente DocuFormRestApiClient
Vorbedingung: Geräte-/Zählerdaten sollen von docuFORM abgerufen werden.
Fakt: `OAuthHelper` (`RequestAuthorization`/`RequestToken`) beschafft ein OAuth2-Token gegen `/auth/v2/token`, bevor Aufrufe gegen `/dfmserver/v2/devices` erfolgen; `SocketsHttpHandler { MaxConnectionsPerServer = 20 }` begrenzt die Verbindungsanzahl.
Aussage: Die Komponente soll vor jedem Datenabruf ein gültiges OAuth2-Token sicherstellen und die Anzahl gleichzeitiger Verbindungen zum externen Dienst begrenzen.
Ergebnis: Geräteabruf erfolgt nur mit gültigem Token; Verbindungsanzahl zum externen Dienst bleibt begrenzt.
Belege:
- [PRIMÄR] src\apis\Centron.Api.docuFORM\DocuFormRestApiClient.cs, DocuFormRestApiConstants.cs - Begründung: durchgesetzter Token-Beschaffungspfad und Verbindungslimit.
Prüfidee: Abruf mit abgelaufenem Token → automatische Erneuerung vor erneutem Versuch (bzw. [HYPOTHESE], falls kein automatischer Retry gefunden — siehe Hypothesen.md).
Tracelinks: SyRS-028
Konsolidierung: nein
Status: belegt
```
@@ -0,0 +1,548 @@
# System Requirements Specification (SyRS)
Ebene: Systemverhalten, Schnittstellen, Performance-, Sicherheitsanforderungen. Nicht-funktionale Anforderungen sind zusätzlich einem Qualitätsmerkmal nach **ISO/IEC 25010** zugeordnet (Feld `ISO25010`). Tracelinks verweisen rückwärts auf StRS und vorwärts auf SwRS.
---
## Block A — Belegkette / Order-to-Cash (System-Ebene)
```
ID: SyRS-001
Titel: Einheitliche Beleg-Verarbeitungs-Engine für alle Belegarten
Ebene: SyRS
Typ: funktional
Akteur: Web-Service (BL-Schicht)
Vorbedingung: Ein Beleg beliebiger Art (Angebot/Auftrag/Lieferschein/Rechnung/Gutschrift) liegt zur Verarbeitung vor.
Fakt: `ReceiptBL` ist die einzige Verarbeitungsklasse für alle Belegarten; belegartspezifisches Verhalten wird über `IReceiptSpecificLogic`-Implementierungen (Strategy-Pattern) injiziert statt über belegartspezifische Subklassen von `ReceiptBL` selbst.
Aussage: Das System soll Änderungen an gemeinsamer Belegverarbeitungslogik (z. B. Validierung, Statuswechsel) zentral an einer Stelle implementieren und über alle Belegarten hinweg konsistent wirksam werden lassen, ohne belegartspezifischen Code zu duplizieren.
Ergebnis: Eine Änderung in `ReceiptBL` wirkt sich konsistent auf Angebot, Auftrag, Lieferschein, Rechnung usw. aus.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Receipts\ReceiptBL.cs - Begründung: zentrale, tatsächlich für alle Belegarten aufgerufene Verarbeitungsklasse.
- [SEKUNDÄR] src\backend\Centron.Interfaces\Sales.Receipts (IReceiptSpecificLogic und Implementierungen) - Begründung: belegt das Strategy-Pattern als Erweiterungsmechanismus.
Prüfidee: Code-Review: Suche nach belegartspezifischer if/else- oder switch-Verzweigung innerhalb `ReceiptBL` außerhalb der `IReceiptSpecificLogic`-Aufrufe (sollte nicht signifikant vorkommen).
Tracelinks: StRS-001; SwRS-001, SwRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-002
Titel: Konsistente Statuspersistenz über Belegarten hinweg (Datenintegrität)
Ebene: SyRS
Typ: Daten
Akteur: Web-Service (BL-Schicht) / Datenbank
Vorbedingung: Beleg wird gespeichert oder automatisch weiterverarbeitet.
Fakt: Alle Belegarten nutzen denselben `ReceiptState`-Enumwert (Active/Completed/Canceled); der Zustandswechsel wird zentral in `AutomaticallyCloseReceiptHelperBL` anhand von Restmengen berechnet statt dezentral je Belegart.
Aussage: Das System soll den Belegstatus als gemeinsames, für alle Belegarten identisch strukturiertes Datenfeld führen, damit modulübergreifende Auswertungen (z. B. "alle offenen Belege") ohne belegartspezifische Sonderlogik möglich sind.
Ergebnis: Abfragen über `ReceiptState` liefern für alle Belegarten konsistente, vergleichbare Ergebnisse.
Belege:
- [PRIMÄR] src\backend\Centron.Interfaces\Sales.Receipts\ReceiptState.cs - Begründung: ein einziges, geteiltes Enum für alle Belegarten.
- [SEKUNDÄR] src\backend\Centron.BL\Sales\Receipts\Internal\AutomaticallyCloseReceiptHelperBL.cs - Begründung: zentrale Berechnungslogik statt Duplikation je Belegart.
Prüfidee: Datenbankabfrage über alle Belegtabellen mit `ReceiptState`-Spalte liefert konsistente Wertemenge {1,2,3}.
Tracelinks: StRS-001, StRS-005; SwRS-003
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-003
Titel: Zeitlich befristete, einmalig gültige Signier-Tokens für Web-Dokumentenfreigabe
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service / Kunde (anonym, tokenbasiert)
Vorbedingung: Ein Angebot/Dokument wurde zur Kundensignatur freigegeben.
Fakt: `SharedDocumentBL.GenerateTokenForDocument` verweigert die Erzeugung eines neuen Tokens, solange bereits ein aktiver, unsignierter Vorgang für denselben Beleg existiert ("Es existiert bereits ein aktiver Signierungs-Ablauf"); das Ablaufdatum wird aus `SharedDocumentSettingsDTO.OfferSignExpiredDateCount` berechnet.
Aussage: Das System soll für jeden Beleg zu jedem Zeitpunkt höchstens einen aktiven, nicht abgelaufenen Signiervorgang zulassen und den Gültigkeitszeitraum konfigurierbar begrenzen.
Ergebnis: Zweiter Signieranstoß für denselben Beleg bei bestehendem aktivem Vorgang wird abgelehnt; abgelaufene Tokens sind nicht mehr nutzbar.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\FileManagement\SharedDocumentBL.cs (GenerateTokenForDocument, Zeilen 128-130) - Begründung: durchgesetzte Ein-Vorgang-Regel, hochkritisch für Rechtsverbindlichkeit der Angebotsannahme → PRIMÄR-Beleg vorhanden.
Prüfidee: Zweiten Signiervorgang für denselben Beleg anstoßen, während erster aktiv ist → Ablehnung mit definierter Fehlermeldung.
Tracelinks: StRS-002; SwRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-004
Titel: Serverseitige Ablehnung abgelaufener oder bereits verwendeter Signier-Tokens
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Ein Token für einen Signiervorgang wird per öffentlichem Link aufgerufen.
Fakt: `SharedDocumentBL.GetSharedDocumentByToken` prüft `ExpiredDate < DateTime.Now` → Fehler "Die Signierungsanfrage ist bereits abgelaufen."; und `IsSigned == true` → Fehler "Dokument wurde bereits signiert.".
Aussage: Das System soll bei jedem Zugriff auf einen Signier-Link serverseitig sowohl Ablauf als auch Mehrfachnutzung prüfen, unabhängig davon, ob der Client (Browser) diese Prüfung bereits vorgenommen hat.
Ergebnis: Zugriff mit abgelaufenem oder bereits verwendetem Token wird serverseitig abgelehnt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\FileManagement\SharedDocumentBL.cs (GetSharedDocumentByToken, Zeilen 405-409) - Begründung: serverseitige, nicht umgehbare Prüfung vor Auslieferung sensibler Vertragsdaten.
Prüfidee: Abgelaufenen Token direkt per HTTP-Request aufrufen (ohne UI) → Server muss ablehnen.
Tracelinks: StRS-002; SwRS-005, SwRS-006
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-005
Titel: Datenbankseitig durchgesetzte Unveränderlichkeit festgeschriebener Rechnungen
Ebene: SyRS
Typ: Daten
Akteur: Datenbank / Web-Service
Vorbedingung: Rechnung mit `IsFixed = 1` liegt vor.
Fakt: Spalte `RechKopf.IsFixed` ist als `NOT NULL DEFAULT(0)` per Migrationsskript definiert; die Anwendungslogik (`ReceiptInvoiceBL.FixInvoice`) ist der einzige Pfad, der das Flag auf 1 setzt, und lehnt danach jede erneute Festschreibung ab.
Aussage: Das System soll den Festschreibungsstatus einer Rechnung als verpflichtendes, nicht auf NULL setzbares Datenbankfeld führen, sodass der Zustand "nicht festgeschrieben" niemals unspezifiziert (NULL) sein kann.
Ergebnis: `IsFixed` ist für jede Rechnung eindeutig 0 oder 1, niemals unbestimmt.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Scripts\ScriptMethods\SqlStatements\SQLScriptCollection2.xml (Skript #10208) - Begründung: technischer DB-Constraint, höchste Evidenzstufe für sicherheits-/buchführungsrelevante Anforderung.
Prüfidee: Direkter INSERT ohne Angabe von `IsFixed` gegen Testdatenbank → DB muss Default 0 setzen, NULL darf nicht möglich sein.
Tracelinks: StRS-003; SwRS-007, SwRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-006
Titel: Zentrale, wiederverwendete Steuerberechnungskomponente
Ebene: SyRS
Typ: funktional
Akteur: Web-Service (alle Clients: WPF, Nexus, API)
Vorbedingung: Beleg mit Positionen und Steuersätzen liegt in beliebigem Client vor.
Fakt: `CalculationUtils.CalculateTaxTotalPrice`/`CalculateGrossPrice` liegt in `Centron.Interfaces` (nicht client-spezifisch) und wird laut Recherche von allen Belegarten verwendet; Rundung ist explizit `MidpointRounding.AwayFromZero` mit 2 Nachkommastellen.
Aussage: Das System soll die Umsatzsteuerberechnung in genau einer Komponente kapseln, die von allen Clients (Desktop, Web, API) und allen Belegarten aufgerufen wird, um abweichende Rundungs- oder Berechnungsergebnisse zwischen Clients zu verhindern.
Ergebnis: Identische Eingabewerte (Netto, Steuersatz, Rabatt, Währungsfaktor) liefern client-unabhängig identische Steuer-/Bruttobeträge.
Belege:
- [PRIMÄR] src\backend\Centron.Interfaces\DataExchange.BookKeeping\CalculationUtils.cs - Begründung: einzige, geteilte Implementierung, keine Duplikate pro Client identifiziert.
Prüfidee: Gleiche Testwerte über WPF-Client und Nexus-Web-Client eingeben → identisches Ergebnis.
Tracelinks: StRS-004; SwRS-009, SwRS-010
Konsolidierung: nein
Status: belegt
```
---
## Block B — Helpdesk / RMA / Automatisierung (System-Ebene)
```
ID: SyRS-007
Titel: Serverseitige, client-unabhängige Autorisierung von Ticket-Operationen
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Eine Ticket-Änderungsoperation (Anlage/Bearbeitung/Schließen) wird angestoßen, gleich über welchen Client.
Fakt: `HelpdeskBL.CheckUserRigths` wird im Speicherpfad (`Save`/`DoBeforeSave`) aufgerufen, also serverseitig im BL, unabhängig davon, ob der Aufruf vom WPF-Client, von Nexus oder von der API kommt.
Aussage: Das System soll jede Ticket-Änderungsoperation unabhängig vom aufrufenden Client an derselben zentralen serverseitigen Rechteprüfung vorbeiführen.
Ergebnis: Ein direkter API-Aufruf ohne UI unterliegt denselben Rechteprüfungen wie eine UI-Aktion.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (Save/DoBeforeSave, CheckUserRigths) - Begründung: Prüfung liegt in der BL-Schicht, nicht im UI-Code.
Prüfidee: Direkter API-Aufruf zum Schließen eines Tickets ohne `CLOSE_REQUEST`-Recht → serverseitige Ablehnung.
Tracelinks: StRS-006, StRS-009; SwRS-011, SwRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-008
Titel: Ergebnismengen-Filterung nach einschränkenden Rechten (Datenscoping)
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Benutzer mit einschränkendem Recht (nur eigene/nur eigene Filiale/nur eigene Abteilung) fragt eine Ticketliste ab.
Fakt: `HelpdeskBL.GetLoggedInUserShowHelpdeskRight` bestimmt die anzuwendende Sichtbarkeits-Einschränkung und wird beim Aufbau der Abfrage (nicht erst beim clientseitigen Filtern der vollständigen Liste) berücksichtigt.
Aussage: Das System soll einschränkende Rechte bereits auf Ebene der Datenbankabfrage anwenden und nicht erst nach Auslieferung der vollständigen Ergebnismenge an den Client filtern, um ungewollte Datenexposition zu vermeiden.
Ergebnis: Die vom Server ausgelieferte Ergebnismenge enthält von vornherein nur die für den Benutzer zulässigen Datensätze.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (GetLoggedInUserShowHelpdeskRight, Zeilen ~271-284) - Begründung: Filterlogik ist Teil der Abfragekonstruktion, nicht nachgelagert.
Prüfidee: Netzwerk-Mitschnitt einer Listenabfrage eines eingeschränkten Benutzers → Antwortdaten dürfen keine unzulässigen Datensätze enthalten (nicht nur UI-Ausblendung).
Tracelinks: StRS-006, StRS-007; SwRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-009
Titel: Referenzielle Pflichtverknüpfung von RMA-Vorgängen an Tickets
Ebene: SyRS
Typ: Daten
Akteur: Web-Service
Vorbedingung: Ein RMA-Vorgang wird gespeichert.
Fakt: `RmaBL.SaveRma` wirft `ResultException("Rma not coneccted to helpdesk", DependencyCheckFailed)`, wenn `rma.HelpdeskI3D <= 0`.
Aussage: Das System soll einen RMA-Datensatz ohne gültige Ticketreferenz nicht persistieren.
Ergebnis: Jeder gespeicherte RMA-Datensatz hat eine gültige `HelpdeskI3D`-Referenz > 0.
Belege:
- [PRIMÄR] src\backend\Centron.BL\CustomerArea\RmaBL.cs (SaveRma, Zeile ~352-353) - Begründung: harte Exception verhindert Persistierung ohne Verknüpfung.
Prüfidee: Speicherversuch eines RMA mit `HelpdeskI3D = 0` → `ResultException` mit Code `DependencyCheckFailed`.
Tracelinks: StRS-008; SwRS-014, SwRS-015
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-010
Titel: Verteiltes Sperren zur Vermeidung doppelter Aufgabenausführung
Ebene: SyRS
Typ: nicht-funktional
ISO25010: Zuverlässigkeit (Fehlertoleranz)
Akteur: Web-Service (mehrere Instanzen/Prozesse möglich)
Vorbedingung: Eine fällige wiederkehrende Aufgabe wird ggf. von mehreren Prozessen gleichzeitig ausgewertet.
Fakt: `TaskManagementTaskBL.ExecuteTask` erwirbt vor Ausführung ein exklusives, transaktionsgebundenes DB-Lock über `sp_getapplock` (`@LockMode = 'Exclusive'`, `@LockTimeout = 0`).
Aussage: Das System soll bei mehreren parallel laufenden Prozessinstanzen sicherstellen, dass eine fällige wiederkehrende Aufgabe (z. B. automatische Ticketerstellung) genau einmal ausgeführt wird.
Ergebnis: Bei gleichzeitiger Auswertung derselben Aufgabe durch zwei Prozesse erhält nur einer das Lock und führt aus.
Belege:
- [PRIMÄR] src\backend\Centron.BL\TaskManager\TaskManagementTaskBL.cs (ExecuteTask, sp_getapplock-SQL) - Begründung: DB-seitig durchgesetzter Sperrmechanismus, nicht nur In-Process-Lock (würde bei mehreren Prozessen/Servern versagen).
Prüfidee: Simultane Ausführung derselben Aufgabe aus zwei Prozessen → nur eine Ausführung erfolgreich, zweite erhält Lock-Timeout.
Tracelinks: StRS-009; SwRS-016, SwRS-017
Konsolidierung: nein
Status: belegt
```
---
## Block C — Warehousing / Purchasing (System-Ebene)
```
ID: SyRS-011
Titel: Feldgranulare, serverseitige Schreibautorisierung auf Artikelstammdaten
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Artikel wird gespeichert, unabhängig vom Client.
Fakt: `ArticleBL.CheckUserRightBeforeSave`/`CheckSpecialUserRightBeforeSave` prüfen einzelne Felder (Preis, Barcode-Pflicht, Warengruppe) getrennt und setzen bei fehlendem Recht den ursprünglichen DB-Wert zurück, statt den gesamten Speichervorgang abzulehnen.
Aussage: Das System soll Schreibrechte auf Artikelfeld-Ebene (nicht nur auf Entitäts-Ebene) prüfen, damit ein Benutzer mit Teilrechten einen Artikel speichern kann, ohne versehentlich geschützte Felder zu verändern.
Ergebnis: Nicht berechtigte Feldänderungen werden stillschweigend verworfen, berechtigte Felder werden trotzdem gespeichert.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\ArticleBL.cs (CheckUserRightBeforeSave Zeilen 991-1055, CheckSpecialUserRightBeforeSave Zeilen 1058-1089) - Begründung: granulare, im BL durchgesetzte Feldprüfung.
Prüfidee: Benutzer mit Recht "Artikel bearbeiten", aber ohne `CHANGE_ARTICLE_PRICE`, ändert Preis und Beschreibung gleichzeitig → Beschreibung wird gespeichert, Preis bleibt unverändert.
Tracelinks: StRS-010; SwRS-018
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-012
Titel: Regelbasierte Klassifikation von Inventurabweichungen
Ebene: SyRS
Typ: funktional
Akteur: Web-Service
Vorbedingung: Inventurzählung einer Position ist erfasst.
Fakt: `InventoryBL` berechnet pro Position einen `CloseState` (Counted/Ok/Risk/problem) aus Differenz zwischen Zähl- und Sollmenge sowie Barcode-Zustandskonflikten; dieselbe Klassifikationslogik existierte zuvor dupliziert in der inzwischen deaktivierten `Storage\StorageBL.cs`.
Aussage: Das System soll jede Inventurposition automatisiert in eine der definierten Abweichungskategorien einordnen, damit Positionen mit Risiko/Problem gezielt nachbearbeitet werden können, bevor die Inventur abgeschlossen wird.
Ergebnis: Jede Inventurposition hat nach Zählung einen gültigen `CloseState`-Wert.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\InventoryManagement\InventoryBL.cs (Zeilen ~694-750) - Begründung: aktuell aktive, technisch durchgesetzte Klassifikationslogik.
- [KONTEXT] src\backend\Centron.BL\Storage\StorageBL.cs (auskommentiert) - Begründung: dokumentiert Vorgängerimplementierung derselben Regel, nur historischer Beleg.
Prüfidee: Position mit Zählmenge ≠ Sollmenge und ohne Barcode-Konflikt → `CloseState = Risk`, keine Freigabe als "Ok".
Tracelinks: StRS-011; SwRS-019, SwRS-020
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-013
Titel: Konsistente Rechteprüfung für Kommissionierungsvorgänge über Module hinweg
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Teilkommissionierung eines Auftrags wird angelegt/gelöscht.
Fakt: `PartialCommissionOrderBL` prüft an vier Stellen (Zeilen 135, 170, 426, 453) konsistent dieselben Rechte-Konstanten vor Anlage/Löschung.
Aussage: Das System soll Anlage und Löschung einer Teilkommissionierung jeweils eigenständig und unabhängig voneinander autorisieren, sodass ein Recht zum Anlegen nicht implizit auch das Löschen erlaubt.
Ergebnis: Benutzer mit `CREATE_PARTIAL_COMMISSION_FOR_ORDER`, aber ohne `DELETE_PARTIAL_COMMISSION_FOR_ORDER`, kann anlegen, aber nicht löschen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Warehousing\Commissions\PartialCommissionOrderBL.cs (Zeilen 135, 170, 426, 453) - Begründung: getrennte Prüfpunkte für Anlage und Löschung im Code.
Prüfidee: Benutzer mit nur Anlage-Recht versucht Löschung → Ablehnung.
Tracelinks: StRS-012; SwRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-014
Titel: Mehrquellen-Aggregation für Bestellvorschlagsberechnung
Ebene: SyRS
Typ: Daten
Akteur: Web-Service
Vorbedingung: Bestand, Mindestbestand, offene Aufträge und offene Bestellungen liegen für einen Artikel vor.
Fakt: `OrderSuggestionListBL` kombiniert ca. 10 separate SQL-Abfragen (Bestand je Lager, offener Auftragsbedarf, offener Bestellzulauf, Sonderpreise) zu einer Gesamtvorschlagsliste; ausgeführt über `RawSqlAccess.ExecuteQuery<T>`, nicht über die NHibernate-ORM-Abstraktion.
Aussage: Das System soll Bestellvorschläge aus mehreren, potenziell inkonsistenten Datenquellen (Bestand, Bedarf, Zulauf) zu einem konsistenten Zeitpunkt aggregieren.
Ergebnis: Vorschlagsliste spiegelt einen in sich konsistenten Datenstand wider (keine Vermischung unterschiedlicher Zeitpunkte je Teilabfrage).
Belege:
- [PRIMÄR] src\backend\Centron.BL\Purchasing\OrderSuggestionList\OrderSuggestionListBL.cs - Begründung: enthält die tatsächliche Aggregationslogik.
Prüfidee: Lasttest: Bestellvorschlagsberechnung während gleichzeitiger Bestandsbuchung → Ergebnis muss nachvollziehbar einem Zeitpunkt zuordenbar sein (Konsistenzprüfung, ggf. [HYPOTHESE] bzgl. Transaktionsisolationsstufe, siehe Hypothesen.md).
Tracelinks: StRS-013; SwRS-022
Konsolidierung: nein
Status: belegt; Workaround (starke Kopplung an Legacy-DB-Schema statt ORM-Abstraktion)
```
```
ID: SyRS-015
Titel: Pluggable-Adapter für distributorspezifische EDI-Dokumentformate
Ebene: SyRS
Typ: Schnittstelle
Akteur: Web-Service
Vorbedingung: Bestellvorschlag soll an einen konfigurierten Distributor übermittelt werden.
Fakt: `EDIDispatcherBL.CreateEDISuggestionOrderAsync` selektiert anhand `EDIMultidistributors`/`EdiDataType` aus der Konfiguration den passenden Dokumentersteller (ALSO, EGIS, Komsa, Alltron, ITScope, OpenTrans 2.1).
Aussage: Das System soll das Format des erzeugten Bestelldokuments ausschließlich anhand der hinterlegten Konfiguration bestimmen, sodass ein neuer Distributor durch Hinzufügen eines Adapters unterstützt werden kann, ohne bestehende Adapter zu verändern.
Ergebnis: Distributor-Konfigurationswechsel führt ohne Codeänderung zu korrektem Zielformat.
Belege:
- [PRIMÄR] src\backend\Centron.BL\EDI\EDIDispatcherBL.cs (Zeilen 56-70) - Begründung: enthält die tatsächliche, konfigurationsgesteuerte Auswahllogik.
Prüfidee: Konfiguration auf "ITScope" umstellen → erzeugtes Dokument muss ITScope-spezifisches Format aufweisen, ohne Codeänderung.
Tracelinks: StRS-014; SwRS-023
Konsolidierung: nein
Status: belegt
```
---
## Block D — Finances (System-Ebene)
```
ID: SyRS-016
Titel: Autorisierung und Idempotenz bei sicherheitskritischen Zahlungsoperationen
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Zahlungstransaktion wird importiert oder eine erfasste Zahlung gelöscht.
Fakt: `OnlineBankingAccountTransactionsBL.SaveOnlineBankingAccountTransactions` weist Duplikate (gleiche Konfiguration/Datum/Betrag/IBAN/Beschreibung) ab; `PaymentsBL.DeleteIncomingPayment` prüft das Recht `INCOMING_PAYMENT_TRANSACTIONS`, bevor eine Zahlung storniert wird — beides Kernoperationen der Zahlungsabwicklung.
Aussage: Das System soll sicherheitskritische Zahlungsoperationen (Import, Löschung) sowohl gegen Mehrfachausführung (Idempotenz) als auch gegen fehlende Berechtigung serverseitig absichern, da Fehler hier unmittelbaren finanziellen Schaden verursachen können.
Ergebnis: Doppelter Transaktionsimport wird abgewiesen; Löschung ohne Recht wird abgewiesen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (SaveOnlineBankingAccountTransactions, Zeilen 294-340) - Begründung: hohe Kritikalität (Fakturierung/Zahlungsverkehr) erfordert PRIMÄR-Beleg, vorhanden als durchgesetzte Duplikatsprüfung.
- [PRIMÄR] src\backend\Centron.BL\Finances\Payments\PaymentsBL.cs (Zeilen 43-44) - Begründung: durchgesetzte Rechteprüfung vor irreversibler Finanzoperation.
Prüfidee: Duplikat-Importtest sowie Lösch-Test ohne Recht (siehe StRS-015/016 für Details).
Tracelinks: StRS-015, StRS-016; SwRS-024, SwRS-025, SwRS-026
Konsolidierung: Kandidat: SyRS-017 (beide betreffen Zahlungsverbuchung)
Status: belegt
```
```
ID: SyRS-017
Titel: Toleranzbasierter Abgleich von Zahlungsbeträgen mit Belegforderung
Ebene: SyRS
Typ: funktional
Akteur: Web-Service
Vorbedingung: Bankumsatz ist einer offenen Rechnung zugeordnet.
Fakt: `BookAmountToAssignedInvoice` (Zeilen ~1042-1086) verbucht nur bei Rechnungsstatus `Active` (oder `Completed` beim Undo, oder negativem Betrag als Rückbuchung) und markiert die Rechnung als bezahlt, sobald `PaidFC >= DemandedGrossAmount`; an anderer Stelle im Modul wird eine Tolerenz von 0,1 für Abschlussvergleiche verwendet (`CheckForCompleted`).
Aussage: Das System soll den Zahlstatus eines Belegs aus der Summe zugeordneter Zahlungen unter Berücksichtigung einer definierten Toleranz automatisch ableiten, statt exakte Centgleichheit zu verlangen.
Ergebnis: Rechnung mit vollständig zugeordnetem Betrag (innerhalb Toleranz) wird automatisch als bezahlt markiert.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (BookAmountToAssignedInvoice, CheckForCompleted) - Begründung: durchgesetzte Verbuchungs- und Toleranzlogik.
Prüfidee: Zahlung mit Differenz 0,05 zur Forderung → Rechnung wird als bezahlt markiert; Differenz 0,20 → nicht.
Tracelinks: StRS-015; SwRS-025
Konsolidierung: Kandidat: SyRS-016
Status: belegt
```
```
ID: SyRS-018
Titel: Serverseitige Durchsetzung feldspezifischer Rechte auf Abrechnungsdaten
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Änderung des Abrechnungsdatums einer Rechnung/eines Lieferscheins wird angestoßen.
Fakt: `ReceiptWebServiceBL` berechnet `CanChangeDateInInvoices`/`CanChangeDateInDeliveryLists` serverseitig aus den Rechten des angemeldeten Benutzers (Zeilen 994-1000); die WPF-Oberfläche (`TimerBillingSettingsPageViewModel`) verwendet dieses serverseitig berechnete Ergebnis lediglich zur Anzeige.
Aussage: Das System soll die Berechtigung zum Ändern von Abrechnungsdaten serverseitig ermitteln und durchsetzen; eine reine UI-seitige Deaktivierung des Eingabefelds genügt nicht als alleinige Kontrolle.
Ergebnis: Ein direkter API-Aufruf zur Datumsänderung ohne serverseitiges Recht wird abgelehnt, unabhängig vom UI-Zustand.
Belege:
- [PRIMÄR] src\backend\Centron.WebServices.Core\WebServices\Sales.Receipts\ReceiptWebServiceBL.cs (Zeilen 994-1000) - Begründung: serverseitige Berechnung, nicht nur Client-Anzeige.
Prüfidee: Direkter Web-Service-Aufruf zur Datumsänderung ohne Recht (unter Umgehung der UI) → muss serverseitig abgelehnt werden. [HYPOTHESE]: Ob der eigentliche Schreibpfad (nicht nur die Anzeige-Flags) diese Prüfung ebenfalls erzwingt, wurde im Rahmen dieser Iteration nicht bis zur konkreten Save-Methode zurückverfolgt — siehe Hypothesen.md.
Tracelinks: StRS-017; SwRS-027
Konsolidierung: nein
Status: belegt
```
---
## Block E — Security / Rechte / Authentifizierung (System-Ebene)
```
ID: SyRS-019
Titel: Zentraler, gecachter Autorisierungsdienst für alle BL-Module
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service (alle BL-Module)
Vorbedingung: Eine BL-Operation prüft ein Benutzerrecht.
Fakt: `AppRightsBL.HasUserRight` liest Rechte aus `Sichtrus`/`Sichmemb` und cached das Ergebnis pro Benutzer (`Session.Advanced.Cache.GetOrAdd`); die Erweiterungsmethode `UserRightsExt.HasUserRight` fängt Exceptions ab und liefert im Fehlerfall `false` (fail-closed).
Aussage: Das System soll Rechteprüfungen über einen einzigen, wiederverwendeten Dienst mit Caching realisieren und im Fehlerfall (z. B. DB-Ausfall während der Prüfung) grundsätzlich den Zugriff verweigern statt ihn zu gewähren.
Ergebnis: Bei technischem Fehler während der Rechteprüfung wird die angefragte Aktion abgelehnt, nicht zugelassen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Rights\AppRightsBL.cs (HasUserRight, ~Zeile 644) - Begründung: zentrale Implementierung.
- [PRIMÄR] src\backend\Centron.BL\Administration\Rights\UserRightsExt.cs (HasUserRight-Erweiterungsmethode, try/catch → false) - Begründung: durchgesetztes Fail-Closed-Verhalten, sicherheitskritisch → PRIMÄR-Beleg erforderlich und vorhanden.
Prüfidee: Rechteprüfung während simuliertem DB-Verbindungsfehler auslösen → Ergebnis muss `false` (verweigert) sein, nicht Exception nach oben durchreichen oder `true` liefern.
Tracelinks: StRS-018; SwRS-028
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-020
Titel: Erweiterbarer Rechte-Katalog mit eindeutiger ID-Vergabe
Ebene: SyRS
Typ: nicht-funktional
ISO25010: Wartbarkeit (Modifizierbarkeit)
Akteur: Entwicklungsteam
Vorbedingung: Ein neues Recht soll dem System hinzugefügt werden.
Fakt: `UserRightsConst.cs` (2819 Zeilen, ~751 Konstanten) enthält den Kommentarblock "NEW .NET MODULE RIGHTS START AT 20800000 / NEXT ID: 20800174" — ein manuell gepflegter, fortlaufender ID-Zähler ohne ersichtliche automatisierte Kollisionsprüfung; ältere Rechte tragen numerische IDs mit `[Obsolete]`-Markierung, bleiben aber im Code.
Aussage: Das System soll neue Rechte-IDs eindeutig und kollisionsfrei vergeben können; aktuell geschieht dies durch manuelle Pflege eines Zählerkommentars, was ein Wartbarkeitsrisiko bei parallelen Änderungen durch mehrere Entwickler darstellt.
Ergebnis: Jede Rechte-ID ist im gesamten System eindeutig.
Belege:
- [PRIMÄR] src\webservice\Centron.WebServices.Core\EntitiesWrongPlace\Administration\Rights\UserRightsConst.cs (Header-Kommentar) - Begründung: unmittelbarer Beleg für den manuellen, nicht automatisiert abgesicherten Vergabeprozess.
Prüfidee: Code-Review-Test: zwei parallele Branches fügen ein neues Recht mit dem "nächsten" ID-Wert hinzu → Merge-Konflikt wird nicht automatisch, sondern nur durch Textgleichheit des Kommentars erkannt (Risiko einer stillen ID-Kollision, falls nicht rechtzeitig bemerkt).
Tracelinks: StRS-018; SwRS-029
Konsolidierung: nein
Status: belegt; Workaround (manuoll gepflegter ID-Zähler statt automatisierter Vergabe/Datenbanksequenz)
```
```
ID: SyRS-021
Titel: Einheitliches Session-Ticket unabhängig vom Authentifizierungsverfahren
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Benutzer hat sich über eines der unterstützten Verfahren erfolgreich authentifiziert.
Fakt: `AuthenticatorFactory` liefert je nach Konfiguration eine von vier `Authenticator`-Implementierungen; alle münden in denselben nachgelagerten Ticket-Ausstellungspfad (`TicketBL`/`AuthenticationTicketBL`), sodass nachgelagerte Systemteile nicht wissen müssen, welches Verfahren verwendet wurde.
Aussage: Das System soll unabhängig vom verwendeten Authentifizierungsverfahren ein einheitlich strukturiertes, zeitlich befristetes Session-Ticket ausstellen, damit nachgelagerte Autorisierungsprüfungen verfahrensunabhängig funktionieren.
Ergebnis: Nachgelagerte BL-Aufrufe benötigen keine Fallunterscheidung nach Authentifizierungsverfahren.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\Auth\AuthenticatorFactory.cs, TicketBL.cs - Begründung: gemeinsamer Ausstellungspfad für alle vier Verfahren.
Prüfidee: Anmeldung über Basic-Auth und über OIDC vergleichen → resultierendes Ticket hat identische Struktur/Felder.
Tracelinks: StRS-019, StRS-020, StRS-022; SwRS-030, SwRS-031, SwRS-032, SwRS-033
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-022
Titel: Zeitliche Befristung von Authentifizierungs-Tickets
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Ticket wurde ausgestellt.
Fakt: `TicketBL` verwendet `ExpirationKind.FromSettings`/`OneDay` zur Bestimmung der Ticket-Gültigkeitsdauer, kombiniert mit einem gerätegebundenen Salt (`CryptoUtils.CreateSalt(32)` + `CreatePasswordHash(deviceId, salt)`).
Aussage: Das System soll jedes ausgestellte Authentifizierungs-Ticket nach einer konfigurierbaren Zeitspanne automatisch ungültig werden lassen.
Ergebnis: Ein Ticket ist nach Ablauf der konfigurierten Frist nicht mehr für Authentifizierung nutzbar.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\TicketBL.cs (Zeilen ~166-169, ExpirationKind-Verwendung) - Begründung: durchgesetzte Ablauflogik.
Prüfidee: Ticket erzeugen, künstlich Systemzeit über Ablaufgrenze vorstellen (Testsystem) → Ticket wird abgelehnt.
Tracelinks: StRS-019; SwRS-032
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-023
Titel: Vollständige, nicht abschaltbare Zugriffs- und Änderungsprotokollierung im Passwort-Tresor
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service
Vorbedingung: Gespeichertes Passwort wird gelesen oder geändert.
Fakt: `PasswordManagementAccessLogBL` und `PasswordManagementLogBL` schreiben bei jedem Zugriff/jeder Änderung einen Protokolleintrag (ActionType, Date, EmployeeI3D); die Protokollierung ist Teil des Zugriffspfads selbst, nicht ein optionales Zusatzfeature.
Aussage: Das System soll jeden Zugriff auf und jede Änderung an gespeicherten Zugangsdaten so protokollieren, dass die Protokollierung durch den zugreifenden Benutzer nicht umgangen werden kann.
Ergebnis: Für jeden Zugriff existiert ein nicht nachträglich durch den Benutzer löschbarer Protokolleintrag.
Belege:
- [PRIMÄR] src\backend\Centron.BL\PasswordManagementArea\PasswordManagementAccessLogBL.cs, PasswordManagementLogBL.cs - Begründung: Protokollierung ist im Zugriffsablauf selbst verankert.
Prüfidee: Zugriff auf gespeichertes Passwort → Protokolleintrag muss unmittelbar entstehen, unabhängig vom Ergebnis des Zugriffs.
Tracelinks: StRS-021; SwRS-034
Konsolidierung: nein
Status: belegt
```
---
## Block F — Web-Kanäle (System-Ebene)
```
ID: SyRS-024
Titel: Isolierung von Kunden-Web-Account-Sitzungen von internen Benutzersitzungen
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service (Nexus)
Vorbedingung: Ein Web-Account-Kunde meldet sich am Kundenportal an.
Fakt: Es existieren getrennte Login-Oberflächen/Handler für internen Mitarbeiterzugang (`AuthPage.razor`), Outlook-Add-In (`OutlookAuthPage.razor`) und Kunden (`CustomerAuthPage.razor`); Kundenportal-Datenabfragen sind auf den authentifizierten Web-Account beschränkt (impliziert durch getrennten `WebAccountAuthenticator`).
Aussage: Das System soll Kunden-Web-Account-Sitzungen strikt von internen Mitarbeitersitzungen trennen und Datenabfragen im Kundenportal auf den jeweils angemeldeten Kunden beschränken.
Ergebnis: Ein Web-Account-Kunde kann über das Kundenportal keine Daten anderer Kunden oder interne Mitarbeiterfunktionen erreichen.
Belege:
- [PRIMÄR] src\backend\Centron.BL\Administration\Logins\Auth\WebAccountAuthenticator.cs - Begründung: eigenständiger Authentifizierungspfad für Web-Accounts.
- [SEKUNDÄR] src\nexus\CentronNexus\Shared\Auth\CustomerAuthPage.razor, AuthPage.razor, OutlookAuthPage.razor - Begründung: drei separate Login-Oberflächen bestätigen die Trennung auf UI-Ebene.
Prüfidee: Als Web-Account-Kunde angemeldet, direkten API-Aufruf auf einen internen/administrativen Endpunkt oder auf Daten eines anderen Kunden versuchen → muss abgelehnt werden. [HYPOTHESE]: Die konkrete serverseitige Scoping-Prüfung pro Kundenportal-Endpunkt wurde nicht für jeden einzelnen Controller einzeln verifiziert — siehe Hypothesen.md.
Tracelinks: StRS-022, StRS-023; SwRS-035
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-025
Titel: Serverseitige Lizenzprüfung für Web-Shop-Funktionalität
Ebene: SyRS
Typ: Sicherheit
Akteur: Web-Service (Nexus)
Vorbedingung: Web-Account-Kunde ruft WebCart-Funktion auf.
Fakt: `WebCartShopPage.razor` trägt das Attribut `[AuthorizeLicense(nameof(LicenseGuids.WebCart2))]`, das laut Namensmuster serverseitig vor Rendern der Seite geprüft wird (Blazor-Server-Modell, Ausführung auf dem Server, nicht im Browser).
Aussage: Das System soll den Zugriff auf die WebCart-Funktion an eine serverseitig geprüfte Lizenz koppeln, unabhängig davon, ob der Kunde die URL direkt aufruft.
Ergebnis: Web-Account ohne WebCart2-Lizenz kann die Shop-Seite nicht öffnen, auch nicht durch direkten URL-Aufruf.
Belege:
- [PRIMÄR] src\nexus\CentronNexus\WebCart\WebCartShopPage.razor (Attribut AuthorizeLicense) - Begründung: Blazor-Server-Ausführungsmodell macht dies zu einer serverseitigen, nicht umgehbaren Prüfung (im Gegensatz zu Blazor WebAssembly).
Prüfidee: Web-Account ohne Lizenz ruft `/webcart/shop` direkt per URL auf → Zugriff wird verweigert. [HYPOTHESE]: Das genaue Verhalten des `AuthorizeLicense`-Attributs (Redirect vs. Fehlerseite vs. Exception) wurde nicht im Detail nachvollzogen — siehe Hypothesen.md.
Tracelinks: StRS-023; SwRS-036
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-026
Titel: Automatisierte, signierte Erstellung aller Auslieferungsartefakte
Ebene: SyRS
Typ: nicht-funktional
ISO25010: Übertragbarkeit (Installierbarkeit)
Akteur: CI/CD-System
Vorbedingung: Änderung wird auf `main`/`release/*`-Branch gemerged.
Fakt: `.github\workflows\build.yml` baut und signiert alle drei Artefakte (Web-Service-Host + Connection Manager, WPF-Client, Nexus-Host) in einem Lauf, erzeugt WiX-MSIs, verifiziert Authenticode-Signaturen und lädt die Artefakte hoch.
Aussage: Das System soll bei jeder Änderung auf den relevanten Branches alle drei Auslieferungsartefakte automatisiert, reproduzierbar und signiert erzeugen, ohne manuellen Eingriff.
Ergebnis: Nach jedem Build-Lauf liegen drei signierte, verifizierte Artefakte vor.
Belege:
- [PRIMÄR] .github\workflows\build.yml - Begründung: enthält den tatsächlich ausgeführten, automatisierten Build-/Signier-/Verifizierungsprozess.
Prüfidee: CI-Lauf beobachten: alle drei Artefakte müssen mit gültiger Authenticode-Signatur vorliegen, Pipeline darf bei Signaturfehler nicht grün werden.
Tracelinks: StRS-024; SwRS-038
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-027
Titel: Containerisierte, konfigurationsexterne Bereitstellung des Web-Portals
Ebene: SyRS
Typ: nicht-funktional
ISO25010: Übertragbarkeit (Anpassbarkeit)
Akteur: Betreiber (Cloud/On-Premises)
Vorbedingung: Container-Host (z. B. Azure) steht bereit.
Fakt: `docker\Dockerfile` baut ein `.NET 10 Alpine`-Image, Konfiguration erfolgt über `appsettings.json`/`appsettings.Development.json` mit Platzhaltern für produktive Werte statt eingebetteter Zugangsdaten (im Gegensatz zum legacy `app.config` der Konsolen-Variante, siehe Hypothesen.md); Deployment via `docker compose` auf einer Ziel-VM.
Aussage: Das System soll das Web-Portal als eigenständigen, umgebungsunabhängigen Container bereitstellen können, dessen Konfiguration extern (nicht im Image fest codiert) erfolgt.
Ergebnis: Dasselbe Container-Image ist mit unterschiedlicher externer Konfiguration in unterschiedlichen Umgebungen einsetzbar.
Belege:
- [PRIMÄR] docker\Dockerfile, docker\README.md - Begründung: enthält den tatsächlichen Build- und Konfigurationsmechanismus.
- [SEKUNDÄR] src\nexus\CentronNexus.Host\appsettings.json - Begründung: zeigt produktionsseitig weitgehend leere/platzhalterhafte Werte, die extern befüllt werden.
Prüfidee: Dasselbe Image mit zwei unterschiedlichen `appsettings`-Overrides starten → unterschiedliches Zielsystem wird angesprochen, ohne Image-Neubau.
Tracelinks: StRS-024; SwRS-038
Konsolidierung: Kandidat: SyRS-026 (beide betreffen Auslieferung/Deployment)
Status: belegt
```
---
## Block G — Externe Integrationen (System-Ebene, leichtere Analysetiefe)
```
ID: SyRS-028
Titel: Fehlerisolation zwischen unabhängigen externen Integrationen
Ebene: SyRS
Typ: nicht-funktional
ISO25010: Zuverlässigkeit (Fehlertoleranz)
Akteur: Web-Service
Vorbedingung: Eine von mehreren konfigurierten externen Schnittstellen (COP/Egis/ITscope/Icecat, GLS/Shipcloud, ebInterface/ZUGFeRD, docuFORM) ist nicht erreichbar oder liefert einen Fehler.
Fakt: Jeder externe Client kapselt Fehler in einer eigenen Exception-Klasse (`ITscopeException`, `CopException`, `EgisException`, `IcecatException`) mit eigener Fehlerbehandlung; es wurde **keine gemeinsame Resilience-Bibliothek (Polly o. ä.)** und **kein einheitliches Retry-/Timeout-Konzept** über alle Integrationen hinweg gefunden — jede Integration behandelt Fehler eigenständig und unterschiedlich (z. B. ITscope: HTTP 404 → stilles Leerergebnis; andere Clients: Exception-Weiterwurf).
Aussage: Das System soll den Ausfall einer externen Integration so behandeln, dass andere, unabhängige Integrationen und Kernfunktionen davon unberührt bleiben; aktuell ist dies nicht durch ein einheitliches Resilience-Konzept, sondern durch voneinander unabhängige, uneinheitliche Fehlerbehandlungen je Client erreicht.
Ergebnis: Ausfall eines externen Dienstes (z. B. Icecat) führt nicht zum Ausfall anderer Funktionen (z. B. GLS-Versand).
Belege:
- [PRIMÄR] src\apis\Centron.APIs.ITscopeDataAccess\ITscopeApi.cs (Zeilen 293-314) - Begründung: durchgesetzte, clientspezifische Fehlerbehandlung.
- [SEKUNDÄR] src\apis\Centron.Api.docuFORM\Helper\HttpResponseMessageExtensions.cs - Begründung: weiterer, eigenständiger Fehlerbehandlungspfad, bestätigt fehlende Vereinheitlichung.
Prüfidee: Simulierter Ausfall eines externen Dienstes (z. B. Timeout) → übrige Integrationen und Kernfunktionen bleiben funktionsfähig; Antwortzeitverhalten bei Ausfall ist [HYPOTHESE] (kein Timeout-Override gefunden, Default-`HttpClient`-Timeout vermutlich wirksam — siehe Hypothesen.md).
Tracelinks: StRS-025, StRS-026, StRS-027, StRS-028; SwRS-039, SwRS-040
Konsolidierung: nein
Status: belegt; Workaround (uneinheitliche, nicht zentralisierte Resilience-Strategie über alle externen Integrationen)
```
@@ -0,0 +1,57 @@
# Traceability-Tabelle
Eine Zeile je SwRS-Anforderung (feinste Granularität), mit jeweils primärer SyRS- und StRS-Referenz sowie dem stärksten (i. d. R. PRIMÄR-)Artefaktbeleg. Vollständige, teils mehrfache Verknüpfungen (eine SyRS kann mehrere StRS bedienen, eine StRS mehrere SyRS) sind in den `Tracelinks`-Feldern der jeweiligen Einzelanforderung in `StRS.md`/`SyRS.md`/`SwRS.md` dokumentiert; diese Tabelle bildet die jeweils primäre Kette ab.
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg (primär) |
|---|---|---|---|
| StRS-001 | SyRS-001 | SwRS-001 | src\backend\Centron.Interfaces\Sales.Receipts\IReceiptSpecificLogic.cs |
| StRS-001 | SyRS-001 | SwRS-002 | src\backend\Centron.Interfaces\CentronObjectKindNumeric.cs |
| StRS-001, StRS-005 | SyRS-002 | SwRS-003 | src\backend\Centron.BL\Sales\Receipts\Internal\AutomaticallyCloseReceiptHelperBL.cs |
| StRS-002 | SyRS-003 | SwRS-004 | src\backend\Centron.BL\Administration\FileManagement\SharedDocumentBL.cs (GenerateTokenForDocument, Z. 128-130) |
| StRS-002 | SyRS-004 | SwRS-005 | src\backend\Centron.BL\Administration\FileManagement\SharedDocumentBL.cs (GetSharedDocumentByToken, Z. 405-409) |
| StRS-002 | SyRS-004 | SwRS-006 | src\backend\Centron.BL\Sales\Receipts\ReceiptBL.cs (AcceptWebReceipt, Z. 6256-6360) |
| StRS-003 | SyRS-005 | SwRS-007 | src\backend\Centron.BL\Sales\Receipts\Invoices\ReceiptInvoiceBL.cs (FixInvoice, Z. 86) |
| StRS-003 | SyRS-005 | SwRS-008 | src\backend\Centron.BL\Administration\Scripts\ScriptMethods\SqlStatements\SQLScriptCollection2.xml (Skript #10208) |
| StRS-004 | SyRS-006 | SwRS-009 | src\backend\Centron.Interfaces\DataExchange.BookKeeping\CalculationUtils.cs |
| StRS-004 | SyRS-006 | SwRS-010 | src\backend\Centron.BL\Sales\Receipts\Invoices\InvoiceSpecificLogic.cs |
| StRS-006 | SyRS-007 | SwRS-011 | src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (Z. 298-326) |
| StRS-006 | SyRS-007 | SwRS-012 | src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (CheckUserRigths, Z. 410-466) |
| StRS-006, StRS-007 | SyRS-008 | SwRS-013 | src\backend\Centron.BL\Sales\Support\HelpdeskBL.cs (GetLoggedInUserShowHelpdeskRight, Z. 271-284) |
| StRS-008 | SyRS-009 | SwRS-014 | src\backend\Centron.BL\CustomerArea\RmaBL.cs (SaveRma, Z. 352-353) |
| StRS-008 | SyRS-009 | SwRS-015 | src\backend\Centron.BL\CustomerArea\RmaBL.cs (SaveRma, Z. 378-521) |
| StRS-009 | SyRS-010 | SwRS-016 | src\backend\Centron.BL\TaskManager\TaskManagementTaskBL.cs (sp_getapplock) |
| StRS-009 | SyRS-010 | SwRS-017 | src\backend\Centron.BL\TaskManager\ActionHandler\TaskManagementHelpdeskActionHandler.cs (Z. 57) |
| StRS-010 | SyRS-011 | SwRS-018 | src\backend\Centron.BL\Warehousing\ArticleBL.cs (Z. 991-1089) |
| StRS-011 | SyRS-012 | SwRS-019 | src\backend\Centron.BL\Warehousing\InventoryManagement\InventoryBL.cs (Z. 694-750) |
| StRS-011 | SyRS-012 | SwRS-020 | src\backend\Centron.BL\Warehousing\InventoryManagement\InventoryBL.cs (DeleteInventory, Z. 98-109) |
| StRS-012 | SyRS-013 | SwRS-021 | src\backend\Centron.BL\Warehousing\Commissions\PartialCommissionOrderBL.cs (Z. 135, 170, 426, 453) |
| StRS-013 | SyRS-014 | SwRS-022 | src\backend\Centron.BL\Purchasing\OrderSuggestionList\OrderSuggestionListBL.cs |
| StRS-014 | SyRS-015 | SwRS-023 | src\backend\Centron.BL\EDI\EDIDispatcherBL.cs (Z. 56-70) |
| StRS-015, StRS-016 | SyRS-016 | SwRS-024 | src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (Z. 294-340) |
| StRS-015 | SyRS-016, SyRS-017 | SwRS-025 | src\backend\Centron.BL\Finances\OnlineBanking\OnlineBankingAccountTransactionsBL.cs (BookAmountToAssignedInvoice, Z. 1042-1086) |
| StRS-016 | SyRS-016 | SwRS-026 | src\backend\Centron.BL\Finances\Payments\PaymentsBL.cs (Z. 43-44) |
| StRS-017 | SyRS-018 | SwRS-027 | src\backend\Centron.WebServices.Core\WebServices\Sales.Receipts\ReceiptWebServiceBL.cs (Z. 994-1000) |
| StRS-018 | SyRS-019 | SwRS-028 | src\backend\Centron.BL\Administration\Rights\AppRightsBL.cs (HasUserRight); UserRightsExt.cs |
| StRS-018 | SyRS-020 | SwRS-029 | src\webservice\Centron.WebServices.Core\EntitiesWrongPlace\Administration\Rights\UserRightsConst.cs (Header-Kommentar) |
| StRS-019 | SyRS-021 | SwRS-030 | src\backend\Centron.BL\Administration\Logins\Auth\AuthenticatorFactory.cs |
| StRS-019 | SyRS-021 | SwRS-031 | src\backend\Centron.BL\Administration\Logins\Auth\BasicAuthenticator.cs (Z. 46, 48) |
| StRS-019, StRS-020 | SyRS-021, SyRS-022 | SwRS-032 | src\backend\Centron.BL\Administration\Logins\TicketBL.cs (Z. 166-169) |
| StRS-020 | SyRS-021 | SwRS-033 | src\backend\Centron.BL\Administration\Logins\TwoFactor\TwoFactorAuthBL.cs |
| StRS-021 | SyRS-023 | SwRS-034 | src\backend\Centron.BL\PasswordManagementArea\PasswordManagementAccessLogBL.cs |
| StRS-022 | SyRS-024 | SwRS-035 | src\backend\Centron.BL\Administration\Logins\Auth\WebAccountAuthenticator.cs |
| StRS-023 | SyRS-025 | SwRS-036 | src\nexus\CentronNexus\WebCart\WebCartShopPage.razor (AuthorizeLicense) |
| StRS-023 | SyRS-025 | SwRS-037 | src\nexus\CentronNexus\WebCart\Helpers\CurrentCartService.cs |
| StRS-024 | SyRS-026, SyRS-027 | SwRS-038 | .github\workflows\build.yml |
| StRS-025 | SyRS-028 | SwRS-039 | src\apis\Centron.APIs.ITscopeDataAccess\ITscopeApi.cs (Z. 293-314) |
| StRS-028 | SyRS-028 | SwRS-040 | src\apis\Centron.Api.docuFORM\DocuFormRestApiClient.cs |
## Ergänzende StRS ohne eigene SwRS-Detailtiefe (leichtere Analysetiefe)
Diese StRS/SyRS-Paare wurden gebildet, besitzen aber laut Priorisierung keine eigenständige SwRS-Anforderung über die in obiger Tabelle bereits unter StRS-025/StRS-028 (SyRS-028) gebündelte Ebene hinaus:
| StRS-ID | SyRS-ID | Artefaktbeleg |
|---|---|---|
| StRS-026 | SyRS-028 | src\apis\Centron.Api.Gls\CentronGlsLogic.cs; src\apis\Centron.Api.Shipcloud\CentronShipcloudLogic.cs |
| StRS-027 | SyRS-028 | src\apis\Centron.Api.EbInterface\EbInterfaceLogic.cs; src\webservice\Centron.Controllers\Controllers\v1\Receipts\ZugferdImportController.cs |
Siehe Analysebericht.md, Abschnitt "Analysetiefe je Modul", für die Begründung der reduzierten Tiefe bei Block G (externe Integrationen).
@@ -0,0 +1,198 @@
# Messprotokoll – V1 Baseline (Prompt-only) – Prompt-Version 01
## Lauf
- **Prompt-Datei:** `Versuche/Versuch_01/01_Prompt.md`
- **SHA-256 (Prompt):** `1B0DB06B8E0A5B92A5EFBDBEC5A0C554351FC928A16AEF34AAD9EAA0893C02FF`
- **Startzeit:** 2026-08-25T12:29:05.2074784+02:00
- **Endzeit:** 2026-08-25T13:00:35.7607833+02:00
- **Dauer gesamt:** 00:31:31 (Wanduhr) bzw. 00:31:26 (`duration_ms`) — API: 00:47:05 (`duration_api_ms`)
- Die API-Dauer übersteigt die Wanduhrzeit, weil 8 `Explore`-Subagenten parallel liefen; die Werte summieren sich über nebenläufige Anfragen.
- **Root-Verzeichnis:** `c:\DEV\MasterArbeit\QuellCode\CentronERP`
- **Codebasis-Commit:** `89ccfd650de2b112c5d20df4230457e413210aad` (dirty vor Eingriff: nein; während des Laufs: ja – siehe *Vorbereitender Eingriff*)
- **Prompt-Repo-Commit:** `0ec86aed8cb8781054c86cbe0dd9f5eb0f7e5f05`
## Vorbereitender Eingriff (Herstellung der Baseline-Bedingung)
Das Root enthielt Werkzeugkonfigurationen, die der Versuchsbedingung „keine Agentendateien,
keine MCP-Server" widersprechen. Sie wurden auf Anweisung des Versuchsleiters **vor** dem Lauf
gelöscht (92 versionierte Dateien in 17 Root-Einträgen):
`.agents/`, `.aiignore`, `.claude/`, `.claudeignore`, `.codex/`, `.cursor/`, `.cursorignore`,
`.mcp.json`, `.mcp.disabled.json.bak`, `.memory-mcp/`, `.serena/`, `.opencode/`, `AGENTS.md`,
`CLAUDE.md`, `opencode.json`, `skills-lock.json`, `.coderabbit.yaml`
Darin enthalten waren u. a. 3 projektspezifische Subagenten, 34 Skill-Definitionen, 6 Slash-Commands,
7 Output-Styles, 11 Serena-Memories und der MCP-Server `serena`.
Kontrollen der Isolation:
- Verschachtelte `CLAUDE.md`/`AGENTS.md`/`.mcp.json`/`.claude` unterhalb des Roots: **keine**
- Übergeordnete Verzeichnisse (`QuellCode/`): **frei von Agentendateien**
- User-Ebene (`~/.claude`): **keine** Agenten, **keine** Skills, **keine** `CLAUDE.md`;
`settings.json` enthält nur `model` und `agentPushNotifEnabled`
- Die Modellpräferenz der User-Settings (`opus[1m]`) wurde per `--model` überschrieben
Wiederherstellung: `git -C QuellCode/CentronERP restore .` (alle Dateien waren versioniert,
Working Tree vor dem Eingriff sauber). Der Eingriff wurde nach dem Lauf vollständig
zurückgenommen; zum weiteren Weg der Codebasis siehe Anmerkung 9.
## Werkzeugkonfiguration
- **Laufverzeichnis-ID:** `v1.0.0-23e8`
- **Ablage:** `Iteration 1/claude-sonnet-5/builtin/high/`
- **Parallele Läufe:** nein
- **Skill-Version:** `1.0.0` (Ausgangsfassung: kein Shell-Zugriff, Isolation durch Löschen der KI-Konfigurationsdateien im Root)
- **Claude-Code-Version:** 2.1.245
- **Effort:** `high` — **nicht zur Laufzeit gesetzt**, sondern aus der Sitzung geerbt und
nachtraeglich aus dem Session-Transkript rekonstruiert (69 Nachrichten, durchgaengig `high`).
`RawResult.json` enthaelt kein `effort`-Feld. Ab Skill-Version 3.4.0 wird der Wert per
`--effort` explizit gesetzt.
- **Modell:** `claude-sonnet-5` (explizit gesetzt, Kontextfenster 1.000.000, max. Output 64.000);
zusätzlich `claude-haiku-4-5-20251001` für interne Hilfsaufrufe (4.176 Input-/20 Output-Tokens)
- **Permission-Mode:** `acceptEdits`
- **MCP-Server / Agentendateien:** keine (siehe *Vorbereitender Eingriff*)
- **Aufruf:** `claude -p --output-format json --permission-mode acceptEdits --model claude-sonnet-5 --add-dir <Laufverzeichnis>`,
Prompt per stdin, Arbeitsverzeichnis = Root
- **Subagenten:** 8 (alle vom eingebauten Typ `Explore`, foreground, max. Tiefe 1, 8 abgeschlossen, 0 fehlgeschlagen).
Es handelt sich um Claude-Code-Bordmittel, nicht um projektspezifische Agentendateien.
- **Fast-Mode:** aus
## Verbrauch
### Hauptagent (`usage` im Ergebnisobjekt)
| Messgröße | Wert |
|---|---|
| Input-Tokens | 46 |
| Output-Tokens | 105.959 (davon 25.299 Thinking-Tokens) |
| Cache-Write-Tokens | 217.738 (vollständig 1h-ephemeral) |
| Cache-Read-Tokens | 3.534.395 |
| Agent-Turns | 43 |
### Gesamtlauf inkl. Subagenten (`modelUsage`, abrechnungsrelevant)
| Messgröße | `claude-sonnet-5` | `claude-haiku-4-5-20251001` | Summe |
|---|---:|---:|---:|
| Input-Tokens | 366 | 4.176 | 4.542 |
| Output-Tokens | 249.020 | 20 | 249.040 |
| Cache-Write-Tokens | 839.291 | 0 | 839.291 |
| Cache-Read-Tokens | 11.959.137 | 0 | 11.959.137 |
| Tokens gesamt | 13.047.814 | 4.196 | **13.052.010** |
**Tokens gesamt: 13.052.010** (Summe aus Input, Output, Cache-Write und Cache-Read ueber alle Modelle; `total_cost_usd` steht weiterhin in `RawResult.json`)
## Ergebnis
- **Status:** erfolgreich (`is_error: false`, `subtype: "success"`, `stop_reason: "end_turn"`, Exit-Code 0, `Stderr.log` leer)
- **Session-ID:** `18b1d5b6-f3e3-49cd-b5aa-38bf1fff642c`
- **Erzeugte Dateien:** alle 7 geforderten Artefakte in `Ergebnisse\`
| Datei | Größe | Inhalt |
|---|---:|---|
| `StRS.md` | 45.710 B | 28 Anforderungen |
| `SyRS.md` | 40.758 B | 28 Anforderungen |
| `SwRS.md` | 51.795 B | 40 Anforderungen |
| `Traceability.md` | 6.095 B | 44 Zeilen StRS→SyRS→SwRS |
| `Hypothesen.md` | 9.182 B | 12 Einträge (H-001…H-012) |
| `Glossar.md` | 6.698 B | Domänenbegriffe |
| `Analysebericht.md` | 13.637 B | Modulübersicht, Konsistenzcheck, Selbstbewertung |
Summe: 96 Anforderungen über drei Ebenen.
- **Root unverändert:** ja. `git status --porcelain` nach dem Lauf ist zeilenweise identisch mit
dem vor dem Lauf gesicherten Stand (92 Einträge, ausnahmslos Status `D` aus dem vorbereitenden
Eingriff). Der Lauf selbst hat keine Datei der Codebasis angelegt, geändert oder gelöscht.
- **Abschlusstext des Agenten:** siehe `RawResult.json` (`result`)
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 28 | 29,2 % |
| SyRS | 28 | 29,2 % |
| SwRS | 40 | 41,7 % |
| **Gesamt** | **96** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| Sicherheit | 38 | 39,6 % |
| funktional | 28 | 29,2 % |
| Daten | 12 | 12,5 % |
| Schnittstelle | 9 | 9,4 % |
| nicht-funktional | 9 | 9,4 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 138 |
| davon `PRIMÄR` | 105 (76,1 %) |
| davon `SEKUNDÄR` | 27 (19,6 %) |
| davon `KONTEXT` | 6 (4,3 %) |
| Belege je Anforderung (Median) | 1,0 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 96 (100,0 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 88 | 91,7 % |
| als `HYPOTHESE` gekennzeichnet | 8 | 8,3 % |
| als Workaround vermerkt | 8 | 8,3 % |
| Konsolidierungskandidaten | 10 | 10,4 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **erfüllt** (49 risikorelevante Anforderungen, alle gedeckt) |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 96 von 96 mit Tracelinks (100,0 %) |
## Anmerkungen/Auffälligkeiten
1. **36 Permission-Denials** (32 × `Bash`, 4 × `PowerShell`). Unter `acceptEdits` sind Shell-Aufrufe
nicht freigegeben; der Lauf brach dadurch nicht ab, sondern wich auf `Read`/`Grep`/`Glob`/`Explore`
aus. Methodisch relevant: Verzeichnisinventuren und Dateizählungen per Shell standen dem Agenten
nicht zur Verfügung, was die Breitenabdeckung beeinflusst haben kann. Für Folgeiterationen ist zu
entscheiden, ob Shell-Zugriff Teil der Werkzeugkonfiguration sein soll.
2. **Abdeckung laut Selbstbewertung des Agenten:** ~17.300 Quelldateien, 82 Projekte, ~85 BL-Module.
Tiefenanalyse für Order-to-Cash/Zahlungseingang, C-Sign-Websignatur, Rechnungsfestschreibung,
Steuerberechnung, Helpdesk/RMA, Lagerhaltung, Einkauf, Online-Banking-Abgleich sowie Rechte-/
Authentifizierungssystem. Leichtere Behandlung externer Integrationen; **rund 55–60 der ~85
BL-Module (Reporting, Statistik, Integrationen, Mobile u. a.) wurden nicht analysiert.**
3. **Sicherheitsbefund:** ungesalzenes SHA-1-Passwort-Hashing, im Code selbst als TODO markiert.
Vom Agenten als belegter Primärfund ausgewiesen.
4. **Konsistenzcheck:** Der Agent gibt an, drei Traceability-Inkonsistenzen gefunden und vor
Abgabe korrigiert zu haben (dokumentiert im `Analysebericht.md`).
5. **Zählabweichung bei Hypothesen:** `Hypothesen.md` führt 12 Einträge (H-001…H-012), während in
den Anforderungsdateien nur 7 Inline-Markierungen `[HYPOTHESE]` stehen (SyRS 5, SwRS 2, StRS 0).
Die Sammeldatei enthält demnach auch Hypothesen ohne zugeordnete Anforderung. Für die Auswertung
der Belegdichte ist zu klären, welche Zählweise maßgeblich ist.
6. **Cache-Dominanz:** 11,96 Mio. Cache-Read- gegenüber 4.542 echten Input-Tokens. Der Verbrauch
wird fast vollständig von wiederholtem Kontextlesen bestimmt — bei Vergleichen zwischen
Iterationen sind Cache-Tokens deshalb getrennt auszuweisen.
7. **Manuelle Eingriffe während des Laufs:** keine.
8. **Vergleichbarkeit mit Folgeläufen:** Dieser Lauf entstand unter der Vorgänger-Konfiguration —
ohne Shell-Freigabe (`acceptEdits` allein) und mit Isolation durch Löschen der
AI-Konfigurationsdateien im Root. Ab Prompt-Version 02 gilt die geänderte Standardkonfiguration
des Skills: `--allowedTools "Bash" "PowerShell"` mit Denylist für schreibende Kommandos
sowie Isolation über einen eingefrorenen Codebasis-Snapshot ohne KI-Konfigurationen
(zusätzlich `--safe-mode` und `--strict-mcp-config`). Die
Werkzeugkonfiguration ist damit zwischen Prompt-Version 01 und den Folgeläufen **nicht identisch**
und bei Vergleichen als Einflussgröße zu berücksichtigen.
9. **Weiterer Weg der Codebasis nach diesem Lauf:** Der für diesen Lauf gelöschte Zustand wurde
zunächst per `git restore .` vollständig auf `89ccfd6` zurückgesetzt. Anschließend wurde die
Codebasis als **eingefrorener Versuchssnapshot** eingerichtet: Das GitHub-Remote
(`NEXOWARE-Systems/CentronERP`) wurde entkoppelt und die KI-Assistenz-Konfigurationen wurden
dauerhaft entfernt (Commit `79c1142`, Parent `89ccfd6`, 92 Dateien, nur lokal – nichts
gepusht). Ab Prompt-Version 02 ist der Untersuchungsgegenstand also `79c1142`. Inhaltlich
unterscheidet er sich von `89ccfd6` ausschließlich um die entfernten KI-Konfigurationen;
der analysierte Produktivcode ist identisch.
@@ -0,0 +1,60 @@
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 28 | 29,2 % |
| SyRS | 28 | 29,2 % |
| SwRS | 40 | 41,7 % |
| **Gesamt** | **96** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| Sicherheit | 38 | 39,6 % |
| funktional | 28 | 29,2 % |
| Daten | 12 | 12,5 % |
| Schnittstelle | 9 | 9,4 % |
| nicht-funktional | 9 | 9,4 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 138 |
| davon `PRIMÄR` | 105 (76,1 %) |
| davon `SEKUNDÄR` | 27 (19,6 %) |
| davon `KONTEXT` | 6 (4,3 %) |
| Belege je Anforderung (Median) | 1,0 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 96 (100,0 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 88 | 91,7 % |
| als `HYPOTHESE` gekennzeichnet | 8 | 8,3 % |
| als Workaround vermerkt | 8 | 8,3 % |
| Konsolidierungskandidaten | 10 | 10,4 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **erfüllt** (49 risikorelevante Anforderungen, alle gedeckt) |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 96 von 96 mit Tracelinks (100,0 %) |
@@ -0,0 +1,82 @@
[
{
"id": "toolu_01XQQaEyB5DtoAwVe7My7V6G",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey BL domains: finance/logistics side",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nFocus on these subfolders of the business logic project `src\\backend\\Centron.BL\\`:\n- Accounting\n- Buying\n- Finances\n- Warehousing\n- Purchasing\n- Production\n- Logistics\n- TradePool\n- VoucherManagement\n- Storage\n\nFor EACH of these folders, report:\n1. Purpose/business domain in one or two sentences, inferred from class/method names and any comments.\n2. The 3-8 most important classes (with exact file path) and what they do.\n3. Any status/state enums or state-machine-like logic (e.g., an enum like `InvoiceStatus`, and methods that transition between states with guard conditions) — quote the enum values and the exact file/method where transitions are enforced.\n4. Any validation logic or business rules enforced in code (e.g. \"cannot post an invoice if X\") — with exact file/method reference.\n5. Any permission/rights checks (e.g. references to UserRightsConst or similar) — exact file/method reference.\n6. Any DB constraints, stored procedures, or SQL visible in these areas (file path).\n\nBe concrete and always cite exact file paths (relative to repo root) and, where feasible, class/method names or line numbers. If a folder is huge, sample representatively rather than reading every file, but note what you skipped.\n\nReport back in a structured format, one section per folder. Keep total response under ~2500 words — prioritize concrete evidence (file paths + short quotes) over prose.",
"ergebnis_zeichen": 14338
},
{
"id": "toolu_013i37jGgA53CAH2PakBm6zR",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey BL domains: sales/customer side",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nFocus on these subfolders of the business logic project `src\\backend\\Centron.BL\\`:\n- Sales (this is large — includes Customer/Helpdesk/ticketing; look for subfolders like Sales\\Customer\\Helpdesk if present)\n- CustomerArea\n- BusinessPartner\n- Projects\n- TicketProjects\n- TaskManager\n- Time\n- CPra\n- EDI\n- Mail\n- Mailings\n\nFor EACH of these folders, report:\n1. Purpose/business domain in one or two sentences, inferred from class/method names and any comments.\n2. The 3-8 most important classes (with exact file path) and what they do.\n3. Any status/state enums or state-machine-like logic (e.g. ticket status, order status) with transition guard conditions — quote enum values and exact file/method.\n4. Any validation logic or business rules enforced in code — exact file/method reference.\n5. Any permission/rights checks (references to UserRightsConst or similar, especially anything matching entries in CentronRights.md like Helpdesk rights) — exact file/method reference.\n6. Any DB constraints, stored procedures, or SQL visible (file path).\n\nBe concrete and always cite exact file paths (relative to repo root) and class/method names or line numbers. Sample representatively for huge folders, note what you skipped.\n\nReport back structured, one section per folder. Keep total response under ~2500 words — prioritize concrete evidence (file paths + short quotes) over prose.",
"ergebnis_zeichen": 13557
},
{
"id": "toolu_019xFjsDuuhReRjdrQ3rxKzG",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey Entities and DAO data model",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nFocus on:\n- src\\backend\\Centron.Entities\\ (data model / entity classes)\n- src\\backend\\Centron.DAO\\ (data access layer)\n- src\\backend\\Centron.Interfaces\\ (interfaces, may reveal contracts)\n- Search the whole repo for .sql files (migration scripts, schema definitions) — report where they live and what a representative one contains (e.g. CREATE TABLE, CHECK, FOREIGN KEY constraints).\n\nReport:\n1. Overall structure of Centron.Entities and Centron.DAO — how are entities organized (by domain folder? one giant namespace?), what ORM/data access pattern is used (NHibernate? Entity Framework? raw ADO.NET? look for mapping files like .hbm.xml or Fluent mappings or DbContext).\n2. List 10-15 core entity classes central to the domain (e.g. things like Customer/Kunde, Order/Auftrag, Invoice/Rechnung, Article/Artikel, Employee/Mitarbeiter) with exact file paths, and their most important fields/relationships.\n3. Any DB-level constraints you can find (NOT NULL, CHECK, FOREIGN KEY, UNIQUE) in .sql or mapping files — exact file + snippet.\n4. Any enums representing status/type fields used across many entities (e.g. a generic status enum) — file path + values.\n5. Evidence of multi-tenancy, soft-delete, audit/history tracking patterns (e.g. a \"ChangeTracking\" mechanism, \"deleted\" flags, \"created by/modified by\" fields) — file path.\n\nBe concrete, cite exact file paths and short code snippets. Sample representatively given the scale, note what you skipped. Keep response under ~2500 words.",
"ergebnis_zeichen": 11901
},
{
"id": "toolu_017VawHGcNQRBJBuHWeTSzib",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey interfaces, webservice and external APIs",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nFocus on:\n- src\\webservice\\ (Centron.Controllers, Centron.Host, Centron.Host.Console, Centron.Host.WindowsService, Centron.WebServices.Core, c-entron.misc.ConnectionManager)\n- src\\apis\\ (Centron.APIs.CopDataAccess, Centron.APIs.EgisDataAccess, Centron.APIs.FinAPI, Centron.APIs.ITscopeDataAccess, Centron.APIs.IcecatDataAccess, Centron.Api.EbInterface, Centron.Api.Gls, Centron.Api.Shipcloud)\n- Centron.Api.docuFORM (top-level folder)\n\nReport:\n1. For src\\webservice: what kind of service is this (REST API? WCF? SOAP?), how are controllers/endpoints organized, list 10-15 representative endpoint/controller classes with exact file paths and what business function they expose. Look for authentication/authorization attributes on controllers (exact file + attribute).\n2. For each external API integration under src\\apis\\ and Centron.Api.docuFORM: what external system does it integrate with (infer from name/code — COP, Egis, FinAPI, ITscope, Icecat, ebInterface [likely e-invoicing], GLS [shipping], Shipcloud [shipping], docuFORM [likely PDF/document generation or e-signature]), what data flows in/out, exact file path for the main client/service class.\n3. Any rate limiting, retry logic, timeout configuration, or error handling policies visible for these integrations — exact file reference.\n4. Any API versioning, request/response DTOs that hint at the external contract shape — exact file path.\n\nBe concrete, cite exact file paths. Sample representatively, note what you skipped. Keep response under ~2500 words.",
"ergebnis_zeichen": 13305
},
{
"id": "toolu_01RenrX7KYjqsYv88VQyog3w",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey security and permissions enforcement",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nGoal: understand how authentication and authorization (\"rights\") work across the system, since this feeds security requirements that need strong evidence.\n\nSteps:\n1. Read C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\CentronRights.md fully (it documents ~a small sample of rights, e.g. Helpdesk, Kalender, Mitarbeiterauslastung) to understand the rights naming convention (UserRightsConst.*).\n2. Find where UserRightsConst is defined (search for \"class UserRightsConst\" or similar) — exact file path, and get a sense of how many rights constants exist total (rough count) and how they're namespaced/organized.\n3. Find the actual enforcement mechanism: search for a method like `HasRight`, `CheckRight`, `IsAllowed`, or similar that takes a UserRightsConst value and returns bool — exact file/class/method. Quote a representative implementation if not too long.\n4. Find 5-10 representative call sites across different modules (Sales, Finances, Security folder, WPF UI) where a right is checked before an action — exact file/line + the right being checked + what it gates.\n5. Look at src\\backend\\Centron.BL\\Security\\ folder specifically — what's in there (authentication, session handling, password management, 2FA — note TwoFactorAuthenticator folder exists in BL too, and PasswordManagementArea/PasswordManager).\n6. Look for any encryption, hashing of passwords, or token-based auth (JWT?) — exact file reference.\n7. Look for any audit logging of security-relevant actions (login, rights changes) — exact file reference.\n\nBe concrete, cite exact file paths and short snippets. Keep response under ~2500 words.",
"ergebnis_zeichen": 11497
},
{
"id": "toolu_016d43StAEwPXmp9HWQNPV5J",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey Nexus web and WPF desktop UI",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nFocus on:\n- src\\nexus\\ (CentronNexus, CentronNexus.Host, CentronNexus.OutlookAddIn) — this is a Blazor-based web frontend, \"c-entron Nexus\" per its README.md\n- src\\centron\\Centron.WPF.UI and Centron.WPF.UI.Extension — the legacy WPF desktop client\n\nReport:\n1. For CentronNexus: what are the main pages/features exposed via the web (look at .razor files, folder structure under Pages or Components). The root README.md mentions a \"WebCart\" feature for customers of customers logging in as a \"web-account\" — find the relevant code (search for WebCart) and describe how it works based on code (exact file paths). List other distinct web-facing features you find (e.g. helpdesk portal, document viewer, offer acceptance / C-Sign — there's a recent commit about \"C-Sign (WebOffer & Acceptance)\", try to find that code).\n2. For Centron.WPF.UI: this is presumably the main desktop ERP client. List the top-level folder/module structure (just directory names, one level or two deep) to map desktop screens to BL domains from Accounting/Sales/Warehousing/etc. Identify how many distinct \"masks\"/views exist roughly (count .xaml files if easy). Look for a Ribbon-related module (mentioned to have custom ribbon merging) — exact folder/file.\n3. Any evidence of role-based UI customization (menus/buttons hidden based on rights) — exact file reference, tie back to UserRightsConst if visible.\n4. Any localization/multi-language evidence (resource files, .resx) — note languages supported if visible.\n\nBe concrete, cite exact file paths. Sample representatively given scale (these are large UI trees), note what you skipped. Keep response under ~2500 words.",
"ergebnis_zeichen": 10366
},
{
"id": "toolu_01Xx1xu6RiPckpy6ENJGacQ8",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey deployment, docs and NFR evidence",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nFocus on non-functional / operational evidence:\n- deployment\\ folder\n- docker\\ folder and .dockerignore at root\n- azure\\ and azure-blazor\\ folders\n- scripts\\ folder\n- docs\\ folder (subfolders: \"Background Service\", features, getting-started, guides, operations, reference) — READ the README.md and a representative sample of files in each subfolder, these are likely genuine feature/ops documentation written by the dev team\n- global.json, Directory.Build.props, nuget.config, version.json at root (just report .NET version / key facts)\n- .github folder (CI/CD workflows — what do they build/test/deploy)\n- tests\\ folder — what test projects exist, roughly how many test files, what's covered (unit/integration/e2e?)\n\nReport:\n1. Deployment architecture as far as inferable (containerized? Azure App Service? on-prem Windows service + desktop client distribution?) — exact file references.\n2. Logging approach (what logging framework, where configured) — exact file reference.\n3. Configuration management (appsettings.json, connection strings, secrets handling) — exact file reference, and flag anything that looks like a hardcoded secret (do NOT quote the secret value, just note file + line and that it looks sensitive).\n4. .NET target framework version(s) used across the solution.\n5. CI/CD: what pipelines exist, what they do (build/test/deploy stages) — exact file reference.\n6. Summarize the docs\\ folder content per subfolder — what topics are documented (this may directly describe existing requirements/features in the dev team's own words) — list file names and one-line summaries.\n7. Test coverage impression: which BL/domain areas have dedicated test projects, which appear to have none.\n\nBe concrete, cite exact file paths. Keep response under ~2500 words.",
"ergebnis_zeichen": 15353
},
{
"id": "toolu_01QVX8oYQyzWKBc1JENviUfE",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Deep dive invoicing, offers and C-Sign billing logic",
"run_in_background": false,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.\n\nThis is a DEEP DIVE into billing/invoicing/offer logic specifically, because these requirements need strong PRIMARY evidence (enforced code/DB constraints, not just UI labels).\n\nRecent commit history mentions:\n- \"Ticket 168496 & 169060 - C-Sign (WebOffer & Acceptance)\" — find this code: search for \"CSign\", \"C-Sign\", \"WebOffer\" across the repo (likely in Centron.BL\\Sales or similar, and in CentronNexus for the web acceptance flow).\n- \"Ticket 150766: rights check for editing invoice or delivery list date in the settings of timer billing\" — search for \"TimerBilling\" or similar in Centron.BL\\Time or Sales, find the rights check added.\n\nAlso investigate generally:\n1. Where is Angebot (offer/quote), Auftrag (order), Lieferschein (delivery note), and Rechnung (invoice) status logic implemented? Look in Centron.BL\\Sales and Centron.BL\\Finances / Accounting. Find the status enum(s) (e.g. quote states: open/accepted/rejected/expired; invoice states: draft/posted/paid/cancelled) — exact file + enum values.\n2. Find the exact method(s) that transition an invoice from draft to \"posted\"/finalized (booked, irreversible) — what validation/guards exist before that transition (e.g. can't post if sum is zero, can't edit after posting)? Exact file/method/line, quote the guard condition code if short.\n3. Find how tax (VAT/MwSt) is calculated — exact file/method.\n4. Find where the C-Sign / WebOffer acceptance flow validates a customer's acceptance (e.g. signature captured, then order status changes) — exact file/method, and what business rule enforces that an offer can only be accepted once / within a validity period, if present.\n5. Find the rights check added for editing invoice/delivery-list dates in timer billing settings (from the commit mentioned above) — exact file/method/UserRightsConst name.\n6. Any DB constraints (in .sql files or mapping) around invoice/financial tables (e.g. immutability, foreign keys to accounting periods) — exact file.\n\nBe concrete, cite exact file paths, class/method names, and short code quotes for guard conditions. This is the highest-scrutiny domain so precision matters more than breadth. Keep response under ~3000 words.",
"ergebnis_zeichen": 8638
}
]
@@ -0,0 +1,232 @@
# Subagenten-Aufrufe
Session `18b1d5b6-f3e3-49cd-b5aa-38bf1fff642c`, Transkript `18b1d5b6-f3e3-49cd-b5aa-38bf1fff642c.jsonl`.
`subagent_stats`: **8** Subagenten gesamt, davon **0** von Subagenten gestartet (max_depth 1). Direkt vom Hauptagenten erwartet: **8**. Im Transkript gefunden: **8**.
## 1. Survey BL domains: finance/logistics side
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1596 **Ergebnis-Zeichen:** 14338
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Focus on these subfolders of the business logic project `src\backend\Centron.BL\`:
- Accounting
- Buying
- Finances
- Warehousing
- Purchasing
- Production
- Logistics
- TradePool
- VoucherManagement
- Storage
For EACH of these folders, report:
1. Purpose/business domain in one or two sentences, inferred from class/method names and any comments.
2. The 3-8 most important classes (with exact file path) and what they do.
3. Any status/state enums or state-machine-like logic (e.g., an enum like `InvoiceStatus`, and methods that transition between states with guard conditions) — quote the enum values and the exact file/method where transitions are enforced.
4. Any validation logic or business rules enforced in code (e.g. "cannot post an invoice if X") — with exact file/method reference.
5. Any permission/rights checks (e.g. references to UserRightsConst or similar) — exact file/method reference.
6. Any DB constraints, stored procedures, or SQL visible in these areas (file path).
Be concrete and always cite exact file paths (relative to repo root) and, where feasible, class/method names or line numbers. If a folder is huge, sample representatively rather than reading every file, but note what you skipped.
Report back in a structured format, one section per folder. Keep total response under ~2500 words — prioritize concrete evidence (file paths + short quotes) over prose.
```
## 2. Survey BL domains: sales/customer side
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1581 **Ergebnis-Zeichen:** 13557
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Focus on these subfolders of the business logic project `src\backend\Centron.BL\`:
- Sales (this is large — includes Customer/Helpdesk/ticketing; look for subfolders like Sales\Customer\Helpdesk if present)
- CustomerArea
- BusinessPartner
- Projects
- TicketProjects
- TaskManager
- Time
- CPra
- EDI
- Mail
- Mailings
For EACH of these folders, report:
1. Purpose/business domain in one or two sentences, inferred from class/method names and any comments.
2. The 3-8 most important classes (with exact file path) and what they do.
3. Any status/state enums or state-machine-like logic (e.g. ticket status, order status) with transition guard conditions — quote enum values and exact file/method.
4. Any validation logic or business rules enforced in code — exact file/method reference.
5. Any permission/rights checks (references to UserRightsConst or similar, especially anything matching entries in CentronRights.md like Helpdesk rights) — exact file/method reference.
6. Any DB constraints, stored procedures, or SQL visible (file path).
Be concrete and always cite exact file paths (relative to repo root) and class/method names or line numbers. Sample representatively for huge folders, note what you skipped.
Report back structured, one section per folder. Keep total response under ~2500 words — prioritize concrete evidence (file paths + short quotes) over prose.
```
## 3. Survey Entities and DAO data model
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1692 **Ergebnis-Zeichen:** 11901
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Focus on:
- src\backend\Centron.Entities\ (data model / entity classes)
- src\backend\Centron.DAO\ (data access layer)
- src\backend\Centron.Interfaces\ (interfaces, may reveal contracts)
- Search the whole repo for .sql files (migration scripts, schema definitions) — report where they live and what a representative one contains (e.g. CREATE TABLE, CHECK, FOREIGN KEY constraints).
Report:
1. Overall structure of Centron.Entities and Centron.DAO — how are entities organized (by domain folder? one giant namespace?), what ORM/data access pattern is used (NHibernate? Entity Framework? raw ADO.NET? look for mapping files like .hbm.xml or Fluent mappings or DbContext).
2. List 10-15 core entity classes central to the domain (e.g. things like Customer/Kunde, Order/Auftrag, Invoice/Rechnung, Article/Artikel, Employee/Mitarbeiter) with exact file paths, and their most important fields/relationships.
3. Any DB-level constraints you can find (NOT NULL, CHECK, FOREIGN KEY, UNIQUE) in .sql or mapping files — exact file + snippet.
4. Any enums representing status/type fields used across many entities (e.g. a generic status enum) — file path + values.
5. Evidence of multi-tenancy, soft-delete, audit/history tracking patterns (e.g. a "ChangeTracking" mechanism, "deleted" flags, "created by/modified by" fields) — file path.
Be concrete, cite exact file paths and short code snippets. Sample representatively given the scale, note what you skipped. Keep response under ~2500 words.
```
## 4. Survey interfaces, webservice and external APIs
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1723 **Ergebnis-Zeichen:** 13305
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Focus on:
- src\webservice\ (Centron.Controllers, Centron.Host, Centron.Host.Console, Centron.Host.WindowsService, Centron.WebServices.Core, c-entron.misc.ConnectionManager)
- src\apis\ (Centron.APIs.CopDataAccess, Centron.APIs.EgisDataAccess, Centron.APIs.FinAPI, Centron.APIs.ITscopeDataAccess, Centron.APIs.IcecatDataAccess, Centron.Api.EbInterface, Centron.Api.Gls, Centron.Api.Shipcloud)
- Centron.Api.docuFORM (top-level folder)
Report:
1. For src\webservice: what kind of service is this (REST API? WCF? SOAP?), how are controllers/endpoints organized, list 10-15 representative endpoint/controller classes with exact file paths and what business function they expose. Look for authentication/authorization attributes on controllers (exact file + attribute).
2. For each external API integration under src\apis\ and Centron.Api.docuFORM: what external system does it integrate with (infer from name/code — COP, Egis, FinAPI, ITscope, Icecat, ebInterface [likely e-invoicing], GLS [shipping], Shipcloud [shipping], docuFORM [likely PDF/document generation or e-signature]), what data flows in/out, exact file path for the main client/service class.
3. Any rate limiting, retry logic, timeout configuration, or error handling policies visible for these integrations — exact file reference.
4. Any API versioning, request/response DTOs that hint at the external contract shape — exact file path.
Be concrete, cite exact file paths. Sample representatively, note what you skipped. Keep response under ~2500 words.
```
## 5. Survey security and permissions enforcement
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1809 **Ergebnis-Zeichen:** 11497
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Goal: understand how authentication and authorization ("rights") work across the system, since this feeds security requirements that need strong evidence.
Steps:
1. Read C:\DEV\MasterArbeit\QuellCode\CentronERP\CentronRights.md fully (it documents ~a small sample of rights, e.g. Helpdesk, Kalender, Mitarbeiterauslastung) to understand the rights naming convention (UserRightsConst.*).
2. Find where UserRightsConst is defined (search for "class UserRightsConst" or similar) — exact file path, and get a sense of how many rights constants exist total (rough count) and how they're namespaced/organized.
3. Find the actual enforcement mechanism: search for a method like `HasRight`, `CheckRight`, `IsAllowed`, or similar that takes a UserRightsConst value and returns bool — exact file/class/method. Quote a representative implementation if not too long.
4. Find 5-10 representative call sites across different modules (Sales, Finances, Security folder, WPF UI) where a right is checked before an action — exact file/line + the right being checked + what it gates.
5. Look at src\backend\Centron.BL\Security\ folder specifically — what's in there (authentication, session handling, password management, 2FA — note TwoFactorAuthenticator folder exists in BL too, and PasswordManagementArea/PasswordManager).
6. Look for any encryption, hashing of passwords, or token-based auth (JWT?) — exact file reference.
7. Look for any audit logging of security-relevant actions (login, rights changes) — exact file reference.
Be concrete, cite exact file paths and short snippets. Keep response under ~2500 words.
```
## 6. Survey Nexus web and WPF desktop UI
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1849 **Ergebnis-Zeichen:** 10366
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Focus on:
- src\nexus\ (CentronNexus, CentronNexus.Host, CentronNexus.OutlookAddIn) — this is a Blazor-based web frontend, "c-entron Nexus" per its README.md
- src\centron\Centron.WPF.UI and Centron.WPF.UI.Extension — the legacy WPF desktop client
Report:
1. For CentronNexus: what are the main pages/features exposed via the web (look at .razor files, folder structure under Pages or Components). The root README.md mentions a "WebCart" feature for customers of customers logging in as a "web-account" — find the relevant code (search for WebCart) and describe how it works based on code (exact file paths). List other distinct web-facing features you find (e.g. helpdesk portal, document viewer, offer acceptance / C-Sign — there's a recent commit about "C-Sign (WebOffer & Acceptance)", try to find that code).
2. For Centron.WPF.UI: this is presumably the main desktop ERP client. List the top-level folder/module structure (just directory names, one level or two deep) to map desktop screens to BL domains from Accounting/Sales/Warehousing/etc. Identify how many distinct "masks"/views exist roughly (count .xaml files if easy). Look for a Ribbon-related module (mentioned to have custom ribbon merging) — exact folder/file.
3. Any evidence of role-based UI customization (menus/buttons hidden based on rights) — exact file reference, tie back to UserRightsConst if visible.
4. Any localization/multi-language evidence (resource files, .resx) — note languages supported if visible.
Be concrete, cite exact file paths. Sample representatively given scale (these are large UI trees), note what you skipped. Keep response under ~2500 words.
```
## 7. Survey deployment, docs and NFR evidence
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 1973 **Ergebnis-Zeichen:** 15353
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
Focus on non-functional / operational evidence:
- deployment\ folder
- docker\ folder and .dockerignore at root
- azure\ and azure-blazor\ folders
- scripts\ folder
- docs\ folder (subfolders: "Background Service", features, getting-started, guides, operations, reference) — READ the README.md and a representative sample of files in each subfolder, these are likely genuine feature/ops documentation written by the dev team
- global.json, Directory.Build.props, nuget.config, version.json at root (just report .NET version / key facts)
- .github folder (CI/CD workflows — what do they build/test/deploy)
- tests\ folder — what test projects exist, roughly how many test files, what's covered (unit/integration/e2e?)
Report:
1. Deployment architecture as far as inferable (containerized? Azure App Service? on-prem Windows service + desktop client distribution?) — exact file references.
2. Logging approach (what logging framework, where configured) — exact file reference.
3. Configuration management (appsettings.json, connection strings, secrets handling) — exact file reference, and flag anything that looks like a hardcoded secret (do NOT quote the secret value, just note file + line and that it looks sensitive).
4. .NET target framework version(s) used across the solution.
5. CI/CD: what pipelines exist, what they do (build/test/deploy stages) — exact file reference.
6. Summarize the docs\ folder content per subfolder — what topics are documented (this may directly describe existing requirements/features in the dev team's own words) — list file names and one-line summaries.
7. Test coverage impression: which BL/domain areas have dedicated test projects, which appear to have none.
Be concrete, cite exact file paths. Keep response under ~2500 words.
```
## 8. Deep dive invoicing, offers and C-Sign billing logic
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** False
- **Prompt-Zeichen:** 2373 **Ergebnis-Zeichen:** 8638
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements effort. This is READ-ONLY research — do not modify anything.
This is a DEEP DIVE into billing/invoicing/offer logic specifically, because these requirements need strong PRIMARY evidence (enforced code/DB constraints, not just UI labels).
Recent commit history mentions:
- "Ticket 168496 & 169060 - C-Sign (WebOffer & Acceptance)" — find this code: search for "CSign", "C-Sign", "WebOffer" across the repo (likely in Centron.BL\Sales or similar, and in CentronNexus for the web acceptance flow).
- "Ticket 150766: rights check for editing invoice or delivery list date in the settings of timer billing" — search for "TimerBilling" or similar in Centron.BL\Time or Sales, find the rights check added.
Also investigate generally:
1. Where is Angebot (offer/quote), Auftrag (order), Lieferschein (delivery note), and Rechnung (invoice) status logic implemented? Look in Centron.BL\Sales and Centron.BL\Finances / Accounting. Find the status enum(s) (e.g. quote states: open/accepted/rejected/expired; invoice states: draft/posted/paid/cancelled) — exact file + enum values.
2. Find the exact method(s) that transition an invoice from draft to "posted"/finalized (booked, irreversible) — what validation/guards exist before that transition (e.g. can't post if sum is zero, can't edit after posting)? Exact file/method/line, quote the guard condition code if short.
3. Find how tax (VAT/MwSt) is calculated — exact file/method.
4. Find where the C-Sign / WebOffer acceptance flow validates a customer's acceptance (e.g. signature captured, then order status changes) — exact file/method, and what business rule enforces that an offer can only be accepted once / within a validity period, if present.
5. Find the rights check added for editing invoice/delivery-list dates in timer billing settings (from the commit mentioned above) — exact file/method/UserRightsConst name.
6. Any DB constraints (in .sql files or mapping) around invoice/financial tables (e.g. immutability, foreign keys to accounting periods) — exact file.
Be concrete, cite exact file paths, class/method names, and short code quotes for guard conditions. This is the highest-scrutiny domain so precision matters more than breadth. Keep response under ~3000 words.
```
@@ -0,0 +1,69 @@
# Analysebericht
**Status: ENTWURF / IN BEARBEITUNG** — dieser Bericht wird laufend während der Analyse aktualisiert und am Ende der Iteration finalisiert (Konsistenzcheck, Selbstbewertung).
## 1. Untersuchungsgegenstand
Codebasis: `C:\DEV\MasterArbeit\QuellCode\CentronERP` (c-entron ERP-Suite), Git-Branch `main`, Stand des Commits `79c1142f48`.
Umfang (statische Auszählung): 22.346 Dateien unter `src/`, davon 15.554 `.cs`-Dateien, 1.233 `.xaml`-Dateien, 491 `.razor`-Dateien. Keine `.sql`-Skriptdateien im Repository gefunden (Datenbankschema wird über C#-Migrationsklassen ausgerollt, siehe unten).
Hinweis: Der jüngste Commit (`79c1142f48`, "Versuchsbasis: KI-Assistenz-Konfigurationen entfernt") hat `.claude/`, `CLAUDE.md` und `.cursor/` entfernt; einige interne Entwicklerdokumente (`docs/getting-started/ai-codebase-navigation.md`) verweisen noch auf diese entfernten Dateien. Dies ist für die vorliegende Analyse ohne Belang, wird aber der Vollständigkeit halber dokumentiert.
## 2. Architektur-Überblick (grob)
| Bereich | Pfad | Rolle |
|---|---|---|
| Backend-Geschäftslogik | `src/backend/Centron.BL` | Serverseitige Fachlogik, NHibernate-Zugriff, ~90 fachliche Unterordner |
| Backend-Datenzugriff | `src/backend/Centron.DAO` | FluentNHibernate-Mappings |
| Backend-Entitäten | `src/backend/Centron.Entities` | NHibernate-Entity-Klassen |
| Gemeinsame Verträge | `src/backend/Centron.Interfaces` | Rechte-, Settings-, Lizenz-Konstanten; Legacy-REST-Contract (`ICentronRestService`) |
| WPF-Desktop-Client | `src/centron/Centron.WPF.UI` | Hauptanwendung "c-entron.NET" (Windows) |
| Web-API (modern) | `src/webservice/Centron.Controllers` | ASP.NET-Core-Controller (`v1/...`, `Unversioned/...`) |
| Web-API (legacy) | `src/webservice/Centron.WebServices.Core` | Legacy-REST-Dienst (`CentronRestService.cs`), DTOs |
| Web-Hosts | `src/webservice/Centron.Host*` | Hostprozesse (Console, Windows-Dienst) |
| Web-Portal | `src/nexus/CentronNexus` | Blazor-Server-Webclient ("c-entron Nexus"), inkl. WebCart/WebOffer/C-Sign |
| Externe Integrationen | `src/apis/*` | Distributoren-/Katalog-/Versand-/Finanz-Schnittstellen (CopDataAccess, EgisDataAccess, ITscopeDataAccess, IcecatDataAccess, FinAPI, EbInterface, Gls, Shipcloud) |
| Geteilte Bausteine | `src/shared/*` | `Centron.Core`, `Centron.Controls` |
| Tests | `tests/*` | Unit (BL/DAO), Integration, End-to-End, Playwright, Nexus-Tests |
| Deployment | `docker/`, `azure/`, `azure-blazor/`, `deployment/` | Docker-Compose-Stack, Azure-Pipelines, WiX-Installer |
Quelle: eigene Verzeichniserhebung (`find`, `.csproj`-Liste) und `docs/getting-started/ai-codebase-navigation.md`, `docs/getting-started/general-structure.md`.
## 3. Modul-/Themenabdeckung dieser Iteration (wird laufend aktualisiert)
Legende Analysetiefe: **TIEF** (Code + Dokumentation gelesen, mehrere Belege), **MITTEL** (Dokumentation + stichprobenhafte Code-Belege), **OBERFLÄCHLICH** (nur Verzeichnisstruktur/Namen erhoben), **NICHT ANALYSIERT**.
| Fachbereich (Centron.BL-Ordner u. verwandte Bereiche) | Analysetiefe | Quelle(n) |
|---|---|---|
| Web-API / Auth / Nexus / Deployment (Systemarchitektur) | TIEF | Subagent-Recherche (Controllers, Authorization, CentronHost.cs, Nexus, Docker/Azure-Pipelines) |
| Sales – Belegsystem (Angebot/Auftrag/Lieferschein/Rechnung/Gutschrift/Abholschein) | TIEF | `docs/reference/receipts/receipts-backend-architecture.md` + Subagent-Recherche |
| Sales – Verträge (Contracts, Kontingente, RMM-Abrechnung) | TIEF | `docs/reference/receipts/contracts-backend.md`, `Contract-Billing-RMM-Article-Logic.md` |
| Security / Rechte (Sichrech, UserRightsConst) | MITTEL–TIEF | `CentronRights.md`, `docs/guides/development/add-a-new-right.md`, `check-userrights.md` + Subagent-Recherche |
| Lizenzsystem | TIEF | `docs/reference/security/licensing-system.md` |
| Authentifizierung (Ticket, JWT/OIDC) | TIEF | `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` + Subagent-Recherche |
| Einstellungen (ApplicationSettings/Stammdat) | MITTEL | `docs/guides/development/settings-management.md` |
| EDI (Lieferanten-Datenaustausch) | MITTEL | `docs/reference/edi/edi-architecture.md` |
| ActionPrice / Preismatrix | MITTEL–TIEF | `docs/reference/receipts/actionprice-system.md` |
| Helpdesk / Ticket (inkl. automatische Ticketerstellung) | MITTEL | `CentronRights.md`, `docs/features/automatic-helpdesk-creation-templates.md` |
| Datenbank-Konventionen (Schema, Skripte) | TIEF | `docs/guides/database/database-conventions.md`, `docs/reference/database/script-rules.md` |
| Architekturmuster (ILogic/BL/WS, DTO/Entity, Result/Response) | TIEF | `docs/getting-started/general-structure.md`, `docs/reference/architecture/*.md` |
| Lokalisierung (DE/EN) | MITTEL | `docs/guides/ui/localization.md` |
| Hintergrunddienste (DataQualityService) | MITTEL | `docs/Background Service/DataQualityService.md` |
| Buying/Purchasing, Warehousing, Logistics, TradePool | *ausstehend* | Subagent-Recherche läuft |
| BusinessPartner/CRM, Angebots-/Auftragsstatus, C-Sign | *ausstehend* | Subagent-Recherche läuft |
| Accounting/Finances, Voucher-Nummernkreise, Zahlungslogik | *ausstehend* | Subagent-Recherche läuft |
| Entities/DAO-Konventionen (Concurrency, Multi-Tenancy, Soft-Delete) | *ausstehend* | Subagent-Recherche läuft |
| Alle übrigen ~75 `Centron.BL`-Unterordner (u. a. Production, TicketProjects, MailScanner, Mobile, Outlook, TwoFactorAuthenticator im Detail, VideoPortal, SocialMedia, ItPlanner, ProductMatrix, Chats, Notifications, Mailings, WebSuite, Tapi, TaskManager, ToDoArea u. v. m.) | NICHT ANALYSIERT | nur Verzeichnisname erhoben |
| WPF-Client-Module im Detail (`Centron.WPF.UI/Modules/*`) | NICHT ANALYSIERT | nur Verzeichnisstruktur erhoben |
| Externe API-Integrationen im Detail (COP, EGIS, ITscope, Icecat, FinAPI, EbInterface, GLS, Shipcloud) | OBERFLÄCHLICH | *ausstehend*, teilweise durch Purchasing-Subagent |
*Dieser Abschnitt wird nach Abschluss aller Teilrecherchen final aktualisiert (Abschnitt "Selbstbewertung" unten).*
## 4. Konsistenzcheck
*Wird nach Fertigstellung aller Anforderungsdokumente durchgeführt (doppelte IDs, Anforderungen ohne Beleg, ungültige Tracelinks).*
## 5. Selbstbewertung
*Wird am Ende der Iteration ergänzt.*
@@ -0,0 +1,45 @@
# Glossar
Domänenbegriffe, die in StRS/SyRS/SwRS verwendet werden. Technische Bezeichner (Klassen, Tabellen, Methoden) bleiben unübersetzt. Quellenangaben sind Sekundär-/Kontextbelege für die Begriffsklärung, nicht für die zugehörigen Anforderungen (diese führen eigene Belege).
| Begriff | Definition | Quelle (Kontext) |
|---|---|---|
| **I3D** | Primärschlüsselspalte ("ID 3develop") jeder Tabelle; `int IDENTITY(1,1) NOT NULL`, geclusterter PK. Fremdschlüssel enden auf das Suffix `I3D` (z. B. `AccountI3D`). | `docs/guides/database/database-conventions.md` |
| **Beleg / Receipt** | Sammelbegriff für die kaufmännischen Vorgangsdokumente der Sales-Pipeline. Alle Belegtypen erben von der abstrakten Basisklasse `ReceiptBase` (`src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs`). | `docs/reference/receipts/receipts-backend-architecture.md` |
| **Angebot (Offer)** | Beleg-Typ "Angebot"; Entity `ReceiptOffer`, Tabelle `AngKopf`/`AngPos`, View `Offers`/`OfferItems`. | ebd. |
| **Auftrag (Order)** | Beleg-Typ "Auftrag"; Entity `ReceiptOrder`, Tabelle `AufKopf`/`AufPos`, View `Orders`/`OrderItems`. | ebd. |
| **Lieferschein (Delivery List)** | Beleg-Typ "Lieferschein"; Entity `ReceiptDeliveryList`, Tabelle `LiefKopf`/`LiefPos`. | ebd. |
| **Rechnung (Invoice)** | Beleg-Typ "Rechnung"; Entity `ReceiptInvoice`, Tabelle `RechKopf`/`RechPos`. | ebd. |
| **Vertrag (Contract)** | Beleg-Typ für wiederkehrende Leistungen/Verträge; Entity `ReceiptContract`, Tabelle `VertragKopf`/`VertragPos`; unterstützt Abrechnungsintervalle, Kontingente, Geräteanbindung. | `docs/reference/receipts/contracts-backend.md` |
| **Gutschrift (Credit Voucher)** | Beleg-Typ "Gutschrift"; Entity `ReceiptCreditVoucher`, Tabelle `GutKopf`/`GutPos`. | `docs/reference/receipts/receipts-backend-architecture.md` |
| **Abholschein (Pickup List)** | Beleg-Typ "Abholschein"; Entity `ReceiptPickupList`, Tabelle `AbholKopf`/`AbholPos`. | ebd. |
| **Kopf/Pos-Muster** | Wiederkehrendes DB-Muster: `*Kopf`-Tabelle für den Belegkopf, `*Pos`-Tabelle für Positionszeilen, `*KopfVersions`/`*PosVersions` für 1:1-Versionshistorie. | ebd. |
| **AnlageLog** | Zentrale, tabellenübergreifende Protokolltabelle für Belegereignisse; referenziert über `AnlageI3D` + `AnlageArt` (Typkennzahl je Belegtyp, z. B. 4 = Rechnung, 22 = Vertrag). | ebd. |
| **Kontingent (Contingent)** | Im Vertrag hinterlegtes Leistungs-/Stundenbudget, das durch Leistungen verbraucht wird (`ContingentUsedHours`, `ContingentUsedAmount`, `ContingentLimitValue` u. a.). | `docs/reference/receipts/contracts-backend.md` |
| **RMM (Remote Monitoring & Management)** | Externes Überwachungssystem (Produktname intern "Riverbird"), aus dem Nutzungsdaten für die automatische Vertragsabrechnung bezogen werden (`RiverConnectionBL`). | `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` |
| **Sichrech** | Datenbanktabelle, die alle Berechtigungen ("Rechte") des Systems auflistet; jede Zeile entspricht einer Konstante in `UserRightsConst.cs`. | `docs/guides/development/add-a-new-right.md` |
| **Recht (Right)** | Feingranulare, hierarchisch organisierte Berechtigung (z. B. `UserRightsConst.Sales.Customer.Helpdesk.SHOW_HELPDESK`); kann Gruppen zugewiesen werden; "einschränkende Rechte" (restricting rights) filtern statt zu gewähren (z. B. "nur eigene Filiale"). | `CentronRights.md`, `docs/guides/development/check-userrights.md` |
| **Filiale (Branch)** | Organisationseinheit, nach der Datensätze isoliert/gefiltert werden können (`BranchI3D`); Basis mehrerer "einschränkender Rechte". | `CentronRights.md` |
| **Mandant** | (Hypothesenkandidat, siehe Hypothesen.md) Mögliche Mehrmandantenfähigkeit oberhalb der Filialebene. | |
| **Lizenz (License)** | GUID-basiertes Merkmal, das eine Anwendung ("Application", darf sich am Webservice anmelden) oder ein Einzelfeature freischaltet; verwaltet in `LicenseGuids.cs`/`ApplicationKind.cs`, geprüft via `LicenseManager`. | `docs/reference/security/licensing-system.md` |
| **Ticket (Application/Auth)** | Sitzungs-Token, das nach erfolgreichem Login clientseitig für weitere API-Aufrufe verwendet wird; serverseitig in Tabelle `Ticket` mit Ablaufzeit (u. a. 30 Minuten bei OIDC-Login). | `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` |
| **BL (Business Logic)** | Serverseitige Geschäftslogik-Schicht, arbeitet direkt mit NHibernate-Entities und der DB (`Centron.BL`). | `docs/getting-started/general-structure.md` |
| **WebServiceBL** | Schicht, die Entities in DTOs konvertiert und die Webservice-Methoden bereitstellt. | ebd. |
| **DTO (Data Transfer Object)** | Datenübertragungsobjekt zwischen WebService und Client/ViewModel; darf keine Fachlogik enthalten. | `docs/reference/architecture/dtos-and-entities.md` |
| **ILogic / BLLogic / WSLogic** | Dreiteiliges Client-Zugriffsmuster: `ILogic`-Interface, `BLLogic`-Implementierung (Direktzugriff SQL Server) und `WSLogic`-Implementierung (Webservice-Zugriff); pro Modul verpflichtend beide Implementierungen. | `docs/getting-started/general-structure.md` |
| **ClassContainer** | Client-seitiger DI-Container/Singleton, der die passende `ILogic`-Implementierung (BL oder WS) je nach Verbindungstyp auflöst. | ebd. |
| **Result / Response** | Internes (`Result`/`Result<T>`) bzw. API-seitiges (`Response`/`Response<T>`) Standardobjekt für Erfolg/Fehler/Warnung-Status und Fehlermeldungen. | `docs/reference/architecture/results-and-responses.md` |
| **ActionPrice (Aktionspreis)** | Zeitlich befristeter Sonderpreis von Distributoren/Herstellern zu einem Artikel; eigene Quelle innerhalb der "Preismatrix" neben externen Preisquellen (ITscope, COP, NEOS, TradersGuide, EGIS). | `docs/reference/receipts/actionprice-system.md` |
| **Preismatrix (Price Matrix)** | UI/Backend-Mechanismus, der Einkaufspreise aus mehreren internen/externen Quellen parallel für einen Artikel anzeigt. | ebd. |
| **EDI (Electronic Data Interchange)** | Automatisierter elektronischer Belegaustausch mit Lieferanten (Bestellungen, Auftragsbestätigungen, Lieferungen, Rechnungen) über lieferantenspezifische Formate (OpenTrans 2.1, ALSO, ALSO CH, Herweck, Komsa, Alltron) sowie ZUGFeRD für Rechnungen. | `docs/reference/edi/edi-architecture.md` |
| **ZUGFeRD / XRechnung** | Standards für strukturierte/elektronische Rechnungen (Deutschland); im System als Datenaustauschformat für Rechnungen verankert (u. a. `IsZugferdInvoiceActive`-Einstellung). | `docs/guides/development/xrechnung.md`, `docs/guides/development/settings-management.md` |
| **C-Sign** | Funktion zur elektronischen Unterschrift/Annahme von Web-Angeboten durch den Kunden (WebOffer & Acceptance). | Commit `89ccfd650d` "Ticket 168496 & 169060 - C-Sign (WebOffer & Acceptance)" |
| **WebCart** | Self-Service-Bestellfunktion für Kunden der Kunden (Endkunden mit Web-Account), basierend auf hinterlegten "Sonderpreisen". | `README.md` (Nexus) |
| **TradePool** | Eigenständiges BL-Modul (`Centron.BL/TradePool`); Funktion gemäß Codebasis noch nicht abschließend verifiziert (siehe Hypothesen.md). | |
| **Nexus (c-entron Web / c-entron Nexus)** | Blazor-Server-basierter Web-Client des Systems, u. a. für Kundenportal-/WebCart-Funktionen; nutzt DevExpress-Blazor-Komponenten. | `README.md`, `docs/getting-started/ai-codebase-navigation.md` |
| **c-entron.NET (WPF-Client)** | Desktop-Hauptclient des ERP-Systems (Windows/WPF), Projekt `Centron.WPF.UI`. | `docs/getting-started/general-structure.md` |
| **DataQualityService** | Serverseitiger Hintergrunddienst (`BackgroundService`), der stündlich Datenbereinigungs- und Konsistenzaufgaben ausführt. | `docs/Background Service/DataQualityService.md` |
| **DeveloperSecurity** | Schutzmechanismus, der in Debug-Builds E-Mail-Versand an externe (nicht-`nexoware.com`) Adressen automatisch auf eine Testadresse umleitet. | `docs/reference/security/developer-security.md` |
| **ApplicationSettings / Stammdat** | Zwei parallele DB-Tabellen für Systemeinstellungen; `Stammdat` ist die historische, `ApplicationSettings` die aktuelle Tabelle für neue Einstellungen. | `docs/guides/development/settings-management.md` |
*Weitere Begriffe werden bei Bedarf in Folge-Iterationen ergänzt (siehe Analysebericht.md, Abschnitt "Empfehlungen für Folge-Iteration").*
@@ -0,0 +1,896 @@
# StRS — Stakeholder Requirements Specification
c-entron ERP-Suite — Reverse Requirements Engineering, Iteration 01 (Baseline).
Fachliche Sicht: Akteure, Geschäftsziele, Geschäftsprozesse. Ebene: `StRS`.
Akteure (aus Rechte-/Modulanalyse abgeleitet, `[HYPOTHESE]`-Anteile siehe Hypothesen.md):
Innendienst-/Vertriebsmitarbeiter, Einkäufer, Lager-/Logistikmitarbeiter, Buchhaltung/Controlling, Servicetechniker/Helpdesk-Bearbeiter, Systemadministrator, Kunde (Web-Account/WebCart), Endkunde ohne Web-Account (nur Angebotsempfänger via C-Sign), externer Lieferant/Distributor (EDI-Gegenstelle), c-entron/NEXOWARE-Entwickler & DevOps.
---
## A. Beleg-Lebenszyklus & Belegweiterleitung (Sales Order-to-Cash)
```
ID: StRS-001
Titel: Einheitlicher Belegzyklus für kaufmännische Vorgangsdokumente
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter, System
Vorbedingung: Ein Geschäftsvorfall (Angebot, Auftrag, Lieferschein, Rechnung, Vertrag, Gutschrift, Abholschein) wird angelegt.
Fakt: Alle Belegtypen erben von der gemeinsamen Basisklasse `ReceiptBase` und nutzen denselben Statuswert `ReceiptState` (`Active`=offen, `Completed`=abgeschlossen, `Canceled`=storniert).
Aussage: Das System soll alle kaufmännischen Belegarten (Angebot, Auftrag, Lieferschein, Rechnung, Vertrag, Gutschrift, Abholschein) über ein einheitliches, gemeinsames Belegmodell mit denselben drei Grundzuständen (offen/abgeschlossen/storniert) abbilden.
Ergebnis: Jeder Beleg besitzt zu jedem Zeitpunkt genau einen der drei definierten Zustände; belegtypübergreifende Auswertungen und UI-Bausteine sind wiederverwendbar.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 - Begründung: Definiert die durchgesetzte Zustandsmenge (Active=1, Completed=2, Canceled=3), von der `ReceiptBase.State` typisiert ist.
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs - Begründung: Abstrakte Basisklasse, von der alle sieben Belegentitäten (ReceiptOffer, ReceiptOrder, ReceiptDeliveryList, ReceiptInvoice, ReceiptContract, ReceiptCreditVoucher, ReceiptPickupList) erben.
- [SEKUNDÄR] docs/reference/receipts/receipts-backend-architecture.md - Begründung: Beschreibt die Belegtyp-Tabelle und das Kopf/Pos-Muster für alle sieben Belegarten.
Prüfidee: Für jeden der sieben Belegtypen erzeugen, in jeden der drei Zustände überführen und prüfen, dass kein vierter Zustand erreichbar ist.
Tracelinks: SyRS-001, SyRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-002
Titel: Kontrollierte Belegweiterleitung entlang der Vertriebskette
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter
Vorbedingung: Ein Beleg (z. B. Angebot) existiert und soll in einen Folgebeleg überführt werden.
Fakt: Jeder Belegtyp deklariert über `IReceiptSpecificLogic` explizit, aus welchen Belegtypen er weitergeleitet werden darf (`CanBeForwardedFrom`) und in welche Belegtypen er weitergeleitet werden darf (`CanBeForwardedInto`); z. B. darf ein Auftrag nur aus einem Angebot entstehen und nur in Lieferschein, Rechnung oder Vertrag weitergeleitet werden.
Aussage: Das System soll die Weiterleitung eines Belegs in einen Folgebeleg nur entlang fachlich vordefinierter, je Belegtyp konfigurierter Übergänge zulassen.
Ergebnis: Unzulässige Belegübergänge (z. B. direkte Umwandlung eines Lieferscheins in ein Angebot) werden verhindert; die Vertriebskette Angebot→Auftrag→Lieferschein/Rechnung/Vertrag bleibt nachvollziehbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:256-257 - Begründung: `CanBeForwardedFrom() => [OfferClass]`, `CanBeForwardedInto() => [DeliveryListClass, InvoiceClass, ContractClass]` legen den erlaubten Übergangsgraphen für Aufträge fest.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs (ForwardReceipt<TTarget,...>) - Begründung: Zentrale, generische Weiterleitungsmethode, die die deklarierten Übergänge durchsetzt.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/CustomerAssets/Offers/OfferBL.cs:98-106 (ForewardOfferToOrder) - Begründung: Konkrete Implementierung des Übergangs Angebot→Auftrag im (parallelen) Legacy-Belegsystem.
Prüfidee: Versuch, einen Lieferschein direkt in ein Angebot umzuwandeln, muss vom System zurückgewiesen werden; Angebot→Auftrag muss gelingen.
Tracelinks: SyRS-003
Konsolidierung: Kandidat: Zwei parallele Implementierungen (Legacy "Asset"-System `Sales/CustomerAssets/*` und modernes "Receipt"-System `Sales/Receipts/*`) bilden denselben Belegzyklus und dieselbe Weiterleitungslogik redundant ab (siehe SwRS-Abschnitt "Datenmodell").
Status: belegt
```
```
ID: StRS-003
Titel: Nachvollziehbare Versionshistorie kaufmännischer Belege
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter, Buchhaltung, Systemadministrator (Revisionssicherheit)
Vorbedingung: Ein bestehender Beleg wird inhaltlich geändert (z. B. Stornierung, Preisänderung, Feldänderung nach Erstanlage).
Fakt: Für jeden Belegtyp existiert eine 1:1-Versions-Schattentabelle (`*KopfVersions`/`*PosVersions`), die bei jeder relevanten Änderung eine vollständige Kopie des vorherigen Zustands anlegt; jede neue Spalte muss zwingend auch in der Versionstabelle ergänzt werden.
Aussage: Das System soll bei jeder wesentlichen Änderung eines Belegs eine vollständige, unveränderliche Kopie des vorherigen Belegzustands (Kopf und Positionen) revisionssicher speichern.
Ergebnis: Zu jedem Beleg ist die vollständige Änderungshistorie inklusive früherer Werte rekonstruierbar.
Belege:
- [PRIMÄR] docs/reference/receipts/receipts-backend-architecture.md (Abschnitt "Version Tables: 1:1 Copies") - Begründung: Dokumentiert Pflicht zur identischen Spaltenstruktur zwischen Basis- und Versionstabelle sowie den `AssetHeadDAO.SaveAssetVersion`-Mechanismus.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs (CancelInvoice, CreateNewVersion) - Begründung: Eine Rechnungsstornierung erzeugt nachweislich eine neue Version statt den Beleg in-place zu verändern.
- [SEKUNDÄR] docs/reference/receipts/contracts-backend.md - Begründung: Bestätigt dasselbe Muster für Verträge (VertragKopfVersions/VertragPosVersions).
Prüfidee: Rechnung stornieren und prüfen, dass eine neue Version erzeugt wird und die ursprünglichen Werte in der Versionstabelle erhalten bleiben.
Tracelinks: SyRS-004, SyRS-005
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-004
Titel: Schutz vor gleichzeitiger Bearbeitung desselben Belegs
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter
Vorbedingung: Zwei Benutzer öffnen denselben Beleg gleichzeitig zur Bearbeitung.
Fakt: Es existieren zwei parallele Schutzmechanismen: ein anwendungsseitiges pessimistisches Sperrobjekt je Belegtyp (`*Lock`-Entität mit `Lockuser`-Spalte) sowie ein optimistisches `ConcurrencyControlGuid`-Feld auf `ReceiptBase`, das bei Speicherung auf Konflikt geprüft wird.
Aussage: Das System soll verhindern, dass zwei Benutzer denselben Beleg gleichzeitig widersprüchlich bearbeiten und speichern können.
Ergebnis: Ein zweiter Benutzer erhält beim Versuch, einen gesperrten oder zwischenzeitlich geänderten Beleg zu speichern, eine Fehlermeldung statt eines stillen Datenverlusts.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/CustomerAssets/AssetLocks/AssetLock.cs:6-10 - Begründung: Enthält `Lockuser` und `Version`, das explizite anwendungsseitige Sperrmodell.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs (UpdateReceiptIsPaid, ConcurrencyControlGuid-Prüfung) - Begründung: Verifizierter Code-Pfad, der bei Guid-Mismatch einen Fehler zurückgibt.
- [SEKUNDÄR] tests/Centron.Tests.EndToEnd/Tests/ReceiptLock/*.expected.txt (8 Testfälle) - Begründung: End-to-End-Tests decken alle Kombinationen aus "gesperrt/nicht gesperrt", "durch anderen Benutzer gesperrt" und "Benutzerrecht vorhanden" ab und bestätigen, dass dies als geschäftskritische Regel getestet wird.
Prüfidee: Beleg durch Benutzer A öffnen (sperren), Speicherversuch durch Benutzer B muss abgelehnt bzw. mit Hinweis versehen werden.
Tracelinks: SyRS-006
Konsolidierung: Kandidat: Zwei redundante Mechanismen (pessimistische Sperre + optimistisches Concurrency-Guid) lösen dieselbe fachliche Anforderung; im Zielsystem auf einen Mechanismus konsolidieren.
Status: belegt
```
## B. Verträge & wiederkehrende Abrechnung
```
ID: StRS-005
Titel: Automatisierte, intervallbasierte Vertragsabrechnung
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, Vertriebsinnendienst
Vorbedingung: Ein Servicevertrag mit konfiguriertem Abrechnungsintervall (täglich/monatlich/quartalsweise/jährlich) und `AutomatedBilling = true` existiert.
Fakt: `ReceiptContract` besitzt Felder `BillingIntervalKind`, `BillingIntervalDuration`, `AutomatedBilling`; `AutomaticFacturaBL.Contracts` erzeugt automatisiert Rechnungen auf Basis der Intervallkonfiguration.
Aussage: Das System soll wiederkehrende Vertragsleistungen automatisiert gemäß dem konfigurierten Abrechnungsintervall in Rechnungen überführen, ohne dass für jede Abrechnung eine manuelle Rechnungserstellung nötig ist.
Ergebnis: Fällige Verträge werden zum Stichtag automatisch abgerechnet; das Abrechnungsdatum des Vertrags wird fortgeschrieben.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs (BillingIntervalKind, AutomatedBilling, LastSubsequentBillingDate) - Begründung: Datenmodell erzwingt Erfassung der Abrechnungskonfiguration am Vertrag.
- [SEKUNDÄR] docs/reference/receipts/contracts-backend.md (Abschnitt "Automated Billing Process") - Begründung: Beschreibt den dreistufigen Ablauf Contract Evaluation → Invoice Generation → Post-Processing.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs - Begründung: Konkrete Klasse für automatisierte Vertragsabrechnung inkl. RMM-Integration.
Prüfidee: Vertrag mit monatlichem Intervall und fälligem Abrechnungsdatum anlegen, Abrechnungslauf ausführen, Rechnung sowie fortgeschriebenes `LastSubsequentBillingDate` prüfen.
Tracelinks: SyRS-007, SyRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-006
Titel: Verbrauchsbasierte Abrechnung aus externem Monitoring-System (RMM)
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, Servicetechniker
Vorbedingung: Ein Vertrag ist für RMM-Abrechnung konfiguriert (`WhetherRMM` = true) und besitzt Artikelreferenzen zu RMM-Metriken.
Fakt: Während `CreateInvoiceToContractComplete` ruft `CheckRMMArticle` den externen RMM-Dienst ("Riverbird") über `RiverConnectionBL.GetContractBillingAmounts` ab und fügt für jede Artikelreferenz mit Nutzungsdaten eine berechnete Rechnungsposition ein; ist der Dienst nicht erreichbar und werden RMM-Artikel erwartet, wird eine `RMMServiceUnavailableException` geworfen und die Rechnungserstellung abgebrochen.
Aussage: Das System soll nutzungsbasierte Vertragspositionen automatisch anhand von Messdaten eines externen Remote-Monitoring-Systems berechnen und in die Rechnung einfügen; ist der externe Dienst nicht erreichbar, darf keine Rechnung mit unvollständigen Nutzungsdaten erzeugt werden.
Ergebnis: Entweder wird die Rechnung mit korrekten, aktuellen Nutzungsdaten erstellt, oder die Erstellung wird kontrolliert abgebrochen (kein stillschweigend falscher Rechnungsbetrag).
Belege:
- [PRIMÄR] docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md (Abschnitt "Error Handling") - Begründung: Beschreibt den Abbruchmechanismus samt zitiertem Code (`RMMServiceUnavailableException`) und die fachliche Begründung ("ensuring customers are billed correctly").
- [PRIMÄR] AutomaticFacturaWebServiceBL / RiverConnectionBL (referenziert in obiger Doku) - Begründung: Konkrete Klassen der Nutzungsdatenabfrage und Rechnungspositionserzeugung.
Prüfidee: Rechnungslauf für einen RMM-Vertrag bei simuliert nicht erreichbarem RMM-Dienst ausführen; erwartetes Ergebnis: Abbruch mit definierter Fehlermeldung, keine Rechnung erzeugt.
Tracelinks: SyRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-007
Titel: Kontingentverwaltung für Servicevereinbarungen
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, Servicetechniker
Vorbedingung: Ein Vertrag mit Leistungskontingent (Stunden oder Betrag) existiert.
Fakt: `ReceiptContract` führt `ContingentUsedHours`, `ContingentUsedAmount`, `ContingentLimitValue`, `ContingentLimitKind`, `IsMonitoring`; `ReceiptContractBL.ContractContingentBalanceCalculation` berechnet Verbrauch und Restbestand.
Aussage: Das System soll den Verbrauch eines vertraglich vereinbarten Leistungskontingents (Stunden oder Betrag) fortlaufend erfassen, den Restbestand ausweisen und bei Erreichen konfigurierter Grenzwerte eine Überwachung ermöglichen.
Ergebnis: Vertragsverantwortliche erkennen Kontingentüberschreitungen zeitnah; Abrechnung von Mehrverbrauch ("Überbuchung") ist möglich.
Belege:
- [PRIMÄR] docs/reference/receipts/contracts-backend.md (Abschnitt "Contingent Management") - Begründung: Listet die konkreten Entitätsfelder für Kontingentverbrauch und -grenzen.
- [SEKUNDÄR] ReceiptContractBL.UpdateTakeRestAndOverBooking() (referenziert in obiger Doku) - Begründung: Konkrete Methode zur Behandlung von Restbeträgen und Überbuchung.
Prüfidee: Vertrag mit Stundenkontingent anlegen, Verbrauch über das Kontingent hinaus buchen, Monitoring-Warnung/Restbestand prüfen.
Tracelinks: SyRS-008
Konsolidierung: nein
Status: belegt
```
## C. C-Sign — Elektronische Web-Angebotsannahme & Signatur
```
ID: StRS-008
Titel: Digitale Kundenannahme von Web-Angeboten mit interner Freigabe
Ebene: StRS
Typ: funktional
Akteur: Kunde (ohne Login), Vertriebsmitarbeiter (Freigabe)
Vorbedingung: Ein Angebot wurde für die Kundenannahme über einen Web-Link vorbereitet.
Fakt: `WebReceiptState`-Enum umfasst u. a. `SendToCustomer`, `WebOfferSign`, `AcceptFullWebReceipt`, `AcceptWebReceiptWithChangeRequests`, `Rejected`; `SharedDocumentAcceptancePage.razor` verlangt laut UI-Text eine interne Mitarbeiter-Prüfung ("Bitte Prüfen Sie dieses Dokument, bevor es an den Kunden geht"), bevor das Dokument dem Kunden zur Unterschrift zugestellt wird.
Aussage: Das System soll Kunden die webbasierte Annahme, Änderungsanforderung oder Ablehnung eines Angebots ermöglichen, wobei dem Versand an den Kunden optional eine interne Freigabeprüfung durch einen Mitarbeiter vorgeschaltet ist.
Ergebnis: Der Angebotsstatus spiegelt lückenlos den Weg von "an Kunden gesendet" über ggf. "zur Unterschrift" bis "angenommen/abgelehnt/mit Änderungswunsch" wider.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/WebReceipt/WebReceiptState.cs:6-26 - Begründung: Definiert die vollständige, im Code durchgesetzte Zustandsmenge des Web-Angebotsprozesses.
- [PRIMÄR] src/nexus/CentronNexus/Office/SharedDocumentAcceptancePage.razor - Begründung: UI-Text und `AcceptSharedDocument()`/`DeclineSharedDocument()` belegen die interne Freigabestufe vor Kundenversand.
- [SEKUNDÄR] src/nexus/CentronNexus/WebOffer/WebReceiptOverview.razor - Begründung: Kundenseitige Annahme-/Ablehnungs-/Kommentarfunktion (`RejectWebReceipt`, `ChangeWebReceiptState`, `LeaveComment`).
Prüfidee: Angebot über den Web-Kanal versenden, interne Freigabe erteilen, Kundenannahme simulieren, resultierenden Auftrag und Statuskette prüfen.
Tracelinks: SyRS-010, SyRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-009
Titel: Rechtssichere elektronische Signatur von Kundendokumenten
Ebene: StRS
Typ: Sicherheit
Akteur: Kunde, System
Vorbedingung: Ein Angebot erfordert laut Konfiguration eine Signatur (kein `AllowAcceptReceiptWithoutSignature`).
Fakt: `PdfSigningBL.SignPdfDocument` signiert das PDF serverseitig mit einem hochgeladenen PKCS12-Zertifikat via DevExpress `PdfDocumentSigner`/`Pkcs7Signer`, optional mit Zeitstempel eines TSA-Servers.
Aussage: Das System soll kundenseitig zu unterzeichnende Dokumente mit einer zertifikatsbasierten elektronischen Signatur (inkl. optionalem Zeitstempel) versehen können.
Ergebnis: Das signierte PDF-Dokument ist kryptographisch nachweisbar unverändert und mit Signaturzeitpunkt versehen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Security/PdfSigningBL.cs:126-165 - Begründung: Konkrete Implementierung der PDF-Signatur inkl. Zertifikats- und TSA-Handling.
Prüfidee: Dokument mit gültigem Zertifikat signieren und die Signatur mit einem PDF-Prüfwerkzeug verifizieren.
Tracelinks: SyRS-011
Konsolidierung: nein
Status: belegt; [HYPOTHESE] unklar, ob zusätzlich eine handschriftliche Kundenunterschrift (Bitmap) erfasst wird — nicht im untersuchten Code gefunden (siehe Hypothesen.md H-01).
```
## D. Kunden/CRM, Kreditlimit, Sonderpreise
```
ID: StRS-010
Titel: Schutz vor Umsatzausfall durch Kreditlimitkontrolle
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter, Buchhaltung
Vorbedingung: Für einen Kunden ist ein Kreditlimit (`CreditLimit`) hinterlegt; ein neuer, offener Auftrag soll gespeichert werden.
Fakt: `ReceiptBL.CheckIfCustomerLimitIsReached` summiert den bereits genutzten Kreditrahmen aus allen limitrelevanten, offenen Belegen und vergleicht ihn mit `Customer.CreditLimit`; bei Überschreitung wird `ShowCustomerLimitExceededDialog` gesetzt und der Benutzer muss aktiv bestätigen ("Möchten Sie den Speichervorgang fortsetzen?").
Aussage: Das System soll beim Speichern eines Auftrags prüfen, ob das vereinbarte Kreditlimit des Kunden durch alle offenen Belege überschritten würde, und den Benutzer in diesem Fall aktiv zur Bestätigung auffordern, bevor gespeichert wird.
Ergebnis: Eine Kreditlimitüberschreitung wird nicht stillschweigend zugelassen, kann aber vom berechtigten Benutzer bewusst übersteuert werden (weicher, kein harter Block).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:8636 (CheckIfCustomerLimitIsReached) - Begründung: Enthält die vollständige Berechnungs- und Dialoglogik inkl. deutschsprachiger Nutzermeldung.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:356-380 (TakesPlaceInLimitCalculation, GetUsedLimitAmount) - Begründung: Legt fest, dass nur `Active`-Aufträge in die Kreditlimitberechnung einfließen.
Prüfidee: Kunde mit Kreditlimit 1.000 € anlegen, offene Aufträge über 1.000 € erfassen, weiteren Auftrag anlegen und Bestätigungsdialog verifizieren.
Tracelinks: SyRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-011
Titel: Kundenindividuelle Sonderpreise als Grundlage des Web-Einkaufs
Ebene: StRS
Typ: funktional
Akteur: Vertriebsinnendienst, Kunde (Web-Account)
Vorbedingung: Für einen Kunden sind Sonderpreise ("Sonderpreise") gepflegt.
Fakt: `Customer.SpecialPrices` (Collection von `CustomerSpecialPrice`) wird gemäß README als Grundlage für die im WebCart sichtbaren Artikel verwendet; `CustomersController` stellt eigene Endpunkte `special-price-articles` bereit.
Aussage: Das System soll es ermöglichen, kundenindividuelle Sonderpreise zu pflegen, und soll diese Sonderpreise als Grundlage dafür verwenden, welche Artikel ein Kunde über den Web-Selbstbedienungskanal (WebCart) sehen und bestellen kann.
Ergebnis: Kunden im WebCart sehen ausschließlich für sie freigegebene/bepreiste Artikel; die Pflege erfolgt zentral im ERP.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:28,266 (SpecialPrices) - Begründung: Entity-seitige Verknüpfung Kunde↔Sonderpreisliste.
- [PRIMÄR] src/webservice/Centron.Controllers/Controllers/v1/Customers/CustomersController.cs (GET special-price-articles, GET {customerId}/special-price-articles) - Begründung: Dedizierte API-Endpunkte, die dieses Konzept operationalisieren.
- [KONTEXT] README.md (Abschnitt "WebCart") - Begründung: Beschreibt explizit den fachlichen Zusammenhang zwischen Sonderpreisen und WebCart-Sichtbarkeit.
Prüfidee: Kunde mit Sonderpreisen für Artikel X anlegen, per Web-Account im WebCart einloggen, Sichtbarkeit von Artikel X prüfen.
Tracelinks: SyRS-013, SyRS-014
Konsolidierung: Kandidat: `ProductMatrix`-Mechanismus (kundenindividuelle Katalogkategorien/Produkte) deckt fachlich ähnliches Ziel ab (Steuerung der für einen Kunden sichtbaren Artikel) — Verhältnis zu Sonderpreisen ungeklärt, siehe Hypothesen.md.
Status: belegt
```
```
ID: StRS-012
Titel: Einheitliche Geschäftspartner-Stammdaten für Kunden und Lieferanten
Ebene: StRS
Typ: Daten
Akteur: Vertriebsinnendienst, Einkäufer
Vorbedingung: Eine Adresse/Kontaktperson soll sowohl im Kunden- als auch im Lieferantenkontext nutzbar sein.
Fakt: `Address` besitzt sowohl `CustomerI3D` als auch `SupplierI3D` als nullable Fremdschlüssel; ein expliziter "BusinessPartner"-Entitätstyp existiert nicht, Kunde (`Customer`) und Lieferant (`Supplier`) sind getrennte Klassen, teilen sich aber dasselbe Adress-/Kontaktmodell.
Aussage: Das System soll Adress- und Kontaktinformationen so verwalten, dass dieselbe physische Struktur sowohl für Kunden als auch für Lieferanten verwendbar ist.
Ergebnis: Adress-/Kontaktdaten müssen nicht separat für Kunden- und Lieferantensicht gepflegt werden.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Address.cs:13-14 - Begründung: Zeigt die duale FK-Struktur (`CustomerI3D`, `SupplierI3D`) auf derselben Tabelle.
Prüfidee: Adressobjekt für einen Lieferanten anlegen und prüfen, dass dieselbe Tabellenstruktur wie bei Kundenadressen verwendet wird.
Tracelinks: SwRS (siehe SwRS-Abschnitt Datenmodell)
Konsolidierung: Kandidat: Es existiert daneben ein neuerer Begriff "Account" (`Centron.BL/Accounts/*`) als mögliche Nachfolgeabstraktion zu `Customer` — Verhältnis ungeklärt, [HYPOTHESE] siehe Hypothesen.md H-02.
Status: belegt
```
## E. Helpdesk / Ticket
```
ID: StRS-013
Titel: Automatische Serviceticket-Erstellung aus Aufträgen mit Vorlagen
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter, Servicetechniker
Vorbedingung: Ein Auftrag wird abgeschlossen bzw. es sollen für Auftragspositionen automatisiert Helpdesk-Tickets erzeugt werden.
Fakt: Feature "Automatic Helpdesk Creation Templates": Nutzer können mehrere benannte Vorlagen (`HelpdeskCreationTemplate`) für die automatische Ticketerstellung pflegen, eine davon als Standard markieren; Vorlage bestimmt u. a. Kategorie, Einzel-/Sammelticket-Modus, automatisches Öffnen.
Aussage: Das System soll es ermöglichen, aus Auftragspositionen automatisiert Helpdesk-Tickets zu erzeugen, wobei Nutzer wiederverwendbare, benannte Konfigurationsvorlagen (inkl. einer Standardvorlage) für diese Ticketerstellung verwalten können.
Ergebnis: Wiederkehrende Ticketerstellungs-Konfigurationen müssen nicht jedes Mal neu eingegeben werden; eine Standardvorlage wird automatisch vorgeschlagen.
Belege:
- [PRIMÄR] docs/features/automatic-helpdesk-creation-templates.md (Abschnitt "Business Rules", `HelpdeskCreationTemplateBL.SetStandardTemplate`) - Begründung: Dokumentiert die durchgesetzte Regel "nur eine Standardvorlage gleichzeitig" und "Standardvorlage kann nicht gelöscht werden".
- [PRIMÄR] ScriptMethod11751.cs (Tabellenerstellung `HelpdeskCreationTemplate`, referenziert in obiger Doku) - Begründung: Belegt das persistente Datenmodell inkl. Soft-Delete- und Audit-Spalten gemäß Datenbankkonvention.
Prüfidee: Vorlage anlegen, als Standard markieren, neues Ticket-Erstellungsformular öffnen und automatisches Vorbefüllen mit Standardvorlage prüfen; Löschversuch der Standardvorlage muss abgelehnt werden.
Tracelinks: SyRS-015
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-014
Titel: Kontrollierter Ticketabschluss
Ebene: StRS
Typ: funktional
Akteur: Servicetechniker/Helpdesk-Bearbeiter
Vorbedingung: Ein Helpdesk-Ticket soll geschlossen werden.
Fakt: `HelpdeskCloseBL.CloseHelpdesk` ermittelt den konfigurierten "geschlossen"-Status, prüft `CanCloseHelpdesk()` (aktuell nur ein allgemeiner Guard-Check; ein Kommentar `//Todo: if rma exists check if finished` zeigt eine noch nicht vollständig implementierte fachliche Prüfung), löscht offene To-Dos und protokolliert den Abschluss inkl. Benachrichtigungen.
Aussage: Das System soll das Schließen eines Helpdesk-Tickets nur nach Durchlaufen definierter Abschlussprüfungen zulassen und dabei offene Folgeaufgaben bereinigen sowie den Vorgang protokollieren.
Ergebnis: Ein Ticket kann nicht ohne Nachvollziehbarkeit geschlossen werden; Historie/Benachrichtigungen/CRM-Aktivität werden ausgelöst.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs:120-166 - Begründung: Enthält den vollständigen Abschluss-Ablauf inkl. des unvollständigen `CanCloseHelpdesk()`-Guards.
Prüfidee: Ticket mit offenem RMA-Vorgang schließen und prüfen, ob (aktuell) keine Blockade erfolgt — Regressionsbasis für spätere Vervollständigung der Prüfung.
Tracelinks: SyRS-015
Konsolidierung: nein
Status: belegt; Workaround (Abschlussprüfung für RMA-Bezug laut Code-Kommentar unvollständig — priorisiert für Validierung vormerken)
```
## F. Rechte & Zugriffssteuerung
```
ID: StRS-015
Titel: Feingranulare, rollenbasierte Funktionsfreischaltung
Ebene: StRS
Typ: Sicherheit
Akteur: Systemadministrator, alle internen Benutzerrollen
Vorbedingung: Ein Benutzer meldet sich an und nutzt eine geschützte Funktion.
Fakt: `UserRightsConst.cs` definiert 750 einzelne, hierarchisch organisierte Rechte-Konstanten (z. B. `Sales.Customer.Helpdesk.SHOW_HELPDESK`); Rechte werden ausschließlich über Gruppenmitgliedschaft vergeben (`AppUser.Groups` → `AppGroup.Rights`), es existiert keine direkte Nutzer-Recht-Zuordnung.
Aussage: Das System soll den Zugriff auf einzelne Funktionen über feingranulare, hierarchisch organisierte Berechtigungen steuern, die ausschließlich über die Zuordnung von Benutzern zu Berechtigungsgruppen vergeben werden.
Ergebnis: Jede geschützte Aktion kann individuell freigegeben/gesperrt werden; Rechteverwaltung erfolgt zentral über Gruppen statt Einzelzuweisung.
Belege:
- [PRIMÄR] src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/Administration/Rights/UserRightsConst.cs (750 `public const int`-Deklarationen) - Begründung: Vollständige, im Code durchgesetzte Rechtemenge.
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs:644 (HasUserRight), SQL-Join `Sichtrus`↔`Sichmemb` - Begründung: Zeigt die tatsächliche DB-seitige Durchsetzung über Gruppenmitgliedschaft, keine direkte Nutzer-Recht-Tabelle gefunden.
- [SEKUNDÄR] CentronRights.md, docs/guides/development/add-a-new-right.md, check-userrights.md - Begründung: Entwicklerdokumentation bestätigt und erläutert das Konzept.
Prüfidee: Benutzer aus allen Rechtegruppen entfernen und prüfen, dass sämtliche geschützten Funktionen gesperrt sind; nach Gruppenzuordnung Freischaltung prüfen.
Tracelinks: SyRS-016, SyRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-016
Titel: Einschränkende Rechte für filial-/eigentumsbezogene Datensichtbarkeit
Ebene: StRS
Typ: Sicherheit
Akteur: Systemadministrator, Fachbereichsleiter
Vorbedingung: Ein Benutzer besitzt ein "einschränkendes Recht" (z. B. "nur eigene Filiale").
Fakt: Mehrfach verifiziertes Muster (Helpdesk, Kalender, Mitarbeiterauslastung, Rechteverwaltung selbst): ein zusätzliches Recht schränkt eine bereits gewährte Berechtigung auf einen Teilbereich ein (eigene Datensätze oder eigene Filiale), technisch umgesetzt als Filterbedingung auf `BranchI3D`/Bearbeiter-/Verantwortlicher-Feld.
Aussage: Das System soll es ermöglichen, gewährte Berechtigungen durch zusätzliche "einschränkende Rechte" auf die eigene Filiale oder auf eigene Datensätze zu begrenzen.
Ergebnis: Führungskräfte/Administratoren können steuern, ob ein Benutzer nur eigene bzw. filialeigene Daten sieht, auch wenn das Grundrecht global gewährt ist.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:196 - Begründung: Konkrete Codeprüfung, die den Zugriff auf Tickets anderer Filialen mit Fehlermeldung blockiert.
- [PRIMÄR] src/backend/Centron.BL/Sales/Calendar/ScheduleBL.cs:373-381,692-703 - Begründung: Analoge Implementierung für Kalendereinträge ("nur eigene").
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs:39 (GetAllRightGroups) - Begründung: Selbst die Rechteverwaltung unterliegt diesem Muster (`MANAGE_RIGHTS_ONLY_OWN_BRANCH`).
- [SEKUNDÄR] CentronRights.md - Begründung: Dokumentiert das Konzept "restricting right" explizit für mehrere Fachbereiche.
Prüfidee: Benutzer mit Grundrecht + "nur eigene Filiale" anlegen, Datensätze anderer Filialen anlegen, Sichtbarkeit/Zugriff verifizieren.
Tracelinks: SyRS-017
Konsolidierung: Kandidat: identisches Muster ist in mind. 4 Fachmodulen (Helpdesk, Kalender, Mitarbeiterauslastung, Rechteverwaltung) separat implementiert statt zentral wiederverwendet.
Status: belegt
```
```
ID: StRS-017
Titel: Getrennte Berechtigungsdomäne für externe Web-Kunden
Ebene: StRS
Typ: Sicherheit
Akteur: Kunde (Web-Account)
Vorbedingung: Ein externer Kunde meldet sich über das Web-Portal (Nexus/WebCart) an.
Fakt: Eine eigenständige Konstantenklasse `WebAccountRightsConst.cs` (separate ID-Räume, ca. 50 Konstanten) und eine eigene Prüfmethode `HasWebAccountRight`/`AppUser.HasWebRight` bilden eine von den internen Mitarbeiterrechten (`UserRightsConst`) getrennte Berechtigungsdomäne.
Aussage: Das System soll die Berechtigungen externer Web-Kunden in einer von den internen Mitarbeiterberechtigungen getrennten Domäne verwalten.
Ergebnis: Interne Rechteänderungen wirken sich nicht unbeabsichtigt auf externe Kundenkonten aus und umgekehrt.
Belege:
- [PRIMÄR] src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/Administration/Rights/WebAccountRightsConst.cs - Begründung: Eigenständige Konstantenklasse mit eigenem ID-Raum.
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs:666-670 (HasWebAccountRight) - Begründung: Getrennte DB-Abfrage über Tabelle `WebAccountsRights`.
Prüfidee: Web-Account-Recht vergeben/entziehen und prüfen, dass dies keine Auswirkung auf interne `UserRightsConst`-Prüfungen hat.
Tracelinks: SyRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-018
Titel: Nachvollziehbarkeit von Rechteänderungen
Ebene: StRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Ein Recht wird einer Berechtigungsgruppe hinzugefügt oder entzogen.
Fakt: `AppRightsBL.AddRightToRightGroup`/`RemoveRightFromRightGroup` schreiben bei jeder Änderung einen Protokolleintrag (`WriteAddRightToGroupLog`).
Aussage: Das System soll jede Änderung an der Rechtezuordnung einer Berechtigungsgruppe protokollieren.
Ergebnis: Nachträglich ist nachvollziehbar, wer wann welches Recht welcher Gruppe zugewiesen oder entzogen hat.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs:168-200 (AddRightToRightGroup, WriteAddRightToGroupLog) - Begründung: Direkter Code-Beleg für die Protokollierung.
Prüfidee: Recht einer Gruppe hinzufügen und Vorhandensein eines Protokolleintrags mit Benutzer/Zeitstempel prüfen.
Tracelinks: SyRS-017
Konsolidierung: nein
Status: belegt
```
## G. Authentifizierung & Sitzungsverwaltung
```
ID: StRS-019
Titel: Mehrere gleichwertige Anmeldewege (Passwort, Active Directory, Microsoft Entra ID)
Ebene: StRS
Typ: Sicherheit
Akteur: alle Benutzerrollen, Systemadministrator
Vorbedingung: Ein Benutzer meldet sich am System an.
Fakt: `AuthenticatorFactory` wählt je nach konfigurierter `SystemAuthenticationMethod` zwischen `BasicAuthenticator` (Passwort), `ActiveDirectoryAuthenticator` (Windows/AD) und `OpenIdConnectAuthenticator` (Microsoft Entra ID/OIDC) sowie einer `FallbackAuthenticator`-Verkettung.
Aussage: Das System soll wahlweise Passwort-basierte Anmeldung, Active-Directory-Anmeldung oder Anmeldung über Microsoft Entra ID (OpenID Connect) unterstützen, konfigurierbar je Installation.
Ergebnis: Unternehmen können den für sie passenden Identitätsanbieter nutzen, ohne den Anwendungscode anzupassen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs - Begründung: Zentrale Weiche zwischen den drei Authentifizierungsmethoden.
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md - Begründung: Vollständig dokumentierter OIDC-Ablauf inkl. konkreter Endpunkte und Settings-IDs (JwtAuthority=10351, JwtAudience=10352, SystemAuthenticationMethod=10360).
Prüfidee: Anmeldung über jede der drei Methoden in einer Testumgebung durchführen und erfolgreichen Login sowie Ticket-Erstellung prüfen.
Tracelinks: SyRS-018, SyRS-019
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-020
Titel: Zeitlich begrenzte Sitzungen (Tickets)
Ebene: StRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Ein Benutzer hat sich erfolgreich angemeldet.
Fakt: `TicketBL` vergibt serverseitige Sitzungs-"Tickets" mit festen Ablaufzeiten: 30 Minuten Standard (`TicketExpireInMinutes`), 5 Minuten für Monitoring-Connector, 1440 Minuten (24 h) für eine gesonderte Kategorie.
Aussage: Das System soll Anmeldesitzungen zeitlich begrenzen und nach Ablauf eine erneute Authentifizierung verlangen.
Ergebnis: Ein kompromittiertes oder vergessenes Sitzungstoken verliert nach spätestens 24 Stunden (Regelfall 30 Minuten) seine Gültigkeit.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TicketBL.cs:26-28,61 (CreateNewTicket, TicketExpireInMinutes=30, TicketMonitoringConnectorExpireInMinutes=5, TicketExpire24HoursInMinutes=1440) - Begründung: Konkrete, im Code fest codierte Ablaufwerte.
- [SEKUNDÄR] src/nexus/CentronNexus/Shared/Auth/CentronAuthenticationStateProvider.cs:15-66 - Begründung: Zeigt clientseitige Revalidierung (alle 1-2 Minuten) gegen dieselbe Ticket-Gültigkeit im Web-Portal.
Prüfidee: Ticket erzeugen, 31 Minuten warten (bzw. Ablaufzeit simulieren), nachfolgenden API-Aufruf auf Ablehnung prüfen.
Tracelinks: SyRS-020
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-021
Titel: Optionale Zwei-Faktor-Authentifizierung
Ebene: StRS
Typ: Sicherheit
Akteur: Benutzer mit aktivierter 2FA
Vorbedingung: `AppUser.UseTwoFactorAuthentication = true`.
Fakt: `TwoFactorAuthenticator`-Klasse implementiert TOTP (6-stelliger PIN, 30-Sekunden-Schritt, ±4 Minuten Zeittoleranz) nach `otpauth://totp/...`-Standard; Prüfung erfolgt inline innerhalb von `BasicAuthenticator.AuthenticateInternal`.
Aussage: Das System soll optional eine zeitbasierte Zwei-Faktor-Authentifizierung (TOTP) je Benutzer erzwingen können.
Ergebnis: Benutzer mit aktivierter 2FA müssen zusätzlich zum Passwort einen gültigen Einmalcode eingeben.
Belege:
- [PRIMÄR] src/shared/Centron.Core/GoogleAuthenticator/TwoFactorAuthenticator.cs:18-27 - Begründung: Konkrete TOTP-Implementierung inkl. Provisionierungs-URL.
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs:62 (_twoFactorAuthBL.ValidateTwoFactor) - Begründung: Zeigt die Einbindung in den Login-Ablauf.
Prüfidee: 2FA für einen Benutzer aktivieren, Login ohne bzw. mit korrektem/falschem TOTP-Code testen.
Tracelinks: SyRS-018
Konsolidierung: nein
Status: belegt
```
## H. Lizenzierung
```
ID: StRS-022
Titel: Modulare, GUID-basierte Produktlizenzierung
Ebene: StRS
Typ: funktional
Akteur: Systemadministrator, NEXOWARE-Vertrieb
Vorbedingung: Ein Kunde soll Zugriff auf eine bestimmte Anwendung oder ein Einzelfeature erhalten.
Fakt: Jede lizenzierbare Anwendung ("Application", darf sich am Webservice anmelden) und jedes Einzelfeature ("Only License") wird über eine eindeutige GUID identifiziert (`LicenseGuids.cs`); jede Lizenz kann zusätzlich eine Anzahl (`count`), ein Ablaufdatum und eine Versionsgrenze besitzen.
Aussage: Das System soll den Zugriff auf Anwendungen und Einzelfeatures über eine GUID-basierte Lizenzverwaltung mit optionaler Mengen-, Zeit- und Versionsbegrenzung steuern.
Ergebnis: Funktionen/Anwendungen ohne gültige Lizenz sind für den Kunden nicht nutzbar bzw. nicht sichtbar; Mengenlizenzen (z. B. Anzahl Importe) werden durchgesetzt.
Belege:
- [PRIMÄR] docs/reference/security/licensing-system.md - Begründung: Vollständige Beschreibung des Lizenzmodells inkl. Codebeispielen (`LicenseManager.Instance.HasLicense`, `GetLicenseCount`).
- [PRIMÄR] src/webservice/Centron.Controllers/Authorization/CentronHostedAuthorization.cs (CentronHostedRequirement, LicenseGuids.CentronInternal) - Begründung: Konkrete Durchsetzung einer Lizenzprüfung als ASP.NET-Core-Autorisierungs-Requirement.
Prüfidee: Feature ohne zugehörige Lizenz aufrufen und Sperrung/Ausblendung prüfen; Mengenlizenz mit `count=3` testen (4. Nutzung muss abgelehnt werden).
Tracelinks: SyRS-021
Konsolidierung: nein
Status: belegt
```
## I. Rechnungsstellung, Nummerierung, Festschreibung, Storno, Zahlungen
```
ID: StRS-023
Titel: Eindeutige, lückenlose Belegnummernvergabe je Mandant/Filiale
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, System
Vorbedingung: Ein neuer Beleg (z. B. Rechnung) wird angelegt und benötigt eine Belegnummer.
Fakt: `NumberGroupBL.GetNextNumber`/`FindNextNumber` inkrementiert eine je Mandant/Filiale/Nummernkreis geführte laufende Nummer, prüft dabei per Datenbankabfrage auf bereits existierende Nummern und verwendet eine bedingte `UPDATE ... WHERE Current = <alter Wert>`-Schleife zur Vermeidung von Kollisionen bei gleichzeitigem Zugriff.
Aussage: Das System soll Belegnummern (u. a. Rechnungsnummern) je Mandant und Filiale eindeutig und kollisionsfrei auch bei gleichzeitigem Zugriff mehrerer Benutzer vergeben.
Ergebnis: Keine doppelt vergebenen Belegnummern, auch nicht bei parallelen Speichervorgängen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs (GetNextNumber, FindNextNumber) - Begründung: Enthält die konkrete, kollisionssichere Vergabelogik inkl. optimistischer Update-Schleife.
- [PRIMÄR] src/backend/Centron.Entities/Entities/Administration/Company/NumberGroup.cs (RangeFrom, RangeTo, Current, Interval, MandatorI3D, BranchI3D) - Begründung: Datenmodell für Nummernkreise je Mandant/Filiale.
Prüfidee: Zwei gleichzeitige Rechnungserstellungen (parallelisiert) simulieren und prüfen, dass keine doppelte Nummer vergeben wird.
Tracelinks: SyRS-022
Konsolidierung: nein
Status: belegt; [HYPOTHESE] ob dies aus einer expliziten GoBD-Anforderung (Deutschland) abgeleitet ist, ist im Code nicht dokumentiert — siehe Hypothesen.md H-03.
```
```
ID: StRS-024
Titel: Unveränderlichkeit festgeschriebener Rechnungen
Ebene: StRS
Typ: Sicherheit
Akteur: Buchhaltung
Vorbedingung: Eine Rechnung wurde als "festgeschrieben" markiert (`IsFixed = true`).
Fakt: `ReceiptInvoiceBL.CheckIfInvoiceIsFixed` blockiert Änderungen an einer festgeschriebenen Rechnung mit der Meldung "Die Rechnung ist festgeschrieben. Änderungen nicht möglich."; `FixInvoice` setzt das Flag per direktem SQL-Update und protokolliert dies.
Aussage: Das System soll verhindern, dass eine als festgeschrieben markierte Rechnung inhaltlich verändert wird.
Ergebnis: Nach Festschreibung sind nur noch kontrollierte Folgeprozesse (z. B. Stornierung mit Neuversionierung) möglich, keine direkte Bearbeitung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:86,273 (FixInvoice, CheckIfInvoiceIsFixed) - Begründung: Konkrete Guard-Implementierung inkl. Nutzermeldung.
Prüfidee: Rechnung festschreiben, Änderungsversuch durchführen und Ablehnung mit definierter Fehlermeldung prüfen.
Tracelinks: SyRS-023
Konsolidierung: nein
Status: belegt; [HYPOTHESE] gesetzlicher Hintergrund (GoBD) nicht im Code dokumentiert, siehe Hypothesen.md H-03.
```
```
ID: StRS-025
Titel: Kontrollierte Rechnungsstornierung mit Mehrfachprüfung
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Eine Rechnung soll storniert werden.
Fakt: `ReceiptInvoiceBL.CancelInvoice` erfordert das Recht `RIGHT_RECHNUNGSTORNIEREN`, verweigert die Stornierung bereits stornierter, bereits an die Buchhaltung exportierter (`IsReceiptExported`), bereits weitergeleiteter oder bei Vertragsrechnungen nicht-letzter Rechnungen; die eigentliche Stornierung erzeugt eine neue Version statt In-place-Änderung.
Aussage: Das System soll die Stornierung einer Rechnung nur nach Prüfung mehrerer Sperrbedingungen (Berechtigung, bereits exportiert, bereits weitergeleitet, Vertragsreihenfolge) zulassen und dabei eine neue Beleg­version erzeugen.
Ergebnis: Bereits an die Finanzbuchhaltung übergebene oder anderweitig referenzierte Rechnungen können nicht unkontrolliert storniert werden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:143 (CancelInvoice) - Begründung: Enthält alle genannten Sperrbedingungen als expliziten Code-Ablauf.
Prüfidee: Stornierung einer bereits exportierten Rechnung versuchen (muss abgelehnt werden); Stornierung einer offenen, nicht exportierten Rechnung durchführen (muss gelingen und neue Version erzeugen).
Tracelinks: SyRS-023
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-026
Titel: Nachvollziehbare Zahlungsbuchung mit Stornofunktion
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Ein Zahlungseingang/-ausgang soll erfasst oder storniert werden.
Fakt: `PaymentsBL.DeleteIncomingPayment` erfordert das Recht `Controlling.Finances.INCOMING_PAYMENT_TRANSACTIONS`; bei Löschung wird die Zahlung durch einen umgekehrt vorzeichenbehafteten Aufruf von `ReceiptBL.UpdateReceiptIsPaid` (inkl. Währungsumrechnung) korrekt zurückgebucht statt nur den Datensatz zu entfernen.
Aussage: Das System soll das Löschen einer erfassten Zahlung nur berechtigten Benutzern erlauben und dabei den Bezahlt-Status des zugehörigen Belegs korrekt (inkl. Währungsumrechnung) zurücksetzen.
Ergebnis: Der Bezahlt-Status eines Belegs bleibt auch nach Korrekturen konsistent mit den tatsächlich erfassten Zahlungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Finances/Payments/PaymentsBL.cs:38 (DeleteIncomingPayment) - Begründung: Konkrete Implementierung inkl. Rechteprüfung und Rückbuchung.
Prüfidee: Zahlung erfassen (Beleg wird "bezahlt"), Zahlung löschen und Rückkehr des Belegs in den unbezahlten Zustand inkl. korrekten Betrags prüfen.
Tracelinks: SyRS-023
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-027
Titel: Kontrollierte Bankverbindungsverwaltung mit Verwendungsprüfung
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Eine Bankverbindung soll gelöscht werden.
Fakt: `BankAccountBL.DeleteBankAccount` prüft, ob die Bankverbindung von einem Beleg mit SEPA-Mandat (`IReceiptWithMandat`) referenziert wird, und verweigert in diesem Fall die Löschung mit Auflistung der blockierenden Belege.
Aussage: Das System soll die Löschung einer Bankverbindung verhindern, solange diese von mindestens einem Beleg mit SEPA-Mandatsbezug verwendet wird, und dem Benutzer die blockierenden Belege anzeigen.
Ergebnis: Keine verwaisten Mandatsreferenzen durch gelöschte Bankverbindungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Accounting/BankAccountBL.cs:119 (DeleteBankAccount) - Begründung: Konkrete Implementierung inkl. Belegliste in der Fehlermeldung.
Prüfidee: Bankverbindung löschen, die von einem aktiven Vertrag mit SEPA-Mandat referenziert wird; Ablehnung mit Belegliste prüfen.
Tracelinks: SyRS-023
Konsolidierung: nein
Status: belegt
```
## J. E-Invoicing & Lieferanten-EDI
```
ID: StRS-028
Titel: Normkonforme elektronische Rechnungsstellung (ZUGFeRD, ebInterface)
Ebene: StRS
Typ: Schnittstelle
Akteur: Buchhaltung, externer Kunde/Lieferant
Vorbedingung: Eine Rechnung soll als strukturiertes E-Invoice ausgegeben werden.
Fakt: `InvoiceZugferdBL`/`ZUGFeRD_BL` erzeugen ZUGFeRD-konforme Hybrid-PDF/XML-Rechnungen (deutscher/europäischer Standard); `EbInterfaceLogic` erzeugt ebInterface-Dateien (österreichischer Standard); die Aktivierung ist über die Einstellung `IsZugferdInvoiceActive` steuerbar.
Aussage: Das System soll Ausgangsrechnungen wahlweise im ZUGFeRD- und/oder ebInterface-Format als strukturierte elektronische Rechnung erzeugen können.
Ergebnis: Rechnungsempfänger mit entsprechenden Systemen können die Rechnung automatisiert maschinell verarbeiten; gesetzliche E-Rechnungspflichten (z. B. B2G) sind adressierbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs (GenerateZugferdFile, CreateZugferdConformPdfDocument) - Begründung: Konkrete Erzeugungslogik für ZUGFeRD-Dateien.
- [PRIMÄR] src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs (GenerateFile) - Begründung: Konkrete Erzeugungslogik für ebInterface.
- [SEKUNDÄR] docs/guides/development/xrechnung.md, docs/guides/development/settings-management.md (IsZugferdInvoiceActive) - Begründung: Zeigt die Aktivierbarkeit über Einstellungen sowie Bezug zu XRechnung.
Prüfidee: Rechnung mit aktivierter ZUGFeRD-Einstellung erzeugen und die PDF-eingebettete XML mit einem Validator (z. B. KOSIT-Tool) prüfen.
Tracelinks: SyRS-024
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-029
Titel: Automatisierter elektronischer Belegaustausch mit Distributoren (EDI)
Ebene: StRS
Typ: Schnittstelle
Akteur: Einkäufer, externer Lieferant/Distributor
Vorbedingung: Eine Bestellung soll elektronisch an einen angebundenen Distributor übermittelt oder eine Auftragsbestätigung/Lieferung/Rechnung empfangen werden.
Fakt: `EDIDispatcherBL` routet die Belegerzeugung je Distributor (`EDIMultidistributors`: ITScope, EGIS, Concerto, Orderowner) und nutzt standardmäßig openTRANS 2.1; `SupplierEdiBL` verarbeitet eingehende Auftragsbestätigungen/Lieferungen/Rechnungen für ALSO, ALSO CH, Alltron, Herweck, Komsa.
Aussage: Das System soll Bestellungen, Auftragsbestätigungen, Lieferavise und Rechnungen mit angebundenen Distributoren über standardisierte bzw. distributorspezifische EDI-Formate automatisiert austauschen.
Ergebnis: Manuelle Doppelerfassung von Bestell- und Lieferdaten entfällt für angebundene Distributoren.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/EDIDispatcherBL.cs (CreateEDISuggestionOrderAsync, EDIMultidistributors) - Begründung: Zeigt konkrete Distributor-Routing-Logik für den Bestellversand.
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs (2179 Zeilen, Partial-Klassen je Distributor) - Begründung: Zentrale Empfangsverarbeitung für mehrere EDI-Formate.
- [SEKUNDÄR] docs/reference/edi/edi-architecture.md - Begründung: Dokumentiert unterstützte Formate/Dokumenttypen je Lieferant tabellarisch.
Prüfidee: Testbestellung an einen konfigurierten EDI-Distributor senden und Empfang/Verarbeitung einer simulierten Auftragsbestätigung prüfen.
Tracelinks: SyRS-025, SyRS-026
Konsolidierung: nein
Status: belegt
```
## K. Einkauf & Lieferantenmanagement
```
ID: StRS-030
Titel: Bedarfsgesteuerte Bestellvorschläge
Ebene: StRS
Typ: funktional
Akteur: Einkäufer
Vorbedingung: Artikelbestände unterschreiten einen Mindestbestand bzw. es besteht offener Auftragsbedarf.
Fakt: `OrderSuggestionListBL` (1144 Zeilen) berechnet Bestellvorschläge je Artikel/Auftrag/Lager (`GetOrderSuggestionArticle`, `GetOrderSuggestionOrder`, `GetOrderSuggestionWH`), inkl. distributorspezifischer Preisermittlung und Berücksichtigung von Wareneingängen im Zulauf (`RefreshIntake`).
Aussage: Das System soll auf Basis von Mindestbeständen, offenem Auftragsbedarf und bereits im Zulauf befindlicher Ware automatisiert Bestellvorschläge je Artikel und Lager erzeugen.
Ergebnis: Einkäufer erhalten eine priorisierte, datenbasierte Grundlage für Nachbestellungen statt manueller Bestandsprüfung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs - Begründung: Zentrale, umfangreiche Implementierung der Bestellvorschlagslogik.
Prüfidee: Artikel unter Mindestbestand setzen und Erscheinen in der Bestellvorschlagsliste mit korrekter Menge prüfen.
Tracelinks: SyRS-027
Konsolidierung: nein
Status: belegt; [HYPOTHESE] genaue Meldebestands-/Reorder-Formel nicht vollständig nachvollzogen, siehe Hypothesen.md H-04.
```
```
ID: StRS-031
Titel: Partiallieferungsfähige Lieferantenbestellabwicklung
Ebene: StRS
Typ: funktional
Akteur: Einkäufer, Lagermitarbeiter
Vorbedingung: Eine Lieferantenbestellung wird teilweise geliefert.
Fakt: `ReceiptSupplierOrderIntake` verfolgt je Bestellposition die kumulierte Wareneingangsmenge (`InStock`, `Booked`) gegenüber der Bestellmenge; `SupplierOrderSpecificLogic.UpdateIntake` aktualisiert diese bei jedem Wareneingang.
Aussage: Das System soll Teillieferungen zu einer Lieferantenbestellung erfassen und den kumulierten Lieferstatus je Bestellposition nachverfolgen.
Ergebnis: Offener Restbedarf je Bestellposition ist jederzeit ersichtlich, auch bei mehreren Teillieferungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:177-215 (UpdateIntake) - Begründung: Konkrete Implementierung der kumulierten Mengenverfolgung.
Prüfidee: Bestellung mit 100 Stück anlegen, zwei Teillieferungen von je 40 und 60 Stück buchen, kumulierten Status nach jeder Teillieferung prüfen.
Tracelinks: SyRS-028
Konsolidierung: nein
Status: belegt
```
## L. Lager & Bestandsführung
```
ID: StRS-032
Titel: Schutz vor unautorisierten Negativbuchungen im Warenausgang
Ebene: StRS
Typ: funktional
Akteur: Lagermitarbeiter
Vorbedingung: Eine Warenausgangsbuchung (z. B. Lieferschein) würde den Bestand eines Artikels neu ins Negative treiben.
Fakt: `ReceiptArticleBookingBL` erkennt eine Buchung als "negativ" nur, wenn der Bestand dadurch neu negativ wird; ohne das Recht `RIGHT_NEGATIVBUCHUNG` wird die Buchung blockiert und ein Dialog zur Anmeldung eines berechtigten Kollegen angeboten. Diese Prüfung ist für Wareneingänge (Lieferantenbestellung/-lieferschein) deaktiviert, für Warenausgang (Kundenlieferschein) aktiv.
Aussage: Das System soll eine Warenausgangsbuchung, die den Artikelbestand neu ins Negative treibt, nur mit einem gesonderten Recht zulassen; ist dieses Recht nicht vorhanden, soll die Anmeldung eines berechtigten Kollegen zur Freigabe angeboten werden.
Ergebnis: Unautorisierte Negativbestände im Warenausgang werden verhindert, während Wareneingänge nicht unnötig blockiert werden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptArticleBookingBL.cs:340-429 - Begründung: Enthält die vollständige Erkennungs- und Freigabelogik inkl. Kollegen-Anmeldedialog.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/DeliveryLists/DeliveryListSpecificLogic.cs:200-201 vs. SupplierOrderSpecificLogic.cs:222-230 / SupplierDeliveryListSpecificLogic.cs:247-255 - Begründung: Belegt die differenzierte Aktivierung je Belegrichtung (Ausgang aktiv, Eingang deaktiviert).
Prüfidee: Warenausgang ohne Negativbuchungsrecht über den verfügbaren Bestand hinaus buchen; Ablehnung und Kollegen-Anmeldedialog prüfen.
Tracelinks: SyRS-029
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-033
Titel: Vollständige Bestandsänderungsprotokollierung
Ebene: StRS
Typ: funktional
Akteur: Lagermitarbeiter, Buchhaltung (Inventurprüfung)
Vorbedingung: Eine Artikelbestandsänderung wird durchgeführt.
Fakt: `ReceiptArticleBookingBL` ruft nach jeder Bestandsaktualisierung `_articleLogBL.WriteAmountChangeLog` auf; separat protokolliert `StockBL.WriteStockRebookLog` Lagerumbuchungen zwischen zwei Lagerorten mit Pflichtangabe von Quell-/Ziellager und Mitarbeiter.
Aussage: Das System soll jede Artikelbestandsänderung inklusive Lagerumbuchungen mit Quelle, Ziel und ausführendem Mitarbeiter protokollieren.
Ergebnis: Bestandsdifferenzen sind nachträglich auf konkrete Buchungsvorgänge zurückführbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptArticleBookingBL.cs:429 (WriteAmountChangeLog) - Begründung: Direkter Aufruf nach jeder Bestandsänderung.
- [PRIMÄR] src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:84-108 (WriteStockRebookLog) - Begründung: Pflichtfeldprüfung für Umbuchungsprotokoll.
Prüfidee: Bestandsänderung durchführen und Vorhandensein eines zugehörigen Protokolleintrags mit Benutzer/Zeitstempel/Mengenänderung prüfen.
Tracelinks: SyRS-029
Konsolidierung: nein
Status: belegt
```
## M. Externe Preis-/Kataloganbindung
```
ID: StRS-034
Titel: Konsolidierte Mehrquellen-Einkaufspreisübersicht (Preismatrix)
Ebene: StRS
Typ: funktional
Akteur: Einkäufer, Vertriebsmitarbeiter
Vorbedingung: Für einen Artikel sollen aktuelle Einkaufspreise verglichen werden.
Fakt: Die "Preismatrix" zeigt parallel bis zu sieben Preisquellen je Artikel: interne zeitlich befristete Aktionspreise sowie vier externe Distributor-/Marktplatz-APIs (ITscope, COP/NEOS/TradersGuide über eine gemeinsame SOAP-Basisklasse, EGIS) und importierte Artikeldaten.
Aussage: Das System soll für einen Artikel Einkaufspreise aus mehreren internen und externen Quellen (Aktionspreise, Distributor-APIs) gebündelt und tagesaktuell (unter Berücksichtigung von Gültigkeitszeiträumen) darstellen.
Ergebnis: Einkäufer/Vertrieb sehen ohne Systemwechsel den jeweils günstigsten verfügbaren Bezugspreis.
Belege:
- [PRIMÄR] docs/reference/receipts/actionprice-system.md (Abschnitt "Integration with Price Matrix") - Begründung: Listet die sieben parallelen Preisquellen explizit auf.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ArticleSearch/CopApiBaseExternalArticleSearchProvider.cs (Unterklassen für COP, NEOS, TradersGuide) - Begründung: Konkrete, wiederverwendete Anbindung dreier Distributoren über ein gemeinsames SOAP-Protokoll.
- [SEKUNDÄR] src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs, Centron.APIs.EgisDataAccess/EgisApi.cs - Begründung: Weitere externe Preis-/Verfügbarkeitsquellen.
Prüfidee: Artikel mit hinterlegtem Aktionspreis und aktivierten externen Quellen öffnen; alle Quellen müssen parallel mit Anbieterkennzeichnung angezeigt werden.
Tracelinks: SyRS-030
Konsolidierung: nein
Status: belegt
```
## N. Web-Selbstbedienungsportal (Nexus/WebCart) & TradePool
```
ID: StRS-035
Titel: Web-Selbstbedienungsportal für Endkunden (WebCart)
Ebene: StRS
Typ: funktional
Akteur: Kunde (Web-Account)
Vorbedingung: Ein Kunde besitzt einen Web-Account und meldet sich am Nexus-Webportal an.
Fakt: `CentronNexus/WebCart` bietet Shop-, Warenkorb-, Vertrags-, Beleg- und Ticketübersichtsseiten für Endkunden; Sichtbarkeit basiert auf den kundenindividuellen Sonderpreisen (siehe StRS-011).
Aussage: Das System soll Endkunden über ein Web-Portal einen Selbstbedienungs-Bestellkanal mit Einsicht in eigene Verträge, Belege und Tickets bereitstellen.
Ergebnis: Kunden können ohne Einbindung eines Innendienstmitarbeiters bestellen und den eigenen Vorgangsstatus einsehen.
Belege:
- [PRIMÄR] src/nexus/CentronNexus/WebCart/ (WebCartShopPage.razor, WebCartCartPage.razor, ContractsOverview.razor, ReceiptsOverview.razor, WebCartTicketsPage.razor) - Begründung: Vollständige Feature-Seiten-Struktur des Selbstbedienungsportals.
- [KONTEXT] README.md (Abschnitt "WebCart") - Begründung: Fachliche Einordnung als "Feature primarily intended for the customers of our customers".
Prüfidee: Als Web-Account anmelden, Artikel im Shop auswählen, Bestellung auslösen, im Belegverlauf wiederfinden.
Tracelinks: SyRS-013, SyRS-031
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-036
Titel: Multi-Distributor-Ressale-Katalog für c-entron-Kunden (TradePool)
Ebene: StRS
Typ: funktional
Akteur: Kunde (Wiederverkäufer/Händler)
Vorbedingung: Ein c-entron-Kunde ist für den TradePool-Zugang authentifiziert.
Fakt: `TradePoolBL`/`TradePoolXmlLogic` importieren artikel-/preis-/bestandsbezogene XML-Feeds mehrerer Distributoren je Kunde und stellen sie über eine eigene, passwortgeschützte Anmeldung (`TradeCustomerLogin`) durchsuchbar bereit.
Aussage: Das System soll c-entron-Kunden über einen separaten, authentifizierten Zugang einen aggregierten, mehrere Distributoren umfassenden Artikel-, Preis- und Bestandskatalog bereitstellen.
Ergebnis: Kunden (vermutlich Wiederverkäufer) können ohne eigene Distributor-Zugänge über c-entron auf gebündelte Distributor-Kataloge zugreifen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TradePool/Core/TradePoolXmlLogic.cs:118-159 (ImportTradeArticles) - Begründung: Konkrete XML-Importlogik mit Distributor-/Kunden-Struktur.
- [PRIMÄR] src/backend/Centron.BL/TradePool/TradePoolBL.cs:170-183 (TradeCustomerLogin) - Begründung: Eigenständiger, von den übrigen Auth-Mechanismen getrennter Login.
Prüfidee: TradePool-Zugang für einen Testkunden einrichten, Artikelsuche über mehrere importierte Distributoren durchführen.
Tracelinks: SyRS-032
Konsolidierung: nein
Status: belegt; [HYPOTHESE] genauer fachlicher Geschäftszweck (Dropshipping? Preisvergleich für Endkunden?) nicht durch Code-Kommentar bestätigt, siehe Hypothesen.md H-05.
```
## O. Plattformübergreifender Betrieb & DevOps
```
ID: StRS-037
Titel: Plattformunabhängiger Web-Service-Betrieb (Windows und Linux)
Ebene: StRS
Typ: nicht-funktional
Akteur: Systemadministrator (Kunde/Hosting)
Vorbedingung: Der c-entron Web-Service soll auf einer vom Kunden gewählten Serverplattform betrieben werden.
Fakt: Der Web-Service ist sowohl als Windows-Installation (WiX-MSI, Windows-Dienst) als auch als Linux-Variante (Docker-Image auf Alpine, `Centron.Host.Console`, systemd-Unit-Beispiel) betreibbar; dokumentierte Unterschiede bestehen u. a. bei Sub-Web-Services (nur Windows) und Zertifikatskonfiguration.
Aussage: Das System soll den Web-Service sowohl unter Windows als auch unter Linux betreibbar machen, mit dokumentierten, akzeptierten Funktionseinschränkungen auf Linux.
Ergebnis: Kunden können die Serverplattform frei wählen; bekannte Linux-Einschränkungen (z. B. fehlende Sub-Web-Service-Unterstützung, manuelle Zertifikatskonfiguration) sind dokumentiert statt stillschweigend zu scheitern.
Belege:
- [PRIMÄR] docker/c-entron-api/Dockerfile (Alpine-Runtime, .NET 10) - Begründung: Konkretes, produktives Linux-Container-Image.
- [SEKUNDÄR] docs/guides/services/web-service-on-linux.md - Begründung: Dokumentiert Installationsschritte, HTTPS-Konfiguration und explizite Linux-Einschränkungen.
- [PRIMÄR] deployment/ (WixSharpInstaller, CentronSetupProject, WebServiceSetupProject) - Begründung: Belegt parallelen Windows-Installer-Vertriebsweg.
Prüfidee: Web-Service-Container unter Linux gemäß Dokumentation starten und Basisfunktionalität (Login, einfacher API-Aufruf) verifizieren.
Tracelinks: SyRS-033, SyRS-034
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-038
Titel: Automatisierte, nachvollziehbare Build- und Ticket-Verknüpfung
Ebene: StRS
Typ: nicht-funktional
Akteur: NEXOWARE-Entwickler, Qualitätssicherung
Vorbedingung: Ein Pull Request mit Ticketbezug wird gemergt.
Fakt: Ein Azure-DevOps-Webhook (`DevOpsCentronTicketBridge`) durchsucht Titel/Beschreibung gemergter Pull Requests nach Ticketnummern (mehrere unterstützte Schreibweisen), trägt die resultierende Versionsnummer automatisch in das referenzierte c-entron-Ticket ein und leitet es automatisch an die Qualitätssicherung weiter (außer bei `[skip-forwarding]`-Markierung).
Aussage: Das System soll nach einem erfolgreichen Build automatisiert erkennen, welche Tickets durch den zugehörigen Pull Request adressiert wurden, die Build-Versionsnummer in diese Tickets eintragen und sie zur Qualitätssicherung weiterleiten.
Ergebnis: Jede ausgelieferte Änderung ist ohne manuellen Zusatzaufwand einer konkreten Versionsnummer und einem QS-Prozessschritt zugeordnet.
Belege:
- [PRIMÄR] docs/operations/build-server-and-automated-builds.md (Abschnitt "c-entron Tickets") - Begründung: Vollständige Beschreibung des Webhook-Mechanismus inkl. unterstützter Ticket-Referenzformate und Opt-out-Tag.
Prüfidee: Pull Request mit "Ticket 12345" im Titel mergen und automatischen Eintrag der Versionsnummer im Ticketsystem prüfen.
Tracelinks: SyRS-035
Konsolidierung: nein
Status: belegt
```
## P. Wartbarkeit, Nachvollziehbarkeit, Mehrsprachigkeit (architektonische Querschnittsziele)
```
ID: StRS-039
Titel: Austauschbarkeit von Datenzugriff (Direktverbindung vs. Web-Service)
Ebene: StRS
Typ: nicht-funktional
Akteur: NEXOWARE-Entwickler, Systemadministrator
Vorbedingung: Ein Kunde betreibt den WPF-Client entweder mit direkter SQL-Server-Verbindung oder über den Web-Service.
Fakt: Jedes fachliche Modul MUSS laut Entwicklerdokumentation sowohl eine direkte Datenbank-Implementierung (`BL*Logic`) als auch eine Web-Service-Implementierung (`WS*Logic`) hinter einem gemeinsamen `ILogic`-Interface bereitstellen; `ClassContainer` wählt zur Laufzeit die passende Implementierung.
Aussage: Das System soll es ermöglichen, denselben WPF-Client wahlweise mit direkter Datenbankverbindung oder über den zentralen Web-Service zu betreiben, ohne die fachliche Modulimplementierung zu duplizieren.
Ergebnis: Kunden können je nach Infrastruktur (Terminalserver mit Direktzugriff vs. verteilte/Cloud-Installation) zwischen beiden Betriebsarten wählen.
Belege:
- [PRIMÄR] docs/getting-started/general-structure.md (Abschnitt "Dual Implementation Architecture") - Begründung: Beschreibt die verpflichtende Dual-Implementierung inkl. Codebeispielen für `ILogic`/`BLLogic`/`WSLogic` und `ClassContainer`.
Prüfidee: Denselben Anwendungsfall (z. B. Kundenanlage) einmal über Direktverbindung und einmal über Web-Service ausführen; identisches fachliches Ergebnis prüfen.
Tracelinks: SyRS-041
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-040
Titel: Zweisprachige Benutzeroberfläche (Deutsch/Englisch)
Ebene: StRS
Typ: nicht-funktional
Akteur: alle Benutzerrollen (international)
Vorbedingung: Ein Benutzer stellt seine Anzeigesprache ein.
Fakt: Alle UI-Texte liegen als Ressourcendateien in Deutsch (Standard, `LocalizedStrings.resx`) und Englisch (`LocalizedStrings.en.resx`) vor; Auswahl erfolgt über `CultureInfo.CurrentUICulture`; Web-Service-Antworten unterstützen den `Accept-Language`-Header.
Aussage: Das System soll die Benutzeroberfläche und Systemmeldungen wahlweise in Deutsch (Standard) oder Englisch anzeigen.
Ergebnis: Nicht-deutschsprachige Mitarbeiter/Kunden können das System in englischer Sprache nutzen.
Belege:
- [PRIMÄR] docs/guides/ui/localization.md - Begründung: Vollständige Dokumentation der Ressourcendatei-Struktur, Sprachauswahl und Konventionen.
- [KONTEXT] docs/getting-started/general-structure.md (Abschnitt "German-First Language Policy") - Begründung: Bestätigt Deutsch als verbindlichen Standard für neue UI-Texte.
Prüfidee: Anzeigesprache auf Englisch umstellen und Vorhandensein englischer Übersetzung für eine Stichprobe von UI-Elementen prüfen.
Tracelinks: SyRS-042
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-041
Titel: Automatisierte, wiederkehrende Datenqualitätssicherung
Ebene: StRS
Typ: nicht-funktional
Akteur: System, Systemadministrator
Vorbedingung: Der Web-Service läuft im Dauerbetrieb.
Fakt: Ein `DataQualityService` (ASP.NET-Core-`BackgroundService`) führt stündlich mehrere fest definierte Bereinigungs-/Reparaturaufgaben aus (u. a. Ticketmuster-Kundenzuordnungen, verwaiste Konto-Referenzen in To-Dos, Bereinigung sekundärer Lagerartikel), jede Aufgabe fehlertolerant und unabhängig von den übrigen.
Aussage: Das System soll im laufenden Betrieb automatisiert und regelmäßig Dateninkonsistenzen erkennen und beheben, ohne dass eine einzelne fehlschlagende Aufgabe den Gesamtdienst beeinträchtigt.
Ergebnis: Datenqualitätsprobleme (fehlende Referenzen, veraltete Zuordnungen) werden ohne manuellen Eingriff kontinuierlich reduziert.
Belege:
- [PRIMÄR] docs/Background Service/DataQualityService.md - Begründung: Vollständige Dokumentation der Aufgabenliste, Fehlerbehandlung und Ausführungsintervalle.
Prüfidee: Bekannte Dateninkonsistenz (z. B. fehlende AccountI3D in einem Todo) erzeugen und nach einem Ausführungszyklus die automatische Korrektur prüfen.
Tracelinks: SyRS-036
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-042
Titel: Sichere, versionierte Programmierschnittstelle für Clients und Drittanwendungen
Ebene: StRS
Typ: Schnittstelle
Akteur: interner Client (WPF/Nexus/Outlook-Add-In), Drittanwendung, NEXOWARE-Entwickler
Vorbedingung: Ein Client oder eine Drittanwendung ruft eine Funktion über die REST-API auf.
Fakt: Die moderne REST-API (`Centron.Controllers`) ist konsequent nach Version organisiert (`v1/...`), setzt Authentifizierung/Autorisierung über wiederverwendbare Attribute (`AuthorizeUserRight`, `AuthorizeCentronHosted`) durch und trennt 15 fachliche Domänen (Accounts, Contracts, Customers, Helpdesks, Offers, Orders, Receipts, Tickets, WebAccount u. a.) in eigene Controller.
Aussage: Das System soll externen und internen Clients eine versionierte, nach Fachdomänen strukturierte REST-Schnittstelle mit einheitlicher, wiederverwendbarer Authentifizierungs-/Autorisierungsprüfung bereitstellen.
Ergebnis: Neue API-Versionen können eingeführt werden, ohne bestehende Client-Integrationen zu brechen; jede Aktion ist konsistent gegen Benutzerrecht und Lizenz geprüft.
Belege:
- [PRIMÄR] src/webservice/Centron.Controllers/Controllers/v1/ (15 Domänen-Unterordner) - Begründung: Belegt die tatsächliche Domänenaufteilung und Versionierung der API.
- [PRIMÄR] src/webservice/Centron.Controllers/Configuration/RegisterCentronApiVersioning.cs - Begründung: Konfiguriert namensraumbasierte Versionierung (Asp.Versioning) mit URL-Segment `v{version}`.
- [SEKUNDÄR] src/webservice/Centron.Controllers/Authorization/README.md - Begründung: Dokumentiert das vorgesehene Zusammenspiel von `AuthorizeCentronHosted` (Lizenz) und `AuthorizeUserRight` (Berechtigung).
Prüfidee: API-Aufruf ohne gültiges Recht (403), ohne gültige Authentifizierung (401) und mit beidem (Erfolg) gegen einen v1-Endpunkt prüfen.
Tracelinks: SyRS-037, SyRS-038
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-043
Titel: Nachvollziehbare Produktnutzung für Lizenz- und Produktsteuerung
Ebene: StRS
Typ: nicht-funktional
Akteur: NEXOWARE (Produktmanagement/Lizenzierung)
Vorbedingung: Ein Benutzer nutzt eine API-Methode, ein KI-gestütztes Werkzeug oder ein MCP-Tool.
Fakt: `TelemetryBL` erfasst und speichert (nach Benutzer, Hardware-ID, Zeit-Bucket gruppiert) die Nutzung von MCP-Tools, KI-Assistenz-Werkzeugen und API-Methoden in eigenen Tabellen und lädt diese Daten gebündelt zu einem externen Server hoch.
Aussage: Das System soll die Nutzung von API-Methoden und KI-/MCP-Werkzeugen je Benutzer/Installation erfassen und für eine zentrale Auswertung bereitstellen.
Ergebnis: NEXOWARE erhält eine Datengrundlage für Produkt- und Lizenzentscheidungen (z. B. Mengenlizenzen, Funktionsnutzung).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Telemetry/TelemetryBL.cs:36-95,181-276 - Begründung: Konkrete Tabellen (`McpToolUsageTelemetry`, `ArtificialIntelligenceToolUsageTelemetry`, `ApiCallTelemetry`), Bucket-Logik und Upload-Mechanismus.
Prüfidee: API-Aufruf durchführen und Vorhandensein eines entsprechenden Telemetrie-Eintrags nach dem nächsten Bucket-Zyklus prüfen.
Tracelinks: SyRS-039
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-044
Titel: Filial- und mandantenübergreifende Datenisolierung
Ebene: StRS
Typ: Daten
Akteur: Systemadministrator, Fachbereichsleiter
Vorbedingung: Ein Unternehmen mit mehreren Filialen bzw. mehreren rechtlichen Einheiten (Mandanten) betreibt eine gemeinsame Installation.
Fakt: Es existieren zwei getrennte Skalierungsebenen: `Mandator` (Unternehmen/rechtliche Einheit) und `Branch`/`Filiale` (Standort); zentrale Geschäftsobjekte (Aufträge, Lagerbestände, Nummernkreise) tragen `BranchI3D`, Nummernkreise zusätzlich `MandatorI3D`.
Aussage: Das System soll Geschäftsdaten auf zwei Ebenen — Mandant (rechtliche Einheit) und Filiale (Standort) — organisatorisch trennen und filialbezogene Auswertungen/Berechtigungen ermöglichen.
Ergebnis: Ein Unternehmen mit mehreren Filialen/Mandanten kann Daten korrekt zuordnen und filial-/mandantenbezogen einschränken (siehe auch StRS-016).
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Administration/Company/Mandator.cs - Begründung: Eigenständige Entität für die Mandantenebene.
- [PRIMÄR] src/backend/Centron.DAO/Mappings/Sales/CustomerAssets/Orders/OrderMaps.cs:74-75 (BranchI3D, BranchFrom) - Begründung: Belegt Filial-Scoping auf zentralen Geschäftsobjekten.
Prüfidee: Zwei Filialen unter einem Mandanten anlegen, Auftrag je Filiale erfassen und filialbezogene Auswertung/Berechtigungsfilterung prüfen.
Tracelinks: SyRS-040
Konsolidierung: nein
Status: belegt; [HYPOTHESE] wie konsequent DAO-Abfragen global nach Mandant/Filiale filtern, wurde nicht vollständig verifiziert — siehe Hypothesen.md H-06.
```
```
ID: StRS-045
Titel: Sichere Speicherung von Benutzerpasswörtern
Ebene: StRS
Typ: Sicherheit
Akteur: Systemadministrator, alle Benutzer (mittelbar)
Vorbedingung: Ein Benutzerpasswort wird gespeichert oder bei Login geprüft.
Fakt: `BasicAuthenticator.AuthenticateInternal` hasht das eingegebene Passwort ausschließlich mit `SHA1Decoder.GetDecodedSHA1String(...)` ohne erkennbares Salt und vergleicht es direkt gegen den gespeicherten Wert; ein Code-Kommentar im selben Modul lautet explizit `// TODO the password should be salted!!!`.
Aussage: Das System soll Benutzerpasswörter mit einem modernen, gesalzenen Hash-Verfahren speichern, das gegen Rainbow-Table- und Brute-Force-Angriffe widerstandsfähig ist.
Ergebnis: Bei einem Datenbank-Kompromittierungsszenario sind gespeicherte Passwort-Hashes nicht trivial in Klartext rückführbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs:46-48 - Begründung: Direkter Code- und Kommentarbeleg für ungesalzenes SHA-1-Hashing; von den Entwicklern selbst als offene Baustelle markiert.
Prüfidee: Zwei Benutzer mit identischem Passwort anlegen und prüfen, ob die gespeicherten Hash-Werte identisch sind (Indiz für fehlendes Salt); Ergebnis mit Sicherheitsverantwortlichen bewerten.
Tracelinks: SyRS-044
Konsolidierung: nein
Status: belegt; Workaround (von den Entwicklern selbst als technische Schuld markiert — hohe Priorität für Zielsystem-Migration)
```
@@ -0,0 +1,846 @@
# SyRS — System Requirements Specification
c-entron ERP-Suite — Reverse Requirements Engineering, Iteration 01 (Baseline).
Systemverhalten, Schnittstellen, Performance-/Sicherheitsanforderungen. Ebene: `SyRS`. NFR-Einordnung folgt ISO/IEC 25010 (Feld `Typ` bzw. Erläuterung im Text).
## A. Beleg-Lebenszyklus (zu StRS-001..004)
```
ID: SyRS-001
Titel: Einheitlicher Belegstatus-Wertebereich
Ebene: SyRS
Typ: Daten
Akteur: System
Vorbedingung: Ein Belegobjekt jeden Typs wird angelegt oder verändert.
Fakt: `ReceiptState` ist eine geschlossene Aufzählung mit genau drei Werten (Active=1, Completed=2, Canceled=3), typisiert auf `ReceiptBase.State`.
Aussage: Das System soll für alle Belegtypen ausschließlich die Statuswerte "Active", "Completed" und "Canceled" als gültige Werte des Feldes `State` zulassen.
Ergebnis: Kein Beleg kann einen undefinierten oder belegtypspezifischen vierten Status annehmen.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 - Begründung: Enum-Definition ist die einzige im Code zulässige Wertemenge.
Prüfidee: Versuch, einen ungültigen Integer-Wert außerhalb {1,2,3} in `State` zu schreiben, muss durch Typsystem/DB verhindert werden.
Tracelinks: StRS-001; SwRS-001
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-002
Titel: Gemeinsames Basisdatenmodell für alle Belegtypen
Ebene: SyRS
Typ: Daten
Akteur: System
Vorbedingung: Ein neuer Belegtyp wird im System benötigt.
Fakt: Alle sieben Belegtypen (Angebot, Auftrag, Lieferschein, Rechnung, Vertrag, Gutschrift, Abholschein) sind über eine gemeinsame Kopf/Positions-Struktur (`ReceiptBase`/`ReceiptItemBase`) sowie ein Kopf/Pos/Versions-Tabellenmuster abgebildet.
Aussage: Das System soll für neue Belegtypen dasselbe Kopf/Positions-Basisdatenmodell wie für bestehende Belegtypen verwenden.
Ergebnis: Gemeinsame Funktionalität (Suche, Sperren, Versionierung, Protokollierung) steht neuen Belegtypen ohne Neuimplementierung zur Verfügung.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs, ReceiptItemBase.cs - Begründung: Gemeinsame Basisklassen aller Belegentitäten.
- [SEKUNDÄR] docs/reference/receipts/receipts-backend-architecture.md (Abschnitt "Extensibility") - Begründung: Beschreibt den vorgesehenen Ablauf zur Erweiterung um neue Belegtypen.
Prüfidee: Struktur eines neu hinzugefügten Belegtyps (z. B. anhand der Dokumentation) gegen die Basisklassen validieren.
Tracelinks: StRS-001; SwRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-003
Titel: Deklarative Belegweiterleitungs-Matrix je Belegtyp
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Eine Belegweiterleitung wird angestoßen.
Fakt: Jede Implementierung von `IReceiptSpecificLogic` deklariert `CanBeForwardedFrom()`/`CanBeForwardedInto()` als Liste erlaubter `CentronObjectKindNumeric`-Werte; `ReceiptBL.ForwardReceipt<TTarget,...>` prüft diese Deklaration vor Ausführung.
Aussage: Das System soll vor jeder Belegweiterleitung die deklarierte Übergangserlaubnis des Quell- und Zielbelegtyps prüfen und bei Verstoß die Weiterleitung ablehnen.
Ergebnis: Nicht deklarierte Belegübergänge werden systemseitig, nicht nur durch UI-Konvention, verhindert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:256-257 - Begründung: Konkrete Deklaration für den Belegtyp Auftrag.
Prüfidee: Direkter API-/BL-Aufruf zur Weiterleitung eines nicht erlaubten Übergangs muss mit definiertem Fehler abgelehnt werden (nicht nur UI-seitig ausgeblendet).
Tracelinks: StRS-002; SwRS-003
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-004
Titel: Strukturidentität von Basis- und Versionstabellen
Ebene: SyRS
Typ: Daten
Akteur: System, Datenbankschema-Migration
Vorbedingung: Eine neue Spalte wird einer Belegtabelle hinzugefügt.
Fakt: Versionstabellen (`*KopfVersions`/`*PosVersions`) müssen laut Architekturdokumentation exakt dieselben Spalten wie die Basistabelle enthalten (außer `I3D`, plus `OriginalI3D`/`KopfVersionsI3D`); fehlende Spalten führen zu Laufzeitfehlern in `DoGetFieldList()`.
Aussage: Das System soll sicherstellen, dass jede Spalte einer Beleg-Basistabelle auch in der zugehörigen Versionstabelle mit identischem Datentyp existiert.
Ergebnis: Der Versionierungsmechanismus kann für jeden Beleg vollständige Schnappschüsse erzeugen, ohne durch fehlende Spalten zu scheitern.
Belege:
- [PRIMÄR] docs/reference/receipts/receipts-backend-architecture.md (Abschnitt "Adding New Columns - Complete Checklist", "Critical Warning") - Begründung: Dokumentiert den Fehlerfall bei Abweichung sowie die 10-Schritte-Checkliste zur korrekten Erweiterung.
Prüfidee: Neue Spalte nur an der Basistabelle ergänzen (Versionstabelle bewusst auslassen) und Auftreten des dokumentierten Laufzeitfehlers bei Versionierung verifizieren.
Tracelinks: StRS-003; SwRS-004
Konsolidierung: nein
Status: belegt; Workaround (manuell zu pflegende Strukturparität statt automatisierter Schema-Synchronisation — Migrationsrisiko für Zielsystem)
```
```
ID: SyRS-005
Titel: Zentrale, belegtypübergreifende Ereignisprotokollierung
Ebene: SyRS
Typ: Daten
Akteur: System
Vorbedingung: Ein Belegereignis (Erstellung, Änderung, Abrechnung, Stornierung) tritt ein.
Fakt: Die Tabelle `AnlageLog` protokolliert Ereignisse für alle Belegtypen einheitlich über `AnlageI3D` + `AnlageArt` (Typkennzahl je Belegtyp).
Aussage: Das System soll belegbezogene Ereignisse aller Belegtypen in einer zentralen, typkennzahlbasierten Protokolltabelle erfassen.
Ergebnis: Auswertungen über Belegereignisse sind belegtypübergreifend ohne UNION mehrerer Spezialtabellen möglich.
Belege:
- [PRIMÄR] docs/reference/receipts/receipts-backend-architecture.md (Abschnitt "Shared Logging Infrastructure") - Begründung: Beschreibt Tabellenstruktur und AnlageArt-Wertetabelle.
Prüfidee: Ereignis für zwei unterschiedliche Belegtypen auslösen und Vorhandensein je eines `AnlageLog`-Eintrags mit korrektem `AnlageArt` prüfen.
Tracelinks: StRS-003; SwRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-006
Titel: Kollisionsschutz bei gleichzeitigem Belegzugriff
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010: Fehlertoleranz)
Akteur: System
Vorbedingung: Zwei Sitzungen greifen gleichzeitig auf denselben Beleg zu.
Fakt: Anwendungsseitige Sperrentität (`AssetLock`, Spalte `Lockuser`) plus optimistisches `ConcurrencyControlGuid`-Feld auf `ReceiptBase`; beide Mechanismen sind unabhängig voneinander im Code vorhanden.
Aussage: Das System soll konkurrierende Schreibzugriffe auf denselben Beleg erkennen und einen davon kontrolliert zurückweisen, statt Änderungen stillschweigend zu überschreiben.
Ergebnis: Datenverlust durch "Last-Write-Wins" wird verhindert.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/CustomerAssets/AssetLocks/AssetLock.cs:6-10 - Begründung: Explizites Sperrmodell.
- [SEKUNDÄR] tests/Centron.Tests.EndToEnd/Tests/ReceiptLock/*.expected.txt - Begründung: 8 getestete Kombinationen belegen den Anspruch an vollständige Fallabdeckung.
Prüfidee: Siehe StRS-004.
Tracelinks: StRS-004; SwRS-005
Konsolidierung: Kandidat: siehe StRS-004 (zwei parallele Mechanismen).
Status: belegt
```
## B. Verträge & RMM-Abrechnung (zu StRS-005..007)
```
ID: SyRS-007
Titel: Konfigurierbares Abrechnungsintervall je Vertrag
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Ein Vertrag mit `AutomatedBilling = true` erreicht sein nächstes Abrechnungsdatum.
Fakt: `BillingIntervalKind` (Daily/Monthly/Quarterly/Yearly) kombiniert mit `BillingIntervalDuration` bestimmt den nächsten Abrechnungszeitpunkt; `LastSubsequentBillingDate` wird nach Ausführung fortgeschrieben.
Aussage: Das System soll das nächste Abrechnungsdatum eines Vertrags aus Intervalltyp und -dauer berechnen und nach jeder automatisierten Abrechnung fortschreiben.
Ergebnis: Kein Vertrag wird doppelt oder verspätet automatisch abgerechnet.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs (BillingIntervalKind, BillingIntervalDuration, LastSubsequentBillingDate) - Begründung: Datenfelder, die die Berechnung tragen.
Prüfidee: Vertrag mit Quartalsintervall (Monthly×3) anlegen und Fälligkeitsberechnung über mehrere Zyklen prüfen.
Tracelinks: StRS-005; SwRS-006
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-008
Titel: Kontingentbilanzierung mit Grenzwertüberwachung
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Eine kontingentrelevante Leistung wird einem Vertrag zugebucht.
Fakt: `ReceiptContractBL.ContractContingentBalanceCalculation` berechnet `ContingentUsedHours`/`ContingentUsedAmount` gegen `ContingentLimitValue`; `IsMonitoring`/`MonitoringValue` steuern eine zusätzliche Überwachungsschwelle.
Aussage: Das System soll bei jeder kontingentrelevanten Buchung den Kontingentverbrauch neu berechnen und bei Überschreitung der konfigurierten Überwachungsschwelle eine Markierung setzen.
Ergebnis: Vertragsverantwortliche werden zeitnah auf drohende oder eingetretene Kontingentüberschreitung hingewiesen.
Belege:
- [PRIMÄR] docs/reference/receipts/contracts-backend.md (Abschnitt "Contingent Limits and Monitoring") - Begründung: Beschreibt die Feld- und Berechnungslogik.
Prüfidee: Kontingent bis knapp unter, dann über die Überwachungsschwelle buchen und Statusänderung prüfen.
Tracelinks: StRS-005, StRS-007; SwRS-006
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-009
Titel: Fail-Closed-Verhalten bei nicht erreichbarem RMM-Dienst
Ebene: SyRS
Typ: Zuverlässigkeit (ISO 25010: Fehlertoleranz)
Akteur: System
Vorbedingung: Ein RMM-fähiger Vertrag wird abgerechnet; der externe RMM-Dienst antwortet nicht.
Fakt: `RiverConnectionBL.GetContractBillingAmounts` liefert einen Fehlerstatus zurück; ist mindestens eine RMM-Artikelreferenz oder ein RMM-Platzhalter vorhanden, wirft der Aufrufer eine `RMMServiceUnavailableException`, die die gesamte Rechnungserstellung abbricht.
Aussage: Das System soll die automatische Rechnungserstellung für einen RMM-abhängigen Vertrag vollständig abbrechen, wenn der externe RMM-Dienst zum Abrechnungszeitpunkt nicht erreichbar ist.
Ergebnis: Keine Rechnung mit fehlenden oder veralteten Nutzungsdaten wird versehentlich final gestellt.
Belege:
- [PRIMÄR] docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md (Codebeispiel `RMMServiceUnavailableException`) - Begründung: Zeigt exakten Bedingungs- und Abbruchcode.
Prüfidee: RMM-Dienst-Endpunkt für einen Testlauf deaktivieren und Abbruch der Rechnungserstellung mit definierter Fehlermeldung prüfen.
Tracelinks: StRS-006; SwRS-007
Konsolidierung: nein
Status: belegt
```
## C. C-Sign / Web-Angebot (zu StRS-008..009)
```
ID: SyRS-010
Titel: Mehrstufiger Statuswechsel für Web-Angebote
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Ein Angebot wird über den Web-Kanal versendet.
Fakt: `WebReceiptState` definiert 9 Zustände (`InProcess`, `FirstLoaded`, `SendToCustomer`, `WebOfferSign`, `AcceptFullWebReceipt`, `AcceptWebReceiptWithChangeRequests`, `Rejected`, `WebReceiptShutDown`, `WebOfferSignedWithoutSignature`); `ReceiptBL.ChangeWebReceiptState` dispatcht je nach Zielzustand auf spezialisierte Methoden.
Aussage: Das System soll den Fortschritt eines Web-Angebots über die neun definierten Zwischenzustände nachvollziehbar abbilden und Zustandswechsel nur über definierte Dispatch-Methoden zulassen.
Ergebnis: Der aktuelle Bearbeitungsstand eines Web-Angebots ist jederzeit eindeutig bestimmbar.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/WebReceipt/WebReceiptState.cs:6-26 - Begründung: Vollständige Enum-Definition.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:5903-5934 (ChangeWebReceiptState) - Begründung: Zentrale Dispatch-Methode.
Prüfidee: Web-Angebot durch alle Hauptpfade (Annahme ohne Signatur / mit Signatur / Ablehnung / Änderungswunsch) führen und Zustandsfolge protokollieren.
Tracelinks: StRS-008; SwRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-011
Titel: Getrennte interne Freigabe vor externem Kundenversand
Ebene: SyRS
Typ: Sicherheit
Akteur: Vertriebsmitarbeiter
Vorbedingung: Ein zu signierendes Dokument soll an den Kunden versendet werden.
Fakt: `SharedDocumentAcceptancePage.razor` implementiert einen eigenen, internen Freigabeschritt (`AcceptSharedDocument`/`DeclineSharedDocument`) über einen Token-Link, bevor `AcceptWebReceipt` den kundenseitigen Signaturlink per E-Mail versendet.
Aussage: Das System soll den Versand eines zur Kundenunterschrift bestimmten Dokuments von einer vorgelagerten internen Freigabe durch einen Mitarbeiter abhängig machen können.
Ergebnis: Fehlerhafte oder unvollständige Dokumente erreichen den Kunden nicht ungeprüft.
Belege:
- [PRIMÄR] src/nexus/CentronNexus/Office/SharedDocumentAcceptancePage.razor:167-179 - Begründung: Konkrete Freigabe-/Ablehnungsaktionen.
- [PRIMÄR] src/backend/Centron.BL/Security/PdfSigningBL.cs:126-165 - Begründung: Nachgelagerte kryptographische Signatur nach Freigabe.
Prüfidee: Dokument ohne interne Freigabe darf nicht an den Kunden-Signaturlink gelangen; nach Freigabe muss der Versand erfolgen.
Tracelinks: StRS-008, StRS-009; SwRS-008
Konsolidierung: nein
Status: belegt
```
## D. Kunde/CRM (zu StRS-010..012)
```
ID: SyRS-012
Titel: Kreditlimitprüfung als weicher Kontrollpunkt beim Belegspeichern
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Ein limitrelevanter Beleg (aktiver Auftrag) wird gespeichert.
Fakt: `ReceiptBL.CheckIfCustomerLimitIsReached` berechnet den genutzten Kreditrahmen aus allen `Active`-Belegen, die laut `TakesPlaceInLimitCalculation()` limitrelevant sind, und liefert bei Überschreitung ein Bestätigungserfordernis (`ShowCustomerLimitExceededDialog`) statt eines harten Fehlers zurück.
Aussage: Das System soll bei jedem Speichern eines limitrelevanten Belegs den genutzten Kreditrahmen neu berechnen und bei Überschreitung ein explizites Bestätigungssignal an den aufrufenden Client zurückgeben.
Ergebnis: Die UI kann dem Benutzer eine Bestätigungsabfrage anzeigen, ohne die Geschäftslogik zu duplizieren.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:8636 - Begründung: Konkrete Berechnungs- und Rückgabelogik.
Prüfidee: Siehe StRS-010.
Tracelinks: StRS-010; SwRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-013
Titel: API-Bereitstellung kundenspezifischer Sonderpreis-Artikellisten
Ebene: SyRS
Typ: Schnittstelle
Akteur: Nexus-Web-Client
Vorbedingung: Ein Web-Account ruft die für ihn verfügbaren Artikel ab.
Fakt: `CustomersController` stellt `GET special-price-articles` und `GET {customerId}/special-price-articles` bereit.
Aussage: Das System soll eine REST-Schnittstelle bereitstellen, über die die für einen Kunden hinterlegten Sonderpreis-Artikel abgefragt werden können.
Ergebnis: Der Web-Client kann die WebCart-Artikelsicht ohne direkten Datenbankzugriff aufbauen.
Belege:
- [PRIMÄR] src/webservice/Centron.Controllers/Controllers/v1/Customers/CustomersController.cs:12-100 - Begründung: Konkrete Endpunktdefinition.
Prüfidee: Endpunkt für einen Testkunden mit Sonderpreisen aufrufen und korrekte Artikelliste inkl. Preis prüfen.
Tracelinks: StRS-011, StRS-035; SwRS-010
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-014
Titel: Kundenindividuelle Katalogsteuerung (Produktmatrix)
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Ein Kunde/Web-Account ruft den Artikelkatalog ab.
Fakt: `CustomerProductMatrixCategory`/`CustomerProductMatrixProduct` bilden eine kundenindividuell kuratierte Kategorie-/Produktstruktur ab (`ProductMatrixBL`).
Aussage: Das System soll es ermöglichen, den für einen Kunden sichtbaren Artikelkatalog über kundenindividuell zugeordnete Kategorien/Produkte einzuschränken.
Ergebnis: Kunden sehen nur die für sie freigegebenen Kategorien/Produkte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ProductMatrix/ProductMatrixBL.cs:27-60 - Begründung: Konkrete Zugriffsmethoden auf die kundenindividuelle Struktur.
Prüfidee: Kundenindividuelle Produktmatrix konfigurieren und Filterwirkung im Katalog/WebCart prüfen.
Tracelinks: StRS-011; SwRS-010
Konsolidierung: Kandidat: Verhältnis zu Sonderpreis-Mechanismus (SyRS-013) ungeklärt — möglicherweise zwei Mechanismen für dasselbe fachliche Ziel "Artikelsichtbarkeit je Kunde steuern" (siehe Hypothesen.md).
Status: belegt
```
## E. Helpdesk/Ticket (zu StRS-013..014)
```
ID: SyRS-015
Titel: Konfigurierbare Ticketerstellungs-Vorlagen mit eindeutiger Standardvorlage
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Mehrere Ticketerstellungs-Vorlagen existieren.
Fakt: `HelpdeskCreationTemplateBL.SetStandardTemplate` stellt sicher, dass zu jedem Zeitpunkt höchstens eine Vorlage als Standard markiert ist; `DeleteTemplate` verweigert das Löschen der Standardvorlage.
Aussage: Das System soll zu jedem Zeitpunkt höchstens eine Ticketerstellungs-Standardvorlage zulassen und deren Löschung verhindern, solange sie als Standard markiert ist.
Ergebnis: Es ist immer eindeutig, welche Vorlage bei Neuöffnung des Formulars automatisch geladen wird.
Belege:
- [PRIMÄR] docs/features/automatic-helpdesk-creation-templates.md (Abschnitt "Business Rules", "Known Limitations") - Begründung: Dokumentiert beide Regeln explizit inkl. Methodennamen.
Prüfidee: Zweite Vorlage als Standard setzen und Aberkennung des Standard-Flags der ersten Vorlage prüfen; Löschversuch der aktuellen Standardvorlage muss scheitern.
Tracelinks: StRS-013, StRS-014; SwRS-011
Konsolidierung: nein
Status: belegt
```
## F. Rechte & Zugriffssteuerung (zu StRS-015..018)
```
ID: SyRS-016
Titel: Zentraler, gecachter Rechteprüfungsdienst
Ebene: SyRS
Typ: Sicherheit
Akteur: System (jede geschützte Aktion)
Vorbedingung: Eine geschützte Aktion wird ausgeführt.
Fakt: `AppRightsBL.HasUserRight` nutzt einen Session-Cache (`Session.Advanced.Cache.GetOrAdd`) für die Rechteliste je Benutzer, rückt aber bei jeder Prüfung auf denselben SQL-Join (`Sichtrus`↔`Sichmemb`) zurück, falls nicht gecacht.
Aussage: Das System soll die Menge der einem Benutzer zugewiesenen Rechte innerhalb einer Sitzung cachen, um wiederholte Datenbankabfragen bei aufeinanderfolgenden Rechteprüfungen zu vermeiden.
Ergebnis: Rechteprüfungen sind performant, ohne die Autorisierungslogik zu duplizieren.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs:644-651 - Begründung: Konkrete Cache- und SQL-Join-Implementierung.
Prüfidee: Mehrere Rechteprüfungen innerhalb derselben Sitzung ausführen und (via Profiling) genau einen SQL-Zugriff für die Rechteliste nachweisen.
Tracelinks: StRS-015, StRS-017; SwRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-017
Titel: Ausschließliche Rechtevergabe über Gruppenmitgliedschaft
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Ein Recht soll einem Benutzer zugeordnet werden.
Fakt: Es existiert keine Datenbanktabelle für eine direkte Nutzer-Recht-Zuordnung; Rechte werden ausschließlich über `AppGroup.Rights` und `AppUser.Groups` (Join `Sichtrus`↔`Sichmemb`) vergeben.
Aussage: Das System soll Benutzerrechte ausschließlich über die Zuordnung von Benutzern zu Berechtigungsgruppen vergeben, nicht über eine direkte Benutzer-Recht-Zuordnung.
Ergebnis: Rechteänderungen für mehrere Benutzer gleichzeitig sind über eine einzige Gruppenänderung möglich; Einzelrechte pro Benutzer sind architektonisch ausgeschlossen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs:63-87 (GetRightsFromCurrentUser, Union über user.Groups) - Begründung: Zeigt, dass die effektiven Rechte ausschließlich aus Gruppen ermittelt werden.
Prüfidee: Versuch, einem Benutzer ohne Gruppenzuordnung ein Einzelrecht zuzuweisen — es muss kein entsprechender Mechanismus im System existieren.
Tracelinks: StRS-015, StRS-016, StRS-018; SwRS-012, SwRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-018
Titel: Austauschbare Authentifizierungsstrategie über Factory-Pattern
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Ein Login-Versuch wird empfangen.
Fakt: `AuthenticatorFactory` liefert je nach `SystemAuthenticationMethod` und `WebLoginType` eine passende `IAuthenticator`-Implementierung (Basic/ActiveDirectory/OpenIdConnect/WebAccount), optional verkettet mit `FallbackAuthenticator`.
Aussage: Das System soll die Wahl der Authentifizierungsmethode zur Laufzeit anhand einer Systemeinstellung treffen, ohne dass aufrufender Code die konkrete Methode kennen muss.
Ergebnis: Neue Authentifizierungsmethoden können ergänzt werden, ohne bestehende Aufrufer zu ändern.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs - Begründung: Konkrete Factory-Implementierung.
Prüfidee: Systemeinstellung zwischen den drei Methoden umschalten und erfolgreichen Login je Methode prüfen.
Tracelinks: StRS-019, StRS-021; SwRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-019
Titel: Zertifikatsbasierte JWT-Bearer-Validierung für OIDC-Anmeldung
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Ein Client präsentiert ein Microsoft-Entra-ID-Token an `POST jwt/login`.
Fakt: `CentronHost.cs` konfiguriert `AddJwtBearer` mit `ValidateIssuer/Audience/Lifetime/IssuerSigningKey = true`, `RequireSignedTokens = true`, `RequireExpirationTime = true`, `ValidateTokenReplay = true`; der Endpunkt ist zusätzlich mit `[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]` geschützt.
Aussage: Das System soll bei der OIDC-Anmeldung sämtliche Standard-JWT-Validierungsprüfungen (Signatur, Aussteller, Zielgruppe, Gültigkeitsdauer, Replay-Schutz) durchsetzen, bevor ein internes Sitzungsticket ausgestellt wird.
Ergebnis: Manipulierte, abgelaufene oder wiederverwendete Tokens werden abgelehnt.
Belege:
- [PRIMÄR] src/webservice/Centron.Host/CentronHost.cs:186-205 - Begründung: Konkrete `TokenValidationParameters`-Konfiguration.
- [SEKUNDÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md - Begründung: Beschreibt den vollständigen Ablauf inkl. Discovery-Document und JWKS-Abruf.
Prüfidee: Manipuliertes/abgelaufenes Token gegen `jwt/login` senden und Ablehnung (401) prüfen.
Tracelinks: StRS-019; SwRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-020
Titel: Feste Sitzungs-Gültigkeitsdauern mit kontinuierlicher Revalidierung im Web-Client
Ebene: SyRS
Typ: Sicherheit
Akteur: System, Nexus-Web-Client
Vorbedingung: Eine Sitzung ist aktiv.
Fakt: Server: `TicketExpireInMinutes=30`; Web-Client: `CentronAuthenticationStateProvider` revalidiert alle 1-2 Minuten gegen `ICentronService.IsValidTicket()`, mit bis zu 3 Wiederholungsversuchen (2 s Verzögerung) bei transienten Fehlern, bevor eine erzwungene Abmeldung erfolgt.
Aussage: Das System soll serverseitige Sitzungen nach spätestens 30 Minuten automatisch ungültig werden lassen und im Web-Client die Sitzungsgültigkeit in kürzeren Abständen aktiv prüfen, um Sitzungsabläufe zeitnah zu erkennen.
Ergebnis: Eine im Hintergrund abgelaufene Sitzung wird dem Nutzer im Web-Client innerhalb weniger Minuten angezeigt statt erst beim nächsten fehlschlagenden Aufruf.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TicketBL.cs:26-28,61 - Begründung: Serverseitige Ablaufzeit.
- [PRIMÄR] src/nexus/CentronNexus/Shared/Auth/CentronAuthenticationStateProvider.cs:15-66 - Begründung: Clientseitige Revalidierungs-/Retry-Konfiguration inkl. Kommentar zur bewussten Intervallverkürzung gegen ein Race-Window.
Prüfidee: Ticket serverseitig invalidieren und Zeit bis zur client-seitigen Erkennung (Abmeldung/Hinweis) messen; muss innerhalb des konfigurierten Revalidierungsintervalls liegen.
Tracelinks: StRS-020; SwRS-015
Konsolidierung: nein
Status: belegt
```
## G. Lizenzierung (zu StRS-022)
```
ID: SyRS-021
Titel: Lizenzgate als eigenständige Autorisierungsanforderung
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Ein API-Aufruf betrifft eine lizenzpflichtige, intern gehostete Funktion.
Fakt: `CentronHostedAuthorization` implementiert eine ASP.NET-Core-`AuthorizationRequirement`, deren einzige Prüfung `LicenseManager.Instance.HasLicense(LicenseGuids.CentronInternal)` ist — unabhängig von Benutzeridentität.
Aussage: Das System soll eine Lizenzprüfung als eigenständige, von der Benutzeridentität unabhängige Autorisierungsanforderung im API-Pipeline umsetzen, kombinierbar mit rechtebasierten Prüfungen.
Ergebnis: Funktionen ohne gültige Installationslizenz sind unabhängig von individuellen Benutzerrechten gesperrt.
Belege:
- [PRIMÄR] src/webservice/Centron.Controllers/Authorization/CentronHostedAuthorization.cs:8-35 - Begründung: Konkrete Requirement-/Handler-Implementierung.
Prüfidee: Lizenz `CentronInternal` deaktivieren und Zugriff auf entsprechend geschützten Endpunkt trotz gültiger Benutzerrechte prüfen (muss abgelehnt werden).
Tracelinks: StRS-022, StRS-042; SwRS-016
Konsolidierung: nein
Status: belegt
```
## H. Rechnungsstellung/Nummerierung/Festschreibung (zu StRS-023..027)
```
ID: SyRS-022
Titel: Kollisionssichere Nummernvergabe unter Nebenläufigkeit
Ebene: SyRS
Typ: Zuverlässigkeit (ISO 25010: Fehlertoleranz)
Akteur: System
Vorbedingung: Zwei Belege desselben Nummernkreises werden nahezu gleichzeitig gespeichert.
Fakt: `NumberGroupBL` verwendet eine bedingte `UPDATE NumberGroup SET Current = next WHERE I3D=... AND Current = <alter Wert>`-Schleife, die bei Nichttreffer (paralleler Änderung durch anderen Prozess) wiederholt wird, bis genau eine Zeile betroffen ist.
Aussage: Das System soll die Vergabe der nächsten Belegnummer eines Nummernkreises so implementieren, dass bei gleichzeitigem Zugriff mehrerer Prozesse keine doppelte Nummer entstehen kann.
Ergebnis: Auch unter hoher Last/Parallelität bleibt die Nummernvergabe eindeutig.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs (GetNextNumber, FindNextNumber) - Begründung: Konkrete optimistische Update-Schleife.
Prüfidee: Lasttest mit ≥10 parallelen Rechnungserstellungen gegen denselben Nummernkreis; Eindeutigkeit aller vergebenen Nummern prüfen.
Tracelinks: StRS-023; SwRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-023
Titel: Mehrfach abgesicherte Änderungssperre für finalisierte/exportierte Rechnungen
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Eine Änderung/Stornierung/Löschung an einer Rechnung, Zahlung oder Bankverbindung wird angefragt.
Fakt: Mehrere unabhängige Guard-Prüfungen verhindern inkonsistente Finanzbuchungen: `IsFixed`-Prüfung vor Bearbeitung, Export-Status-Prüfung (`IsReceiptExported`) vor Stornierung, Referenzprüfung vor Löschung einer Bankverbindung, Rechteprüfung vor Zahlungslöschung mit korrekter Rückbuchung.
Aussage: Das System soll Änderungen, Stornierungen und Löschungen an finanzrelevanten Objekten (Rechnung, Zahlung, Bankverbindung) nur zulassen, wenn keine der jeweils relevanten Sperrbedingungen (Festschreibung, Buchhaltungsexport, aktive Referenzierung, fehlende Berechtigung) zutrifft.
Ergebnis: Bereits weiterverarbeitete oder referenzierte Finanzdaten bleiben konsistent.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:86,143,273 - Begründung: Festschreibungs- und Stornierungs-Guards.
- [PRIMÄR] src/backend/Centron.BL/Accounting/BankAccountBL.cs:119 - Begründung: Referenzprüfung vor Löschung.
- [PRIMÄR] src/backend/Centron.BL/Finances/Payments/PaymentsBL.cs:38 - Begründung: Rechteprüfung + korrekte Rückbuchung bei Zahlungslöschung.
Prüfidee: Je Guard einen gezielten Verletzungsversuch durchführen und Ablehnung mit spezifischer Fehlermeldung prüfen.
Tracelinks: StRS-024, StRS-025, StRS-026, StRS-027; SwRS-018
Konsolidierung: nein
Status: belegt
```
## I. E-Invoicing/EDI (zu StRS-028..029)
```
ID: SyRS-024
Titel: Konfigurierbare Erzeugung strukturierter E-Rechnungsformate
Ebene: SyRS
Typ: Schnittstelle
Akteur: System
Vorbedingung: Eine Rechnung wird finalisiert und die entsprechende Einstellung ist aktiviert.
Fakt: `IsZugferdInvoiceActive` (ApplicationSettings) steuert, ob `InvoiceZugferdBL` beim Rechnungsdruck zusätzlich eine ZUGFeRD-konforme Hybrid-PDF erzeugt; `EbInterfaceLogic` erzeugt unabhängig davon ebInterface-XML.
Aussage: Das System soll die Erzeugung des ZUGFeRD-Rechnungsformats über eine globale Einstellung aktivierbar/deaktivierbar machen und bei Aktivierung automatisch bei jeder Rechnungsfinalisierung anwenden.
Ergebnis: Kunden mit gesetzlicher oder vertraglicher E-Rechnungspflicht erhalten automatisch konforme Dokumente, ohne Sonderprozess je Rechnung.
Belege:
- [PRIMÄR] docs/guides/development/settings-management.md (Beispiel `IsZugferdInvoiceActive`) - Begründung: Zeigt die Einstellung als steuerbaren Schalter.
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs - Begründung: Konkrete Erzeugungslogik.
Prüfidee: Einstellung aktivieren, Rechnung finalisieren, PDF auf eingebettete ZUGFeRD-XML prüfen (z. B. mit KOSIT-Validator).
Tracelinks: StRS-028; SwRS-019
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-025
Titel: Distributorspezifisches EDI-Routing für ausgehende Bestellungen
Ebene: SyRS
Typ: Schnittstelle
Akteur: System
Vorbedingung: Ein Bestellvorschlag wird an einen EDI-fähigen Distributor übermittelt.
Fakt: `EDIDispatcherBL` wählt anhand `EDIMultidistributors` (None/Orderowner/ITScope/EGIS/Concerto) die passende Bestell-Erzeugungsklasse; ohne spezifische Konfiguration wird openTRANS 2.1 als Standardformat verwendet.
Aussage: Das System soll für jeden angebundenen Distributor automatisch das jeweils passende EDI-Bestellformat erzeugen und bei fehlender Distributor-spezifischer Konfiguration auf den offenen Branchenstandard openTRANS 2.1 zurückfallen.
Ergebnis: Neue Distributoren ohne Sonderformat sind ohne Zusatzentwicklung sofort anbindbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/EDIDispatcherBL.cs:36,56 - Begründung: Konkrete Routing- und Default-Logik.
Prüfidee: Bestellung an einen nicht speziell konfigurierten Distributor auslösen und Erzeugung eines validen openTRANS-2.1-Dokuments prüfen.
Tracelinks: StRS-029; SwRS-020
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-026
Titel: Formaterkennung und Partial-Class-Verarbeitung eingehender Lieferanten-EDI-Dokumente
Ebene: SyRS
Typ: Schnittstelle
Akteur: System
Vorbedingung: Eine EDI-Datei eines Lieferanten wird empfangen (Auftragsbestätigung, Lieferung, Rechnung).
Fakt: `SupplierEdiBL` erkennt Format/Objektart (`EdiDataType`, `EDIConnectionObjectKind`) und delegiert an eine lieferantenspezifische Partial-Class (`.Also.cs`, `.AlsoCH.cs`, `.Alltron.cs`, `.Herweck.cs`, `.Komsa.cs`, `.Opentrans.cs`).
Aussage: Das System soll eingehende EDI-Dokumente automatisch nach Format und Dokumentart klassifizieren und an eine dedizierte, lieferantenspezifische Verarbeitungsroutine weiterleiten.
Ergebnis: Format-Erweiterungen (neue Lieferanten) sind isoliert ergänzbar, ohne die zentrale Dispatch-Logik zu ändern.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs (2179 Zeilen, Partial-Class-Struktur) - Begründung: Konkrete Klassenstruktur.
- [SEKUNDÄR] docs/reference/edi/edi-architecture.md - Begründung: Dokumentiert Klassenhierarchie und Datenflussdiagramm.
Prüfidee: Testdatei je unterstütztem Format einspielen und korrekte Delegation an die jeweilige Partial-Class (per Log/Trace) prüfen.
Tracelinks: StRS-029; SwRS-020
Konsolidierung: nein
Status: belegt
```
## J. Einkauf (zu StRS-030..031)
```
ID: SyRS-027
Titel: Bestandsbasierte Bestellvorschlagsberechnung je Lager
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Artikelbestand, offener Bedarf und Zulauf sind bekannt.
Fakt: `OrderSuggestionListBL.GetOrderSuggestionWH` berechnet Vorschläge je Lager unter Einbeziehung von `RefreshIntake` (Zulauf/erwarteter Wareneingang) und distributorspezifischer Preisdaten (`GetDistributorToArticle`).
Aussage: Das System soll Bestellvorschläge je Artikel und Lager unter Berücksichtigung des bereits im Zulauf befindlichen Bestands berechnen.
Ergebnis: Doppelbestellungen für bereits unterwegs befindliche Ware werden vermieden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs (GetOrderSuggestionWH, RefreshIntake:1088) - Begründung: Konkrete Berechnungsmethoden.
Prüfidee: Artikel mit offenem Zulauf und Unterschreitung des Mindestbestands prüfen; Bestellvorschlagsmenge muss den Zulauf berücksichtigen.
Tracelinks: StRS-030; SwRS-021
Konsolidierung: nein
Status: belegt; [HYPOTHESE] siehe Hypothesen.md H-04.
```
```
ID: SyRS-028
Titel: Kumulierte Teillieferungsverfolgung je Bestellposition
Ebene: SyRS
Typ: Daten
Akteur: System
Vorbedingung: Ein Wareneingang zu einer Lieferantenbestellung wird gebucht.
Fakt: `ReceiptSupplierOrderIntake` speichert `InStock`/`Booked` je Bestellposition; `SupplierOrderSpecificLogic.UpdateIntake` aktualisiert diese Werte kumulativ bei jeder Wareneingangsbuchung.
Aussage: Das System soll bei jedem Wareneingang zu einer Bestellposition die kumulierte Eingangsmenge fortschreiben, statt nur den letzten Eingang zu speichern.
Ergebnis: Der Gesamtstatus einer Bestellposition ("wie viel wurde insgesamt geliefert") ist nach beliebig vielen Teillieferungen korrekt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:177-215 - Begründung: Konkrete kumulative Update-Logik.
Prüfidee: Siehe StRS-031.
Tracelinks: StRS-031; SwRS-022
Konsolidierung: nein
Status: belegt
```
## K. Lager (zu StRS-032..033)
```
ID: SyRS-029
Titel: Richtungsabhängige Negativbestands-Kontrollpolitik mit vollständiger Protokollierung
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Eine Bestandsbuchung wird durchgeführt.
Fakt: `ReceiptArticleBookingBL` prüft Negativbuchung nur bei "neu negativ" werdendem Bestand; die Aktivierung dieser Prüfung ist je Belegrichtung konfigurierbar (`WarnIfUserMakesNegativeArticleBooking`/`UserNeedsRightToMakeNegativeArticleBooking`, deaktiviert für Wareneingang, aktiv für Warenausgang); jede Bestandsänderung wird unabhängig davon über `WriteAmountChangeLog` protokolliert.
Aussage: Das System soll die Negativbestandsprüfung richtungsabhängig (Wareneingang vs. -ausgang) konfigurierbar machen und unabhängig vom Ergebnis der Prüfung jede Bestandsänderung protokollieren.
Ergebnis: Fachlich sinnvolle Buchungsrichtungen werden nicht unnötig blockiert; jede Mengenänderung bleibt nachvollziehbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptArticleBookingBL.cs:340-429 - Begründung: Zentrale Buchungs- und Protokollierungslogik.
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/DeliveryLists/DeliveryListSpecificLogic.cs:200-201 vs. SupplierOrderSpecificLogic.cs:222-230 - Begründung: Konkreter Beleg für die richtungsabhängige Konfiguration.
Prüfidee: Siehe StRS-032/033.
Tracelinks: StRS-032, StRS-033; SwRS-023
Konsolidierung: nein
Status: belegt
```
## L. Externe Preisquellen (zu StRS-034)
```
ID: SyRS-030
Titel: Parallele, zeitlich gefilterte Aggregation mehrerer Preisquellen
Ebene: SyRS
Typ: Performance-Effizienz
Akteur: System
Vorbedingung: Ein Benutzer öffnet die Preismatrix eines Artikels.
Fakt: Bis zu sieben Preisquellen (interne Aktionspreise + vier externe APIs + Artikelimport) werden parallel geladen; Ergebnisse werden nach Herstellercode+EAN gecacht und bei Änderung an Aktionspreisen invalidiert; Aktionspreise werden zusätzlich nach Gültigkeitszeitraum gefiltert (`EffectiveFrom.StartOfDay() <= DateTime.Now && EffectiveUntil >= DateTime.Now`).
Aussage: Das System soll Preisdaten aus mehreren internen und externen Quellen parallel abrufen, das Ergebnis cachen und bei Änderung interner Preisdaten gezielt invalidieren.
Ergebnis: Die Preismatrix bleibt trotz mehrerer externer Abhängigkeiten performant nutzbar.
Belege:
- [PRIMÄR] docs/reference/receipts/actionprice-system.md (Abschnitt "Cache Behavior", "Display Rules") - Begründung: Beschreibt Cache-Schlüssel, Invalidierung und Gültigkeitsfilter.
Prüfidee: Aktionspreis außerhalb des Gültigkeitszeitraums anlegen und Nichterscheinen in der Preismatrix prüfen; Preismatrix-Ladezeit mit und ohne Cache messen.
Tracelinks: StRS-034; SwRS-024
Konsolidierung: nein
Status: belegt
```
## M. Web-Portal & TradePool (zu StRS-035..036)
```
ID: SyRS-031
Titel: Cookie-/Ticket-basierte Sitzungsverwaltung im Blazor-Server-Portal
Ebene: SyRS
Typ: Sicherheit
Akteur: Kunde (Web-Account)
Vorbedingung: Ein Kunde meldet sich am Nexus-Portal an (direkt oder über OIDC).
Fakt: `AuthController` (`Route("auth")`) signiert nach erfolgreichem Ticket-Erhalt über `CookieAuthenticationDefaults.AuthenticationScheme` ein; zusätzliche OIDC-Routen (`auth/oidc/login`, `.../reauthenticate`) nutzen `OpenIdConnectDefaults` mit einer temporären Cookie-Zwischenstufe.
Aussage: Das System soll die Web-Portal-Sitzung eines Kunden nach erfolgreicher Authentifizierung (direkt oder über OIDC) über ein serverseitiges Authentifizierungs-Cookie verwalten, das an das zugrunde liegende c-entron-Ticket gekoppelt ist.
Ergebnis: Der Kunde bleibt im Web-Portal angemeldet, solange sowohl Cookie als auch zugrunde liegendes Ticket gültig sind.
Belege:
- [PRIMÄR] src/nexus/CentronNexus/Shared/Auth/AuthController.cs (auth/complete_login, auth/oidc/*) - Begründung: Konkrete Cookie-/OIDC-Implementierung.
Prüfidee: Login über Nexus durchführen, Cookie-Setzung prüfen, Ticket serverseitig invalidieren und erzwungene Abmeldung gemäß SyRS-020 prüfen.
Tracelinks: StRS-035; SwRS-025
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-032
Titel: Eigenständige, salted-hash-basierte Authentifizierung für TradePool-Kunden
Ebene: SyRS
Typ: Sicherheit
Akteur: Kunde (TradePool)
Vorbedingung: Ein TradePool-Kunde meldet sich am separaten Portal an.
Fakt: `TradePoolBL.AuthenticateUser` nutzt eine gesalzene Passwort-Hash-Prüfung, getrennt von den übrigen Authentifizierungswegen (Ticket/JWT/AD/OIDC).
Aussage: Das System soll für den TradePool-Kundenzugang eine eigenständige, vom Haupt-Authentifizierungssystem unabhängige Anmeldung mit gesalzenem Passwort-Hash bereitstellen.
Ergebnis: TradePool-Kunden benötigen keinen regulären c-entron-Benutzer-/Web-Account.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TradePool/TradePoolBL.cs:170-183 - Begründung: Konkrete, eigenständige Authentifizierungsimplementierung.
Prüfidee: TradePool-Login mit korrektem/falschem Passwort testen; Nichtverfügbarkeit einer TradePool-Sitzung für reguläre c-entron-Endpunkte prüfen.
Tracelinks: StRS-036; SwRS-025
Konsolidierung: Kandidat: dritter, unabhängiger Authentifizierungsmechanismus neben Haupt-Auth (SyRS-018) und Web-Account-Rechten (StRS-017) — Konsolidierungspotenzial für Zielsystem.
Status: belegt
```
## N. Betrieb/DevOps (zu StRS-037..038)
```
ID: SyRS-033
Titel: Container-basierte Referenzarchitektur für Testbetrieb
Ebene: SyRS
Typ: Übertragbarkeit
Akteur: Systemadministrator/DevOps
Vorbedingung: Eine Testumgebung soll aufgesetzt werden.
Fakt: `docker/compose/compose.yaml` definiert vier Dienste (db=MSSQL, webservice, smtp=Mailcatcher, nexus) in einem gemeinsamen Netzwerk; das produktive Webservice-Image basiert auf .NET 10 / Alpine Linux mit vorinstallierten ICU/Schriftarten für Dokumentgenerierung.
Aussage: Das System soll über eine vollständige Docker-Compose-Referenzarchitektur (Datenbank, Web-Service, Mail-Testserver, Web-Portal) reproduzierbar als Testumgebung aufsetzbar sein.
Ergebnis: Neue Entwickler/Umgebungen können ohne manuelle Einzelinstallation eine funktionsfähige Instanz starten.
Belege:
- [PRIMÄR] docker/compose/compose.yaml:1-54 - Begründung: Vollständige Dienstdefinition inkl. Ports, Abhängigkeiten, Health-relevanter Reihenfolge (`depends_on`).
- [PRIMÄR] docker/c-entron-api/Dockerfile - Begründung: Bestätigt .NET 10/Alpine als produktive Laufzeitbasis.
Prüfidee: `docker compose up` gemäß Konfiguration ausführen und Erreichbarkeit aller vier Dienste prüfen.
Tracelinks: StRS-037; SwRS-026
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-034
Titel: Ausgewiesene funktionale Einschränkungen im Linux-Betrieb
Ebene: SyRS
Typ: Übertragbarkeit
Akteur: Systemadministrator
Vorbedingung: Der Web-Service wird unter Linux statt Windows betrieben.
Fakt: Dokumentierte Einschränkungen: Sub-Web-Services funktionieren nicht unter Linux (Code liegt nur in der Windows-only "Connection Manager"-Anwendung); es existiert kein Konfigurationswerkzeug für Linux (manuelles Editieren von `WebServiceConfig.xml`); das Zertifikatspasswort liegt unter Linux im Klartext in der Konfigurationsdatei (im Gegensatz zur verschlüsselten Windows-Konfiguration).
Aussage: Das System soll die unter Linux bestehenden funktionalen und sicherheitsrelevanten Einschränkungen (fehlende Sub-Web-Service-Unterstützung, Klartext-Zertifikatspasswort, kein Konfigurationswerkzeug) gegenüber dem Windows-Betrieb dokumentieren.
Ergebnis: Betreiber treffen die Plattformwahl auf Basis bekannter, nicht erst im Betrieb entdeckter Einschränkungen.
Belege:
- [PRIMÄR] docs/guides/services/web-service-on-linux.md (Abschnitte "Differences between Linux and Windows", "What is left to do") - Begründung: Explizite Auflistung aller drei Einschränkungen durch die Entwickler selbst.
Prüfidee: Linux-Installation gemäß Dokumentation aufsetzen und Nichtverfügbarkeit der Sub-Web-Services sowie Klartext-Zertifikatspasswort in der Konfigurationsdatei verifizieren.
Tracelinks: StRS-037; SwRS-026
Konsolidierung: nein
Status: belegt; Workaround (Klartext-Zertifikatspasswort unter Linux ist ein von den Entwicklern selbst dokumentierter Sicherheits-Workaround, kein Zielzustand)
```
```
ID: SyRS-035
Titel: Automatisierte Ticket-Version-Verknüpfung über Webhook
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (Build-Infrastruktur)
Vorbedingung: Ein Build für einen gemergten Pull Request wird erfolgreich abgeschlossen.
Fakt: Ein Azure-DevOps-Service-Hook löst bei `Build completed`/`Succeeded` einen HTTP-POST an `DevOpsCentronTicketBridge` aus, der über konfigurierbare reguläre Ausdrücke Ticketnummern aus Titel/Beschreibung des zugehörigen Pull Requests extrahiert und per c-entron-API in die referenzierten Tickets einträgt.
Aussage: Das System soll bei jedem erfolgreichen Produktions-Build automatisiert per Webhook erkennen, welche Tickets betroffen sind, und deren Versionsfeld sowie QS-Weiterleitung automatisch aktualisieren.
Ergebnis: Kein manueller Schritt zur Ticket-Versions-Pflege nach einem Release erforderlich.
Belege:
- [PRIMÄR] docs/operations/build-server-and-automated-builds.md (Abschnitte "c-entron Tickets", "Azure DevOps setup") - Begründung: Vollständige technische Beschreibung inkl. konkreter Konfigurationswerte (Webhook-Filter, Regex-Beispiele).
Prüfidee: Test-Pull-Request mit Ticketreferenz mergen, Build auslösen und automatischen Ticket-Eintrag verifizieren.
Tracelinks: StRS-038; SwRS-026
Konsolidierung: nein
Status: belegt
```
## O. Wartung/Datenqualität (zu StRS-041)
```
ID: SyRS-036
Titel: Fehlertolerante, sequenzielle Ausführung wiederkehrender Wartungsaufgaben
Ebene: SyRS
Typ: Zuverlässigkeit (ISO 25010: Fehlertoleranz)
Akteur: System
Vorbedingung: Der stündliche Wartungszyklus des `DataQualityService` läuft.
Fakt: Jede der (mindestens neun) Wartungsaufgaben läuft in einer eigenen, kurzlebigen `BLSession`, ist einzeln in try-catch gekapselt (Fehler werden mit Aufgabennamen geloggt, brechen aber nicht den gesamten Zyklus ab) und prüft nach jeder Aufgabe auf Abbruchanforderung.
Aussage: Das System soll jede Wartungsaufgabe des Datenqualitätsdienstes unabhängig von den übrigen Aufgaben ausführen, sodass der Fehlschlag einer einzelnen Aufgabe die übrigen Aufgaben und den nächsten Zyklus nicht verhindert.
Ergebnis: Ein Defekt in einer einzelnen Wartungsroutine gefährdet nicht die übrigen Datenqualitätsmaßnahmen.
Belege:
- [PRIMÄR] docs/Background Service/DataQualityService.md (Abschnitte "Error Handling", "Session Management") - Begründung: Beschreibt Muster inkl. Codebeispiel für Session-Kapselung und Fehlerbehandlung.
Prüfidee: Eine Wartungsaufgabe gezielt zum Fehlschlagen bringen (z. B. durch inkonsistente Testdaten) und Fortsetzung der übrigen Aufgaben im selben Zyklus prüfen.
Tracelinks: StRS-041; SwRS-027
Konsolidierung: nein
Status: belegt
```
## P. API-Architektur, Telemetrie, Mandantenfähigkeit (zu StRS-042..044)
```
ID: SyRS-037
Titel: Namensraumbasierte API-Versionierung mit einheitlicher Routing-Konvention
Ebene: SyRS
Typ: Schnittstelle
Akteur: Client-Entwickler (intern/extern)
Vorbedingung: Ein neuer API-Endpunkt wird veröffentlicht oder eine bestehende Version weiterentwickelt.
Fakt: `RegisterCentronApiVersioning` leitet die API-Version aus dem Controller-Namensraum ab (`Controllers.v1.*`), Standardversion=1; `KebabCaseTransformer` wandelt PascalCase-Routensegmente automatisch in Kebab-Case um (z. B. `special-price-articles`).
Aussage: Das System soll die API-Version aus der Namensraumstruktur der Controller ableiten und Routensegmente einheitlich im Kebab-Case-Format bereitstellen.
Ergebnis: Konsistente, vorhersagbare URL-Struktur über alle API-Domänen hinweg; neue Versionen sind durch neue Namensräume statt manueller Attributpflege einführbar.
Belege:
- [PRIMÄR] src/webservice/Centron.Controllers/Configuration/RegisterCentronApiVersioning.cs:9-23 - Begründung: Konkrete Versionierungskonfiguration.
- [PRIMÄR] src/webservice/Centron.Controllers/Configuration/Routing/KebabCaseTransformer.cs:6-14 - Begründung: Konkrete Routing-Transformation.
Prüfidee: Neuen Controller im Namensraum `Controllers.v2.*` anlegen und automatische Zuordnung zur API-Version 2 ohne weitere Konfiguration prüfen.
Tracelinks: StRS-042; SwRS-028
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-038
Titel: Offene CORS-Richtlinie ohne Ursprungsbeschränkung
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Ein Browser sendet eine Cross-Origin-Anfrage an die API.
Fakt: `CentronHost.cs:266` konfiguriert CORS mit `AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()` — keine Einschränkung auf bekannte Ursprünge.
Aussage: Das System erlaubt aktuell Cross-Origin-Anfragen von jedem beliebigen Ursprung ohne Einschränkung.
Ergebnis: Beliebige Webanwendungen können clientseitig gegen die API browserbasierte Anfragen stellen; dies erleichtert Drittintegrationen, stellt aber zugleich eine erhöhte Angriffsfläche dar (siehe Prüfidee).
Belege:
- [PRIMÄR] src/webservice/Centron.Host/CentronHost.cs:168,266 (AddCors, UseCors mit AllowAnyOrigin/AllowAnyHeader/AllowAnyMethod) - Begründung: Direkter, unmissverständlicher Codebeleg.
Prüfidee: Cross-Origin-Testanfrage von einer nicht autorisierten Domain senden und erfolgreiche CORS-Freigabe (statt Ablehnung) verifizieren; im Rahmen der Validierung mit Sicherheitsverantwortlichen klären, ob dies beabsichtigt ist.
Tracelinks: StRS-042; SwRS-028
Konsolidierung: nein
Status: belegt; [HYPOTHESE] ob die offene CORS-Konfiguration bewusste Designentscheidung (z. B. für Nexoware-übergreifende Integrationen) oder ein zu härtender Zustand ist, ist im Code nicht dokumentiert — siehe Hypothesen.md H-07.
```
```
ID: SyRS-039
Titel: Bucket-basierte, batch-hochgeladene Nutzungstelemetrie
Ebene: SyRS
Typ: Daten
Akteur: System
Vorbedingung: Eine API-Methode, ein MCP-Tool oder ein KI-Assistenz-Werkzeug wird aufgerufen.
Fakt: `TelemetryBL` schreibt Nutzung in zeitlich gebündelte ("gebucketete") Datensätze über `MERGE ... WITH (HOLDLOCK)`-Upserts mit Deadlock-Retry-Logik (bis zu 5 Versuche, SQL-Fehlercodes 1205/2627/2601) und markiert hochgeladene Datensätze über einen separaten Upload-Client.
Aussage: Das System soll Nutzungsdaten lokal zeitlich gebündelt (Bucket) und nebenläufigkeitssicher speichern und anschließend gebündelt an einen zentralen Server hochladen.
Ergebnis: Nutzungsstatistiken gehen auch unter hoher gleichzeitiger Last nicht durch Datenbank-Deadlocks verloren.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Telemetry/TelemetryBL.cs:36-95,181-276 - Begründung: Konkrete MERGE-Logik und Retry-Mechanismus.
Prüfidee: Parallele API-Aufrufe (≥20 gleichzeitig) simulieren und korrekte, verlustfreie Bucket-Aggregation prüfen.
Tracelinks: StRS-043; SwRS-029
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-040
Titel: Zweistufiges Skalierungsmodell Mandant/Filiale in zentralen Geschäftsobjekten
Ebene: SyRS
Typ: Daten
Akteur: System
Vorbedingung: Ein Geschäftsobjekt (Auftrag, Bestand, Nummernkreis) wird angelegt.
Fakt: `Mandator`-Entität (rechtliche Einheit) existiert getrennt von `BranchI3D`/Filiale; zentrale Objekte wie `Order` tragen `BranchI3D`, Nummernkreise zusätzlich `MandatorI3D`.
Aussage: Das System soll Geschäftsobjekte konsistent auf zwei Ebenen — Mandant und Filiale — referenzierbar machen.
Ergebnis: Auswertungen und Berechtigungen können sowohl je Mandant als auch je Filiale erfolgen.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Administration/Company/Mandator.cs - Begründung: Eigenständige Mandanten-Entität.
- [PRIMÄR] src/backend/Centron.DAO/Mappings/Sales/CustomerAssets/Orders/OrderMaps.cs:74-75 - Begründung: Filial-Referenzierung auf zentralem Geschäftsobjekt.
Prüfidee: Siehe StRS-044.
Tracelinks: StRS-044; SwRS-030
Konsolidierung: nein
Status: belegt; [HYPOTHESE] durchgängige Filterung aller DAO-Abfragen nach Mandant/Filiale nicht vollständig verifiziert, siehe Hypothesen.md H-06.
```
## Q. Architekturmuster, Lokalisierung, Betriebsgrenzen (zu StRS-039, StRS-040, StRS-042, StRS-045)
```
ID: SyRS-041
Titel: Verpflichtender Dual-Implementierungsvertrag je Fachmodul (ILogic)
Ebene: SyRS
Typ: Wartbarkeit
Akteur: NEXOWARE-Entwickler
Vorbedingung: Ein neues Fachmodul im WPF-Client wird implementiert.
Fakt: Jedes Modul muss laut Entwicklerkonvention ein `ILogic`-Interface sowie eine `BL*Logic`- (Direktverbindung) und eine `WS*Logic`-Implementierung (Web-Service) bereitstellen; `ClassContainer` löst die passende Implementierung anhand des konfigurierten `CentronConnectionType` auf.
Aussage: Das System soll für jedes Fachmodul erzwingen (durch Konvention/Registrierung), dass sowohl eine Direktverbindungs- als auch eine Web-Service-Implementierung desselben Interfaces existiert.
Ergebnis: Kein Modul funktioniert nur in einer der beiden Betriebsarten.
Belege:
- [PRIMÄR] docs/getting-started/general-structure.md (Abschnitt "Dual Implementation Architecture", Punkt 2 "Implementation Guidelines") - Begründung: Explizite Verpflichtung ("MUST implement both") inkl. Namenskonvention.
Prüfidee: Neues Modul ohne eine der beiden Implementierungen registrieren und Fehlverhalten/Registrierungsfehler beim Start prüfen.
Tracelinks: StRS-039; SwRS-031
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-042
Titel: Kulturabhängige Ressourcenauflösung für UI- und Fehlertexte
Ebene: SyRS
Typ: Übertragbarkeit (Internationalisierbarkeit)
Akteur: System
Vorbedingung: Ein UI-Text oder eine Fehlermeldung wird angezeigt bzw. eine Web-Service-Antwort wird zurückgegeben.
Fakt: Jede Assembly mit UI-relevanten Texten führt Ressourcendateien `LocalizedStrings.resx` (Deutsch, Standard) und `LocalizedStrings.en.resx` (Englisch); die Sprache wird aus `CultureInfo.CurrentUICulture` bzw. dem HTTP-Header `Accept-Language` bestimmt.
Aussage: Das System soll UI- und Fehlertexte anhand der aktuellen Kultureinstellung des Clients bzw. eines übermittelten Sprachheaders aus vordefinierten Ressourcendateien auflösen.
Ergebnis: Neue Sprachen können durch Ergänzung weiterer Ressourcendateien unterstützt werden, ohne Code zu ändern.
Belege:
- [PRIMÄR] docs/guides/ui/localization.md (Abschnitte "Resource Files Structure", "Get localized strings through Web-Service call") - Begründung: Beschreibt Ressourcenstruktur und HTTP-Header-Mechanismus im Detail.
Prüfidee: Web-Service-Aufruf mit `Accept-Language: en-US` senden und englische statt deutsche Fehlermeldung prüfen.
Tracelinks: StRS-040; SwRS-032
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-043
Titel: Fehlende serverseitige Anfragebegrenzung bei gleichzeitig sehr langen Timeouts
Ebene: SyRS
Typ: Zuverlässigkeit / Sicherheit (ISO 25010: Verfügbarkeit, Missbrauchsresistenz)
Akteur: System
Vorbedingung: Der Web-Service verarbeitet eingehende HTTP-Anfragen.
Fakt: `CentronHost.cs` konfiguriert `MaxRequestBodySize = null` (unbegrenzt), `IdleConnection`/`RequestQueue`-Timeout von 30 Minuten (Windows/HttpSys) bzw. `KeepAliveTimeout` von 30 Minuten (Linux/Kestrel); im gesamten `src/webservice`- und `src/nexus`-Code wurde keine Rate-Limiting-Middleware (`AddRateLimiter`, `[EnableRateLimiting]`) gefunden.
Aussage: Das System soll die Anzahl bzw. Rate eingehender Anfragen pro Client begrenzen können, insbesondere in Kombination mit unbegrenzter Anfragegröße und sehr langen Verbindungs-Timeouts.
Ergebnis: Aktuell besteht kein serverseitiger Schutz gegen exzessive parallele oder wiederholte Anfragen eines einzelnen Clients auf API-Ebene.
Belege:
- [PRIMÄR] src/webservice/Centron.Host/CentronHost.cs:116-150 - Begründung: Konkrete, unbegrenzte Body-Size- und lange Timeout-Konfiguration.
- [KONTEXT] Repository-weite Suche nach `RateLimit`/`EnableRateLimiting` (Subagent-Recherche) - Begründung: Keine Treffer außerhalb von NuGet-Build-Caches; Abwesenheitsbeleg, kein abschließender Beweis für Gesamtsystem.
Prüfidee: Lasttest mit sehr vielen parallelen/wiederholten Anfragen eines einzelnen Clients durchführen und Verhalten (Drosselung ja/nein) beobachten.
Tracelinks: StRS-042; SwRS-033
Konsolidierung: nein
Status: belegt; [HYPOTHESE] ob Rate-Limiting auf einer vorgelagerten Infrastrukturebene (Reverse Proxy/API-Gateway) außerhalb des Repositories erfolgt, konnte nicht geprüft werden — siehe Hypothesen.md H-08.
```
```
ID: SyRS-044
Titel: Unzureichende kryptographische Stärke der Passwort-Hash-Funktion
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Ein Passwort wird bei Registrierung/Änderung gehasht oder bei Login verglichen.
Fakt: `BasicAuthenticator` verwendet `SHA1Decoder.GetDecodedSHA1String(...)` ohne erkennbares, individuelles Salt pro Benutzer; SHA-1 gilt kryptographisch als gebrochen/veraltet für Passwort-Hashing (branchenüblicher Konsens, nicht separat im Repository dokumentiert).
Aussage: Das System soll für die Passwort-Hash-Bildung ein für Passwörter geeignetes, salted und rechenintensives Verfahren (z. B. bcrypt/Argon2/PBKDF2) verwenden statt eines einzelnen, ungesalzenen SHA-1-Hashs.
Ergebnis: Ein Offline-Angriff auf entwendete Passwort-Hashes wird signifikant erschwert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs:46-48 - Begründung: Direkter Code-/Kommentarbeleg, siehe StRS-045.
Prüfidee: Siehe StRS-045.
Tracelinks: StRS-045; SwRS-034
Konsolidierung: nein
Status: belegt; Workaround
```
@@ -0,0 +1,205 @@
# Messprotokoll – V1 Baseline (Prompt-only) – Prompt-Version 01, Lauf 2 (ABGEBROCHEN)
> **Status: Lauf unvollständig.** Der Headless-Lauf brach nach 24:08 mit einem API-Fehler ab.
> Es liegen 4 von 7 geforderten Ergebnisdateien vor. Die Messwerte unten sind vollständig
> erfasst, beziehen sich aber auf einen **abgebrochenen** Lauf und sind nicht mit einem
> vollständigen Lauf vergleichbar.
## Lauf
- **Prompt-Datei:** `Versuche/Versuch_01/01_Prompt.md`
- **SHA-256 (Prompt):** `1B0DB06B8E0A5B92A5EFBDBEC5A0C554351FC928A16AEF34AAD9EAA0893C02FF`
(identisch zu Lauf 1 – der Prompt wurde nicht verändert)
- **Startzeit:** 2026-08-25T13:49:05.7854277+02:00
- **Endzeit:** 2026-08-25T14:20:29.6392629+02:00
- **Dauer gesamt:** 00:31:24 (Wanduhr) bzw. 00:24:08 (`duration_ms`) — API: 00:49:57 (`duration_api_ms`)
- Die API-Dauer übersteigt die Wanduhrzeit, weil 6 Subagenten nebenläufig liefen.
- **Root-Verzeichnis:** `c:\DEV\MasterArbeit\QuellCode\CentronERP`
- **Codebasis-Commit:** `79c1142f489a32ba6a4a4cb043fd7f8550a9f257` (dirty: nein)
- **Snapshot-Zustand:** bereinigt von KI-Konfigurationen: **ja** (Prüfung vor dem Lauf: 0 Treffer);
Remote entkoppelt: **ja** (`git remote` leer)
- **Prompt-Repo-Commit:** `0ec86aed8cb8781054c86cbe0dd9f5eb0f7e5f05`
## Werkzeugkonfiguration
- **Laufverzeichnis-ID:** `v2.0.0-8b0a`
- **Ablage:** `Iteration 1/claude-sonnet-5/builtin/high/`
- **Parallele Läufe:** nein
- **Skill-Version:** `2.0.0` (Shell-Zugriff + Denylist, Isolation über eingefrorenen Snapshot)
- **Claude-Code-Version:** 2.1.245
- **CLI-Pfad:** `C:\Users\ChristophSchwoerer\.vscode\extensions\anthropic.claude-code-2.1.245-win32-x64\resources\native-binary\claude.exe`
- **Effort:** `high` — **nicht zur Laufzeit gesetzt**, sondern aus der Sitzung geerbt und
nachtraeglich aus dem Session-Transkript rekonstruiert (100 Nachrichten, durchgaengig `high`).
`RawResult.json` enthaelt kein `effort`-Feld. Ab Skill-Version 3.4.0 wird der Wert per
`--effort` explizit gesetzt.
- **Modell:** `claude-sonnet-5` (explizit gesetzt); zusätzlich `claude-haiku-4-5-20251001`
für interne Hilfsaufrufe (4.176 Input-/26 Output-Tokens)
- **Permission-Mode:** `acceptEdits`
- **Toolfreigabe:**
- `--allowedTools "Bash" "PowerShell"`
- `--disallowedTools` mit 33 Einträgen: 22 × `Bash(...)` und 11 × `PowerShell(...)` für
schreibende Kommandos (`rm`, `rmdir`, `mv`, `cp`, `dd`, `truncate`, `chmod`, `chown`, `ln`,
`tee`, `sed -i`, `Remove-Item`, `Move-Item`, `Copy-Item`, `New-Item`, `Set-Content`,
`Add-Content`, `Clear-Content`, `Out-File`, `Set-ItemProperty`), Git-Mutationen
(`checkout`, `restore`, `clean`, `reset`, `add`, `commit`, `push`) und Build-Werkzeuge
(`dotnet`, `msbuild`, `nuget`, `npm install`)
- **Isolationsmechanismus:** eingefrorener Codebasis-Snapshot ohne KI-Konfigurationen,
zusätzlich `--safe-mode` und `--strict-mcp-config`
- **MCP-Server / Agentendateien:** keine – aus dem Snapshot entfernt, zusätzlich `--safe-mode`
- **Subagenten:** 6 × `general-purpose` (alle im Hintergrund gestartet, max. Tiefe 1,
6 abgeschlossen, 0 fehlgeschlagen)
- **Fast-Mode:** aus
## Verbrauch
### Hauptagent (`usage`)
| Messgröße | Wert |
|---|---|
| Input-Tokens | 10 |
| Output-Tokens | 81.610 (davon 13.370 Thinking-Tokens) |
| Cache-Write-Tokens | 86.138 (vollständig 1h-ephemeral) |
| Cache-Read-Tokens | 1.369.720 |
| Agent-Turns | 8 |
### Gesamtlauf inkl. Subagenten (`modelUsage`, abrechnungsrelevant)
| Messgröße | `claude-sonnet-5` | `claude-haiku-4-5-20251001` | Summe |
|---|---:|---:|---:|
| Input-Tokens | 364 | 4.176 | 4.540 |
| Output-Tokens | 226.587 | 26 | 226.613 |
| Cache-Write-Tokens | 805.842 | 0 | 805.842 |
| Cache-Read-Tokens | 15.618.130 | 0 | 15.618.130 |
| Tokens gesamt | 16.650.923 | 4.202 | **16.655.125** |
**Tokens gesamt: 16.655.125** (Summe aus Input, Output, Cache-Write und Cache-Read ueber alle Modelle; `total_cost_usd` steht weiterhin in `RawResult.json`)
## Ergebnis
- **Status:** **Fehler.** `is_error: true`, `terminal_reason: "api_error"`,
`stop_reason: "stop_sequence"`, `api_error_status: null`, Exit-Code 1.
Abschlusstext des Agenten wörtlich:
`API Error: The response stopped arriving. The response above may be incomplete.`
`Stderr.log` ist leer (0 Byte) – die CLI hat keine zusätzliche Diagnose ausgegeben.
Das Feld `subtype` steht auf `success` und widerspricht damit `is_error: true`;
maßgeblich sind `is_error` und `terminal_reason`.
- **Session-ID:** `46eee72a-c498-4572-a51e-b29ac39a180e`
(Transkript persistiert, 1.504.499 Byte – eine Fortsetzung per `--resume` ist technisch möglich)
- **Permission-Denials:** **0.** Die neue Werkzeugkonfiguration hat den Lauf zu keinem Zeitpunkt
eingeschränkt; der Abbruch hat keinen Bezug zu Berechtigungen.
- **Erzeugte Dateien:** 4 von 7
| Datei | Größe | Zeitstempel | Inhalt |
|---|---:|---|---|
| `Glossar.md` | 8.309 B | 13:53 | Domänenbegriffe |
| `Analysebericht.md` | 6.292 B | 13:55 | **als ENTWURF markiert**, nicht finalisiert |
| `StRS.md` | 74.069 B | 14:09 | 45 Anforderungen |
| `SyRS.md` | 58.925 B | 14:10 | 44 Anforderungen |
**Fehlend:** `SwRS.md`, `Traceability.md`, `Hypothesen.md`.
Der Abbruch erfolgte nach `SyRS.md` (14:10) und vor Fertigstellung der SwRS-Ebene.
- **Root unverändert:** ja. `git status --porcelain` nach dem Lauf ist leer, HEAD unverändert
`79c1142`. Der Lauf hat trotz voller Shell-Freigabe keine Datei der Codebasis angelegt,
geändert oder gelöscht.
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 45 | 50,6 % |
| SyRS | 44 | 49,4 % |
| SwRS | 0 | 0,0 % |
| **Gesamt** | **89** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| funktional | 33 | 37,1 % |
| Sicherheit | 22 | 24,7 % |
| Daten | 9 | 10,1 % |
| Schnittstelle | 9 | 10,1 % |
| nicht-funktional | 6 | 6,7 % |
| Zuverlässigkeit (ISO 25010: Fehlertoleranz) | 3 | 3,4 % |
| Übertragbarkeit | 2 | 2,2 % |
| nicht-funktional (Zuverlässigkeit, ISO 25010: Fehlertoleranz) | 1 | 1,1 % |
| Performance-Effizienz | 1 | 1,1 % |
| Wartbarkeit | 1 | 1,1 % |
| (2 weitere) | 2 | 2,2 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 149 |
| davon `PRIMÄR` | 125 (83,9 %) |
| davon `SEKUNDÄR` | 20 (13,4 %) |
| davon `KONTEXT` | 4 (2,7 %) |
| Belege je Anforderung (Median) | 1 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 89 (100,0 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 78 | 87,6 % |
| als `HYPOTHESE` gekennzeichnet | 11 | 12,4 % |
| als Workaround vermerkt | 5 | 5,6 % |
| Konsolidierungskandidaten | 8 | 9,0 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **erfüllt** (34 risikorelevante Anforderungen, alle gedeckt) |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 89 von 89 mit Tracelinks (100,0 %) |
## Anmerkungen/Auffälligkeiten
1. **Abbruchursache: API-Transportfehler, keine Konfigurationsfrage.** Die Antwort des Modells
hörte auf einzutreffen (`terminal_reason: "api_error"`). Weder die Toolfreigabe noch die
Denylist noch die Isolation waren beteiligt – `permission_denials` ist 0 und `Stderr.log` leer.
Es handelt sich um einen Infrastrukturfehler, der eine Wiederholung erfordert.
2. **Die neue Werkzeugkonfiguration hat funktioniert.** Gegenüber Lauf 1 (36 Denials) traten
**0 Denials** auf. Der Agent konnte Shell-gestützt inventarisieren und weist im
`Analysebericht.md` erstmals eine statische Auszählung aus: 22.346 Dateien unter `src/`,
davon 15.554 `.cs`, 1.233 `.xaml`, 491 `.razor`. In Lauf 1 fehlten solche Zahlen.
3. **Höhere Anforderungsdichte bis zum Abbruch.** Die beiden fertiggestellten Ebenen enthalten
mehr Anforderungen als im vollständigen Lauf 1: StRS 45 gegenüber 28, SyRS 44 gegenüber 28.
Auch die Dateigrößen liegen deutlich höher (StRS 74,1 KB gegenüber 45,7 KB; SyRS 58,9 KB
gegenüber 40,8 KB). Ein belastbarer Vergleich ist erst nach einem vollständigen Lauf möglich.
4. **Anderer Subagenten-Typ.** Lauf 2 nutzte 6 × `general-purpose` (im Hintergrund gestartet),
Lauf 1 dagegen 8 × `Explore` (Vordergrund). Der Prompt war identisch; die Wahl des
Subagenten-Typs ist damit keine Konstante der Versuchsanordnung und bei der Interpretation
von Laufzeit- und Kostenunterschieden zu berücksichtigen.
5. **Kosten trotz Abbruch nahezu identisch zum vollständigen Lauf 1:** 16.655.125 Tokens gegenüber
13.052.010 Tokens. Die Cache-Read-Tokens liegen mit 15,62 Mio. sogar über Lauf 1 (11,96 Mio.).
6. **Beobachtung des Agenten zum Snapshot:** Im `Analysebericht.md` vermerkt er, dass
`docs/getting-started/ai-codebase-navigation.md` noch auf die im Commit `79c1142` entfernten
Dateien (`.claude/`, `CLAUDE.md`, `.cursor/`) verweist. Der Verweis ist inhaltlich folgenlos,
dokumentiert aber, dass der Snapshot-Eingriff im Repository nachvollziehbare Spuren
hinterlässt.
7. **Werkzeugfehler im Skill entdeckt und behoben:** Die Sicherung `before.txt` wurde per
`git status --porcelain | Set-Content` erzeugt. Ist die Pipeline leer (sauberes Root),
schreibt `Set-Content` die Datei **nicht** und lässt den alten Inhalt stehen. Dadurch enthielt
`before.txt` noch die 92 Löschzeilen aus Lauf 1, und der Vorher/Nachher-Vergleich meldete
fälschlich eine Abweichung. Die Kontrolle wurde unabhängig per direktem
`git status --porcelain` (leer) und `git rev-parse HEAD` (`79c1142`) wiederholt – das Root ist
unverändert. Der Skill wurde auf eine leerwertsichere Variante umgestellt.
8. **Manuelle Eingriffe während des Laufs:** keine.
@@ -0,0 +1 @@
{"is_error":true,"duration_api_ms":2996847,"num_turns":8,"stop_reason":"stop_sequence","session_id":"46eee72a-c498-4572-a51e-b29ac39a180e","total_cost_usd":7.839986,"usage":{"input_tokens":10,"cache_creation_input_tokens":86138,"cache_read_input_tokens":1369720,"output_tokens":81610,"output_tokens_details":{"thinking_tokens":13370},"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":86138,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":3377,"cache_read_input_tokens":316766,"cache_creation_input_tokens":5403,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":5403},"type":"message"}],"speed":"standard"},"modelUsage":{"claude-haiku-4-5-20251001":{"inputTokens":4176,"outputTokens":26,"cacheReadInputTokens":0,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.004306,"contextWindow":200000,"maxOutputTokens":32000,"canonicalModel":"claude-haiku-4-5","provider":"firstParty"},"claude-sonnet-5":{"inputTokens":364,"outputTokens":226587,"cacheReadInputTokens":15618130,"cacheCreationInputTokens":805842,"webSearchRequests":0,"costUSD":7.83568,"contextWindow":1000000,"maxOutputTokens":64000,"canonicalModel":"claude-sonnet-5","provider":"firstParty"}},"permission_denials":[],"terminal_reason":"api_error","fast_mode_state":"off","fast_mode_disabled_reason":"extra_usage_disabled","origin":{"kind":"task-notification"},"subagent_stats":{"spawned":6,"requested":{"background":0,"foreground":0,"unset":6},"started_in_background":6,"max_depth":1,"spawned_by_subagents":0,"completed":6,"failed":0,"killed":{"parent":0,"user":0,"system":0},"refused":{"depth_limit":0,"concurrency_limit":0,"budget":0},"by_type":{"general-purpose":6}},"subtype":"success","api_error_status":null,"result":"API Error: The response stopped arriving. The response above may be incomplete.","type":"result","duration_ms":1447523,"uuid":"4a8486c6-43ee-4c77-9ba1-c2ff508e801d","queued_turn_count":0}
@@ -0,0 +1,66 @@
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 45 | 50,6 % |
| SyRS | 44 | 49,4 % |
| SwRS | 0 | 0,0 % |
| **Gesamt** | **89** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| funktional | 33 | 37,1 % |
| Sicherheit | 22 | 24,7 % |
| Daten | 9 | 10,1 % |
| Schnittstelle | 9 | 10,1 % |
| nicht-funktional | 6 | 6,7 % |
| Zuverlässigkeit (ISO 25010: Fehlertoleranz) | 3 | 3,4 % |
| Übertragbarkeit | 2 | 2,2 % |
| nicht-funktional (Zuverlässigkeit, ISO 25010: Fehlertoleranz) | 1 | 1,1 % |
| Performance-Effizienz | 1 | 1,1 % |
| Wartbarkeit | 1 | 1,1 % |
| (2 weitere) | 2 | 2,2 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 149 |
| davon `PRIMÄR` | 125 (83,9 %) |
| davon `SEKUNDÄR` | 20 (13,4 %) |
| davon `KONTEXT` | 4 (2,7 %) |
| Belege je Anforderung (Median) | 1 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 89 (100,0 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 78 | 87,6 % |
| als `HYPOTHESE` gekennzeichnet | 11 | 12,4 % |
| als Workaround vermerkt | 5 | 5,6 % |
| Konsolidierungskandidaten | 8 | 9,0 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **erfüllt** (34 risikorelevante Anforderungen, alle gedeckt) |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 89 von 89 mit Tracelinks (100,0 %) |
@@ -0,0 +1,62 @@
[
{
"id": "toolu_01LtGmoAa9pyj5dVZeE9K8tZ",
"werkzeug": "Agent",
"subagent_type": "general-purpose",
"description": "Survey security & rights model",
"run_in_background": null,
"model": null,
"prompt": "You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP. Do NOT write requirements text, do NOT modify any files — this is read-only research. Your output will be used by another process to write ISO/IEC/IEEE 29148 requirements, so it must be precise, evidence-cited (exact file path + class/method/line), and separate raw facts from any interpretation.\n\nFocus area: the authorization / user-rights model.\n\nInvestigate:\n1. src/backend/Centron.BL/Security — what classes/services exist, how are rights checked at runtime (e.g. a method like HasRight(...)), how are rights structured (hierarchical constants, per-branch/per-department restrictions)?\n2. Find the actual \"UserRightsConst\" class/file(s) (likely in Centron.Common or Centron.Entities or Centron.BL) — report its structure/organization (roughly how many rights, how organized into categories) and a handful of concrete representative examples with full constant names.\n3. Read CentronRights.md at the repo root fully (already partially known: documents Helpdesk, Kalender, Mitarbeiterauslastung rights) — note it's a partial doc; check if there are other *.md rights docs elsewhere.\n4. Find where authentication happens (login flow) — for the WPF client and for the webservice/Controllers (src/webservice/Centron.Controllers/Authorization). What auth mechanism is used (session token, JWT, Windows auth, 2FA)? Look at src/backend/Centron.BL/TwoFactorAuthenticator too.\n5. Find examples of \"restricting rights\" implemented in code (a right that filters a list to \"only own\" or \"only own branch\") — cite 2-3 concrete code locations showing the actual filter logic (e.g. LINQ where clause or SQL WHERE referencing a UserId/BranchId).\n6. Look for role/group concepts (is there a \"role\" entity distinct from individual rights, and how are rights assigned to users — directly, via groups, via roles)?\n7. Any password policy / account lockout / session timeout logic (PasswordManagementArea, PasswordManager folders)?\n\nFor each fact, report: exact file path, class/method name (with line number if feasible), a short verbatim or near-verbatim code/text excerpt, and classify it as PRIMÄR (enforced rule in code/DB constraint), SEKUNDÄR (UI label, config, mapping), or KONTEXT (comment/doc/commit). Flag anything you could not verify as UNCLEAR.\n\nReport back in a structured list, organized by the 7 numbered topics above. Be thorough — read actual file contents, don't guess from names. Target ~800-1500 words of dense factual findings.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01Uf2tDybxNBkfuhXMenQoks",
"werkzeug": "Agent",
"subagent_type": "general-purpose",
"description": "Survey billing/invoicing/accounting logic",
"run_in_background": null,
"model": null,
"prompt": "You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.\n\nFocus area: billing / invoicing / accounting (Fakturierung, Rechnung, Zahlung, Buchhaltung).\n\nInvestigate:\n1. src/backend/Centron.BL/Accounting and src/backend/Centron.BL/Finances — list the main classes/services and what they do (invoice creation, payment booking, dunning/Mahnwesen, VAT/tax handling, currency).\n2. src/backend/Centron.BL/VoucherManagement — what is a \"Voucher\" here (receipt/document type)? How does status progress (draft -> booked -> paid -> cancelled etc)? Find an actual status enum (e.g. VoucherStatus or similar) with its values, and find the code that enforces valid transitions (state machine / guard checks, e.g. \"cannot edit a booked invoice\").\n3. Look for entities in src/backend/Centron.Entities relevant to invoices/orders/receipts (e.g. Rechnung, Auftrag, Beleg, Voucher) — report field names relevant to money (amounts, tax rates, currency) and any DB-level constraints visible (e.g. Required attributes, foreign keys, check constraints) in the entity classes or any .edmx/mapping files.\n4. Find numbering-scheme logic for invoices (Rechnungsnummer / sequential numbering) — is there a class enforcing unique, gapless, or year-based numbering? This is often legally required (GoBD in Germany) — look for related comments.\n5. Find validation logic before finalizing/\"printing\"/\"booking\" an invoice (e.g. required fields, credit limit checks, permission checks referencing UserRightsConst for Accounting/Finances rights).\n6. Look at the recent commit \"feat: added rights check for editing invoice or delivery list date in the settings of timer billing\" (git log) — find the actual changed files/code to understand this specific business rule about editing invoice/delivery-list dates and the associated right.\n7. Any interfaces to external accounting/payment systems (e.g. src/apis/Centron.APIs.FinAPI, EDI folder, EbInterface API for e-invoicing) — what do they do at a high level?\n\nFor each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, and flag UNCLEAR items. Read actual file contents, don't guess from names. Target ~1000-1800 words of dense factual findings, organized by the 7 topics.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01L9ZUv5JiL5XWnNwcufSW3U",
"werkzeug": "Agent",
"subagent_type": "general-purpose",
"description": "Survey sales order lifecycle and CRM",
"run_in_background": null,
"model": null,
"prompt": "You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.\n\nFocus area: Sales / Order-to-cash process and Customer/CRM (BusinessPartner).\n\nInvestigate:\n1. src/backend/Centron.BL/Sales — list main subfolders/classes. Find the core \"Auftrag\"/order object's lifecycle: locate a status enum (e.g. OrderStatus/AuftragStatus) with its values, and the code enforcing valid status transitions (a state machine, switch statement, or guard method).\n2. src/backend/Centron.BL/BusinessPartner — what is a BusinessPartner (customer/supplier/both)? What are the main sub-entities (contacts, addresses, special prices \"Sonderpreise\" mentioned in README, credit limits)? Look for validation rules (e.g. required fields, duplicate detection).\n3. Find how quotations/offers (\"Angebot\") relate to orders — is there a conversion process (Angebot -> Auftrag)? Cite code.\n4. Find delivery/shipment logic (Lieferschein / delivery list) — connects to src/apis/Centron.Api.Gls, Centron.Api.Shipcloud shipping integrations. What triggers a shipment, what status does it set on the order?\n5. Look at recent commits related to \"C-Sign\" (WebOffer & Acceptance, ticket 168496 & 169060) — find the actual code for electronic signing of offers, understand what business process this represents (customer digitally accepts/signs a web-based offer). Cite files.\n6. Find the Helpdesk domain (src/backend/Centron.BL/... helpdesk related, also cross-check CentronRights.md content already known) — is Helpdesk part of Sales/CustomerArea? What's a \"Ticket\" status lifecycle?\n7. Any product/article catalog logic worth noting (ProductMatrix folder) — briefly, what does it do?\n\nFor each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_0192J98jM7xPFAej2ppjypYF",
"werkzeug": "Agent",
"subagent_type": "general-purpose",
"description": "Survey purchasing, warehousing, logistics",
"run_in_background": null,
"model": null,
"prompt": "You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.\n\nFocus area: Purchasing (Einkauf), Warehousing (Lager), Logistics.\n\nInvestigate:\n1. src/backend/Centron.BL/Buying (or Purchasing) — main classes: purchase order lifecycle, supplier (\"Lieferant\") handling, find a status enum if present with its values and transition logic.\n2. src/backend/Centron.BL/Warehousing — stock/inventory management: find how stock levels are tracked (a \"Bestand\" or \"Stock\" concept), find booking/movement logic (goods receipt \"Wareneingang\", goods issue), and any validation preventing negative stock or similar business rule enforced in code.\n3. src/backend/Centron.BL/Logistics — what does this cover distinctly from Warehousing (shipping, tours, routes)?\n4. src/backend/Centron.BL/TradePool — what is this (looks like a distinctive c-entron concept, maybe pooled/shared trading inventory between dealers)? Investigate and explain based on code/comments.\n5. Look at src/apis/* external data-access integrations: Centron.APIs.CopDataAccess, Centron.APIs.EgisDataAccess, Centron.APIs.ITscopeDataAccess, Centron.APIs.IcecatDataAccess — briefly identify what external systems/catalogs these integrate (likely wholesaler/distributor product data and pricing feeds for the IT/electronics trade). Cite a representative class/method per API.\n6. src/backend/Centron.BL/EDI — what EDI processes exist (electronic data interchange with suppliers, likely order/invoice exchange)? Cite concrete classes.\n7. Find any DB-level or code-level constraints tied to stock/quantity fields in src/backend/Centron.Entities (e.g. non-negative constraints, required warehouse references).\n\nFor each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01UjCMWRfusUhbaz2yYbj7Ak",
"werkzeug": "Agent",
"subagent_type": "general-purpose",
"description": "Survey webservice API, auth, and web client",
"run_in_background": null,
"model": null,
"prompt": "You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.\n\nFocus area: Web-facing system architecture — REST API layer, Blazor web client (Nexus), deployment/operations config. This feeds SyRS (system requirements: interfaces, performance, security, deployment).\n\nInvestigate:\n1. src/webservice/Centron.Controllers/Controllers/v1 and /Unversioned — list controller names (gives an inventory of the REST API surface: what business objects are exposed via API). Pick 3-4 representative controllers and note their endpoints (HTTP verbs, routes) and any [Authorize] attributes or custom auth filters.\n2. src/webservice/Centron.Controllers/Authorization — how is API authentication/authorization implemented (token validation, middleware, policies)?\n3. src/webservice/Centron.Controllers/Configuration and Configuration/Routing — API versioning strategy, any rate-limiting, CORS, or Swagger/OpenAPI config.\n4. src/nexus/CentronNexus — this is \"c-entron Nexus\" (web client per README, Blazor + DevExpress). Explore top-level structure, identify main feature areas (e.g. WebCart mentioned in README — self-service ordering for customers' customers via \"Sonderpreise\"). Cite the WebCart implementation location and how it authenticates (\"web-account\" concept).\n5. Deployment/ops artifacts: look in docker/, azure/, azure-blazor/, deployment/ directories at repo root — what do the Dockerfiles / docker-compose / azure pipeline yaml / deployment scripts reveal about: runtime environment, required services (SQL Server, etc.), logging/telemetry setup, environment configuration (appsettings), health checks. Cite specific files and relevant excerpts.\n6. src/backend/Centron.BL/Telemetry — what telemetry/logging is implemented (Application Insights? Custom)?\n7. Look for rate limits, timeouts, or performance-related configuration anywhere (appsettings.json values, HttpClient timeout configs, connection pool settings).\n\nFor each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01SvBc4WPXL7jW4VkYXJhjLH",
"werkzeug": "Agent",
"subagent_type": "general-purpose",
"description": "Survey entities data model and change tracking",
"run_in_background": null,
"model": null,
"prompt": "You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.\n\nFocus area: cross-cutting data model conventions and audit/change-tracking (feeds SwRS: data requirements, software-internal rules).\n\nInvestigate:\n1. src/backend/Centron.Entities/Entities — how many entity classes roughly (a count is fine), and what ORM/data-access pattern is used (look for base classes, attributes like [Table], [Key], [Required], [MaxLength], DataAnnotations or Fluent mapping). Pick 3-4 representative entity classes central to the business (e.g. something order/invoice/customer related) and report their key fields and any constraints.\n2. src/backend/Centron.DAO — what pattern is used for data access (Repository pattern? Direct ADO.NET? Stored procedures? Entity Framework?) Look for a representative DAO class and report its structure, including any raw SQL found (stored procedure calls, parameterized queries) — cite exact SQL text if found.\n3. src/backend/Centron.BL/ChangeTracking — what does the change-tracking/audit-trail mechanism do? Is every entity change logged? Who/what triggers it? Find the core class and report its mechanism (e.g. a generic audit table, before/after value diffing).\n4. Look for soft-delete vs hard-delete conventions (an \"IsDeleted\" or \"Aktiv\" flag pattern vs actual DELETE statements) — cite examples.\n5. Look for multi-tenancy or multi-company (\"Mandant\"/\"Filiale\"/Branch) scoping in entities or DAO queries — is there a company/branch ID that scopes almost all queries?\n6. Look for concurrency control (optimistic concurrency via a timestamp/rowversion column, or pessimistic locking) in entities or DAO.\n7. Database technology: search for connection string configuration or ADO.NET provider references to confirm MSSQL usage, and note the .NET target framework version(s) from a few .csproj files (TargetFramework element) to establish technical baseline.\n\nFor each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.",
"ergebnis_zeichen": 1093
}
]
@@ -0,0 +1,151 @@
# Subagenten-Aufrufe
Session `46eee72a-c498-4572-a51e-b29ac39a180e`, Transkript `46eee72a-c498-4572-a51e-b29ac39a180e.jsonl`.
`subagent_stats`: **6** Subagenten gesamt, davon **0** von Subagenten gestartet (max_depth 1). Direkt vom Hauptagenten erwartet: **6**. Im Transkript gefunden: **6**.
## 1. Survey security & rights model
- **Werkzeug:** `Agent` **Typ:** `general-purpose` **Hintergrund:** None
- **Prompt-Zeichen:** 2579 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\DEV\MasterArbeit\QuellCode\CentronERP. Do NOT write requirements text, do NOT modify any files — this is read-only research. Your output will be used by another process to write ISO/IEC/IEEE 29148 requirements, so it must be precise, evidence-cited (exact file path + class/method/line), and separate raw facts from any interpretation.
Focus area: the authorization / user-rights model.
Investigate:
1. src/backend/Centron.BL/Security — what classes/services exist, how are rights checked at runtime (e.g. a method like HasRight(...)), how are rights structured (hierarchical constants, per-branch/per-department restrictions)?
2. Find the actual "UserRightsConst" class/file(s) (likely in Centron.Common or Centron.Entities or Centron.BL) — report its structure/organization (roughly how many rights, how organized into categories) and a handful of concrete representative examples with full constant names.
3. Read CentronRights.md at the repo root fully (already partially known: documents Helpdesk, Kalender, Mitarbeiterauslastung rights) — note it's a partial doc; check if there are other *.md rights docs elsewhere.
4. Find where authentication happens (login flow) — for the WPF client and for the webservice/Controllers (src/webservice/Centron.Controllers/Authorization). What auth mechanism is used (session token, JWT, Windows auth, 2FA)? Look at src/backend/Centron.BL/TwoFactorAuthenticator too.
5. Find examples of "restricting rights" implemented in code (a right that filters a list to "only own" or "only own branch") — cite 2-3 concrete code locations showing the actual filter logic (e.g. LINQ where clause or SQL WHERE referencing a UserId/BranchId).
6. Look for role/group concepts (is there a "role" entity distinct from individual rights, and how are rights assigned to users — directly, via groups, via roles)?
7. Any password policy / account lockout / session timeout logic (PasswordManagementArea, PasswordManager folders)?
For each fact, report: exact file path, class/method name (with line number if feasible), a short verbatim or near-verbatim code/text excerpt, and classify it as PRIMÄR (enforced rule in code/DB constraint), SEKUNDÄR (UI label, config, mapping), or KONTEXT (comment/doc/commit). Flag anything you could not verify as UNCLEAR.
Report back in a structured list, organized by the 7 numbered topics above. Be thorough — read actual file contents, don't guess from names. Target ~800-1500 words of dense factual findings.
```
## 2. Survey billing/invoicing/accounting logic
- **Werkzeug:** `Agent` **Typ:** `general-purpose` **Hintergrund:** None
- **Prompt-Zeichen:** 2543 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\DEV\MasterArbeit\QuellCode\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.
Focus area: billing / invoicing / accounting (Fakturierung, Rechnung, Zahlung, Buchhaltung).
Investigate:
1. src/backend/Centron.BL/Accounting and src/backend/Centron.BL/Finances — list the main classes/services and what they do (invoice creation, payment booking, dunning/Mahnwesen, VAT/tax handling, currency).
2. src/backend/Centron.BL/VoucherManagement — what is a "Voucher" here (receipt/document type)? How does status progress (draft -> booked -> paid -> cancelled etc)? Find an actual status enum (e.g. VoucherStatus or similar) with its values, and find the code that enforces valid transitions (state machine / guard checks, e.g. "cannot edit a booked invoice").
3. Look for entities in src/backend/Centron.Entities relevant to invoices/orders/receipts (e.g. Rechnung, Auftrag, Beleg, Voucher) — report field names relevant to money (amounts, tax rates, currency) and any DB-level constraints visible (e.g. Required attributes, foreign keys, check constraints) in the entity classes or any .edmx/mapping files.
4. Find numbering-scheme logic for invoices (Rechnungsnummer / sequential numbering) — is there a class enforcing unique, gapless, or year-based numbering? This is often legally required (GoBD in Germany) — look for related comments.
5. Find validation logic before finalizing/"printing"/"booking" an invoice (e.g. required fields, credit limit checks, permission checks referencing UserRightsConst for Accounting/Finances rights).
6. Look at the recent commit "feat: added rights check for editing invoice or delivery list date in the settings of timer billing" (git log) — find the actual changed files/code to understand this specific business rule about editing invoice/delivery-list dates and the associated right.
7. Any interfaces to external accounting/payment systems (e.g. src/apis/Centron.APIs.FinAPI, EDI folder, EbInterface API for e-invoicing) — what do they do at a high level?
For each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, and flag UNCLEAR items. Read actual file contents, don't guess from names. Target ~1000-1800 words of dense factual findings, organized by the 7 topics.
```
## 3. Survey sales order lifecycle and CRM
- **Werkzeug:** `Agent` **Typ:** `general-purpose` **Hintergrund:** None
- **Prompt-Zeichen:** 2207 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\DEV\MasterArbeit\QuellCode\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.
Focus area: Sales / Order-to-cash process and Customer/CRM (BusinessPartner).
Investigate:
1. src/backend/Centron.BL/Sales — list main subfolders/classes. Find the core "Auftrag"/order object's lifecycle: locate a status enum (e.g. OrderStatus/AuftragStatus) with its values, and the code enforcing valid status transitions (a state machine, switch statement, or guard method).
2. src/backend/Centron.BL/BusinessPartner — what is a BusinessPartner (customer/supplier/both)? What are the main sub-entities (contacts, addresses, special prices "Sonderpreise" mentioned in README, credit limits)? Look for validation rules (e.g. required fields, duplicate detection).
3. Find how quotations/offers ("Angebot") relate to orders — is there a conversion process (Angebot -> Auftrag)? Cite code.
4. Find delivery/shipment logic (Lieferschein / delivery list) — connects to src/apis/Centron.Api.Gls, Centron.Api.Shipcloud shipping integrations. What triggers a shipment, what status does it set on the order?
5. Look at recent commits related to "C-Sign" (WebOffer & Acceptance, ticket 168496 & 169060) — find the actual code for electronic signing of offers, understand what business process this represents (customer digitally accepts/signs a web-based offer). Cite files.
6. Find the Helpdesk domain (src/backend/Centron.BL/... helpdesk related, also cross-check CentronRights.md content already known) — is Helpdesk part of Sales/CustomerArea? What's a "Ticket" status lifecycle?
7. Any product/article catalog logic worth noting (ProductMatrix folder) — briefly, what does it do?
For each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.
```
## 4. Survey purchasing, warehousing, logistics
- **Werkzeug:** `Agent` **Typ:** `general-purpose` **Hintergrund:** None
- **Prompt-Zeichen:** 2220 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\DEV\MasterArbeit\QuellCode\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.
Focus area: Purchasing (Einkauf), Warehousing (Lager), Logistics.
Investigate:
1. src/backend/Centron.BL/Buying (or Purchasing) — main classes: purchase order lifecycle, supplier ("Lieferant") handling, find a status enum if present with its values and transition logic.
2. src/backend/Centron.BL/Warehousing — stock/inventory management: find how stock levels are tracked (a "Bestand" or "Stock" concept), find booking/movement logic (goods receipt "Wareneingang", goods issue), and any validation preventing negative stock or similar business rule enforced in code.
3. src/backend/Centron.BL/Logistics — what does this cover distinctly from Warehousing (shipping, tours, routes)?
4. src/backend/Centron.BL/TradePool — what is this (looks like a distinctive c-entron concept, maybe pooled/shared trading inventory between dealers)? Investigate and explain based on code/comments.
5. Look at src/apis/* external data-access integrations: Centron.APIs.CopDataAccess, Centron.APIs.EgisDataAccess, Centron.APIs.ITscopeDataAccess, Centron.APIs.IcecatDataAccess — briefly identify what external systems/catalogs these integrate (likely wholesaler/distributor product data and pricing feeds for the IT/electronics trade). Cite a representative class/method per API.
6. src/backend/Centron.BL/EDI — what EDI processes exist (electronic data interchange with suppliers, likely order/invoice exchange)? Cite concrete classes.
7. Find any DB-level or code-level constraints tied to stock/quantity fields in src/backend/Centron.Entities (e.g. non-negative constraints, required warehouse references).
For each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.
```
## 5. Survey webservice API, auth, and web client
- **Werkzeug:** `Agent` **Typ:** `general-purpose` **Hintergrund:** None
- **Prompt-Zeichen:** 2482 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\DEV\MasterArbeit\QuellCode\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.
Focus area: Web-facing system architecture — REST API layer, Blazor web client (Nexus), deployment/operations config. This feeds SyRS (system requirements: interfaces, performance, security, deployment).
Investigate:
1. src/webservice/Centron.Controllers/Controllers/v1 and /Unversioned — list controller names (gives an inventory of the REST API surface: what business objects are exposed via API). Pick 3-4 representative controllers and note their endpoints (HTTP verbs, routes) and any [Authorize] attributes or custom auth filters.
2. src/webservice/Centron.Controllers/Authorization — how is API authentication/authorization implemented (token validation, middleware, policies)?
3. src/webservice/Centron.Controllers/Configuration and Configuration/Routing — API versioning strategy, any rate-limiting, CORS, or Swagger/OpenAPI config.
4. src/nexus/CentronNexus — this is "c-entron Nexus" (web client per README, Blazor + DevExpress). Explore top-level structure, identify main feature areas (e.g. WebCart mentioned in README — self-service ordering for customers' customers via "Sonderpreise"). Cite the WebCart implementation location and how it authenticates ("web-account" concept).
5. Deployment/ops artifacts: look in docker/, azure/, azure-blazor/, deployment/ directories at repo root — what do the Dockerfiles / docker-compose / azure pipeline yaml / deployment scripts reveal about: runtime environment, required services (SQL Server, etc.), logging/telemetry setup, environment configuration (appsettings), health checks. Cite specific files and relevant excerpts.
6. src/backend/Centron.BL/Telemetry — what telemetry/logging is implemented (Application Insights? Custom)?
7. Look for rate limits, timeouts, or performance-related configuration anywhere (appsettings.json values, HttpClient timeout configs, connection pool settings).
For each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.
```
## 6. Survey entities data model and change tracking
- **Werkzeug:** `Agent` **Typ:** `general-purpose` **Hintergrund:** None
- **Prompt-Zeichen:** 2448 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are gathering EVIDENCE for a Reverse Requirements Engineering effort on the c-entron ERP codebase at C:\DEV\MasterArbeit\QuellCode\CentronERP. Do NOT write requirements text, do NOT modify any files — read-only research only. Output must be precise, evidence-cited (exact file path + class/method, line numbers where feasible), separating raw fact from interpretation.
Focus area: cross-cutting data model conventions and audit/change-tracking (feeds SwRS: data requirements, software-internal rules).
Investigate:
1. src/backend/Centron.Entities/Entities — how many entity classes roughly (a count is fine), and what ORM/data-access pattern is used (look for base classes, attributes like [Table], [Key], [Required], [MaxLength], DataAnnotations or Fluent mapping). Pick 3-4 representative entity classes central to the business (e.g. something order/invoice/customer related) and report their key fields and any constraints.
2. src/backend/Centron.DAO — what pattern is used for data access (Repository pattern? Direct ADO.NET? Stored procedures? Entity Framework?) Look for a representative DAO class and report its structure, including any raw SQL found (stored procedure calls, parameterized queries) — cite exact SQL text if found.
3. src/backend/Centron.BL/ChangeTracking — what does the change-tracking/audit-trail mechanism do? Is every entity change logged? Who/what triggers it? Find the core class and report its mechanism (e.g. a generic audit table, before/after value diffing).
4. Look for soft-delete vs hard-delete conventions (an "IsDeleted" or "Aktiv" flag pattern vs actual DELETE statements) — cite examples.
5. Look for multi-tenancy or multi-company ("Mandant"/"Filiale"/Branch) scoping in entities or DAO queries — is there a company/branch ID that scopes almost all queries?
6. Look for concurrency control (optimistic concurrency via a timestamp/rowversion column, or pessimistic locking) in entities or DAO.
7. Database technology: search for connection string configuration or ADO.NET provider references to confirm MSSQL usage, and note the .NET target framework version(s) from a few .csproj files (TargetFramework element) to establish technical baseline.
For each fact: exact file path, class/method, short excerpt, classification PRIMÄR/SEKUNDÄR/KONTEXT, flag UNCLEAR items. Read actual file contents, don't guess from names alone. Target ~1200-1800 words of dense factual findings organized by the 7 topics.
```
@@ -0,0 +1,78 @@
# Analysebericht – Reverse Requirements Engineering c-entron ERP (V1 Baseline, Iteration 01)
## 1. Vorgehen dieser Iteration
Die Analyse erfolgte ausschließlich statisch (kein Ausführen der Anwendung) in mehreren Wellen:
1. **Strukturelle Größenermittlung**: Zählung von Quelldateien je Top-Level-Projekt (`src/backend`, `src/centron`, `src/webservice`, `src/nexus`, `src/apis`, `src/shared`) → 15.554 C#-Dateien, 1.233 XAML-Dateien insgesamt. Damit ist die Codebasis eine vollständige kommerzielle ERP-Suite; eine erschöpfende Zeile-für-Zeile-Analyse war innerhalb dieser Iteration nicht leistbar und wurde auch nicht angestrebt (siehe Vorgabe zur selbstständigen Tiefenpriorisierung).
2. **Parallele Struktur-Surveys** (7 nebenläufige Recherche-Agenten) über: Entitätsmodell (`Centron.Entities`), Geschäftslogik (`Centron.BL`), Datenzugriff (`Centron.DAO`), WPF-Oberfläche (`Centron.WPF.UI`), Webservice-API-Schicht, Nexus/externe APIs/Dokumentation, Deployment/Betrieb/Tests.
3. **Vertiefte Lektüre der internen Entwicklerdokumentation** (`docs/**`, 35 Markdown-Dateien vollständig gelesen) – diese erwies sich als ungewöhnlich reichhaltige, teils code-zeilen-genaue Quelle (insbesondere Architektur-, Beleg-, EDI-, ZUGFeRD- und Sicherheitsdokumente) und wurde als primäre Grundlage für SEKUNDÄR-/teils PRIMÄR-Belege verwendet, wo sie konkrete Codezitate mit Dateiname/Zeilennummer enthielt.
4. **Commit-Historie** (80 jüngste Commits) als KONTEXT-Quelle für aktive Weiterentwicklung, Modulnamen und Ticketreferenzen.
5. **Formalisierung** in StRS (30 Anforderungen), SyRS (38 Anforderungen), SwRS (38 Anforderungen) mit durchgängiger Belegpflicht, Fakt/Aussage-Trennung, Belegklassifikation und Traceability.
Es wurden **keine Codedateien der analysierten Codebasis verändert**; alle Ergebnisdateien liegen ausschließlich im vorgegebenen Ausgabeverzeichnis.
## 2. Modul-/Komponentenübersicht mit Analysetiefe
| Bereich | Analysetiefe | Begründung/Beleglage |
|---|---|---|
| Beleg-Engine (Angebot/Auftrag/Lieferschein/Rechnung/Gutschrift/Vertrag/Abholschein), `ReceiptBL`, `IReceiptSpecificLogic` | **Tief** | Ausführliche interne Architekturdokumentation mit Codezeilenreferenzen; ergänzt durch direkte Agentenrecherche in `Centron.BL`. Mehrheit der PRIMÄR-Belege dieser Iteration stammt aus diesem Bereich. |
| Vertrags-/Kontingent-/RMM-Abrechnung | **Tief** | Zwei dedizierte, detaillierte Architekturdokumente inkl. Fehlerbehandlungscode. |
| EDI-Lieferantenintegration | **Tief** | Zwei vollständige Architekturdokumente mit Enum-/Klassendefinitionen im Original. |
| ZUGFeRD/XRechnung-E-Invoicing | **Tief** | Feld-für-Feld-Mapping-Dokument mit exakten Codezeilenverweisen (höchster Detailgrad aller gesichteten Dokumente). |
| Rechte-/Rollenverwaltung (`UserRightsConst`, `HasUserRight`, `AppRightsBL`) | **Tief** | Verbindliche Entwicklerdokumentation plus quantifizierter Codebefund (318 Aufrufstellen in 93 Dateien) durch Agentenrecherche. |
| Authentifizierung (Ticket, OpenID Connect/Microsoft Entra, JWT, Access Tokens, RADIUS-2FA) | **Tief** | Vollständiges technisches Anleitungsdokument mit Sequenzdiagramm und Dateireferenzen; zusätzlich Testevidenz (`RadiusMessageAuthenticationTest.cs`). |
| Lizenzierung | **Mittel** | Ein gutes Konzeptdokument, aber keine direkte Codelektüre von `LicenseManager.cs`/`LicenseGuids.cs`. |
| Datenbank-Schema-/Migrationskonventionen | **Tief** | Drei dedizierte Konventionsdokumente plus Agentenrecherche mit konkreten DDL-Fundstellen (`CentronConfigurationDbRepository.cs`). |
| Webservice-/API-Schicht (Legacy-WCF-Bridge, moderne v1-Controller, SignalR) | **Tief** | Eigener Recherche-Agent mit konkreten Controller-/Endpunktlisten, Auth-Mechanismen, Middleware. |
| WPF-Oberfläche – Modulinventar | **Mittel (Breite), oberflächlich (Tiefe je Modul)** | Ein Recherche-Agent lieferte eine breite Modulübersicht (ca. 27 Top-Level-Module) mit Stichprobenklassen; einzelne Module (z. B. Production, PLM, QM, Survey, TelekomDive, PayersAndCostCenter, Massenupdates) wurden nur namentlich, nicht inhaltlich erfasst. |
| Helpdesk/Ticketing (WPF + Nexus ServiceBoard) | **Mittel** | Gute Dokumentation zur automatischen Ticketerstellung; Statusmodell (`HelpdeskState`) nur auf Strukturebene (datengetrieben statt Enum) erkannt, nicht inhaltlich mit konkreten Statuswerten befüllt. |
| RMA/Retourenmanagement | **Oberflächlich** | Nur UI-Modulexistenz und eine Commit-Referenz; keine BL-Klassen gelesen. |
| Mahnwesen (Dunning) / OPOS | **Tief für Rechteschutz, mittel für fachliche Berechnungslogik** | Konkrete Codezeilen für Rechteprüfung gefunden; genaue Mahnstufen-Fristenlogik nicht im Detail gelesen. |
| Nexus (Blazor-Webportal: ServiceBoard, WebCart/WebOffer, Outlook-Add-in) | **Tief (Architektur/Existenznachweis), mittel (Detailfunktionen)** | Playwright-Tests liefern konkrete, funktionsfähige Workflows (Freigabe, Ticketsichtbarkeit); vollständiger Seiten-für-Seite-Funktionsumfang nicht erhoben. |
| Exchange-/Outlook-Kalendersynchronisation | **Tief** | Außergewöhnlich detailliertes QS-Protokoll mit Root-Cause-Analysen und Codezitaten für acht konkrete Tickets. |
| Externe API-Integrationen (GLS, Shipcloud, ITscope, Icecat, COP, EGIS, FinAPI, docuFORM, EbInterface) | **Mittel** | Für jede Integration wurde die Existenz, der Zweck und typische Endpunkte identifiziert; Geschäftsregeln (z. B. Matching-Logik bei Banking) wurden nicht im Detail gelesen. |
| Deployment/Betrieb (Docker, Installer, CI/CD) | **Tief** | Eigener Recherche-Agent mit konkreten Konfigurationsdateien, inkl. sicherheitsrelevanter Negativbefunde (Klartext-Secrets, fehlendes Rate-Limiting, offenes CORS). |
| Tests (E2E, Unit, Playwright) | **Mittel** | Struktur- und Stichprobenanalyse (Dateizahlen, Testnamen); keine Testimplementierungen im Detail gelesen außer den zitierten QS-Protokoll-Beispielen. |
| Produktion (`Modules\Production`), PLM, QM, Survey, TelekomDive, PayersAndCostCenter, Massenupdates, OnlineBanking (UI-Detail), PasswordManager, DataQuality-Feinlogik über die dokumentierte Liste hinaus | **Nicht analysiert** | Nur Modulname aus Ordnerstruktur bekannt; kein Code oder Dokumentation gelesen. |
| DSGVO-Modul (konkreter Funktionsumfang) | **Nicht analysiert (nur Existenznachweis)** | Als `[HYPOTHESE]` in StRS-028 geführt. |
| "C-Sign" und "C-FLOW" (laut Commit-Historie existierende Features) | **Nicht analysiert** | Nur über Commit-Nachrichten bzw. ein Entitätsfeld (`CFlowStateI3D`) indirekt erschlossen; siehe `Hypothesen.md` H-04/H-05. |
## 3. Konsistenzcheck über das gesamte Anforderungs-Set
Durchgeführt am fertigen Anforderungsbestand (StRS-001…030, SyRS-001…038, SwRS-001…038, insgesamt 106 Anforderungen):
- **Doppelte/mehrfach vergebene IDs:** Keine gefunden. Alle IDs wurden per Grep über alle drei Dokumente extrahiert und sind lückenlos, sequenziell und eindeutig (StRS-001 bis StRS-030, SyRS-001 bis SyRS-038, SwRS-001 bis SwRS-038).
- **Anforderungen ohne Beleg:** Keine gefunden – jede der 106 Anforderungen führt mindestens einen klassifizierten Beleg (PRIMÄR/SEKUNDÄR/KONTEXT). Alle abrechnungs-, sicherheits- und rechterelevanten Anforderungen (StRS-013, StRS-014, StRS-016, StRS-017, SyRS-007 bis SyRS-012, SyRS-018, SyRS-028 bis SyRS-031, SwRS-012 bis SwRS-021, SwRS-034, SwRS-035) verfügen über mindestens einen PRIMÄR-Beleg; wo dies nicht eindeutig möglich war (SyRS-029 Ratenbegrenzung), wurde konsequent `[HYPOTHESE]` vergeben statt einer unbelegten Verallgemeinerung.
- **Tracelinks auf nicht existierende IDs:** Keine gefunden. Alle referenzierten StRS-/SyRS-/SwRS-IDs in den `Tracelinks`-Feldern existieren im jeweiligen Dokument.
- **Korrigierte Inkonsistenzen während des Checks:** Zwei Abweichungen wurden identifiziert und direkt behoben: (1) SwRS-008 (Steuersatzkette) verwies nur auf SwRS-007, ohne eine SyRS-/StRS-Rückverknüpfung – ergänzt um StRS-008/SyRS-013. (2) SwRS-034 (Modul-Rechteprüfung) referenzierte fälschlich „StRS-011" (Ticket-Vorlagen, thematisch unpassend) statt der beabsichtigten „SyRS-011" (Autorisierung) – korrigiert.
- **Traceability-Vollständigkeit:** Die konsolidierte Tabelle in `Traceability.md` deckt alle 30 StRS- und alle 38 SyRS-Anforderungen ab; für 12 SyRS-Anforderungen (v. a. querschnittliche/technische Themen wie Fehlerbehandlung, DB-Konventionen, Lokalisierung, Kodierung, Build-Pipeline) wurde keine 1:1-StRS-Zuordnung vorgenommen, da sie mehrere StRS-Anforderungen gemeinsam unterstützen, statt einer einzelnen zugeordnet zu sein (siehe Hinweis in `Traceability.md`).
## 4. Selbstbewertung
### Welche Module wurden vollständig, welche nur stichprobenhaft, welche gar nicht analysiert?
- **Vollständig (im Sinne von: alle verfügbaren internen Primärquellen gelesen, nicht im Sinne von Zeile-für-Zeile-Codeanalyse):** Beleg-/Vertrags-/EDI-/ZUGFeRD-/Rechte-/Auth-Architektur, da hierzu erschöpfende, code-referenzierte interne Dokumentation existierte.
- **Stichprobenhaft:** WPF-UI-Modulinventar (Breite statt Tiefe – ca. 27 Module identifiziert, aber nur 8–10 mit konkreten View/ViewModel-Pfaden belegt), Testlandschaft (Struktur- und Namensanalyse, keine Testcode-Lektüre in der Breite), externe API-Integrationen (Existenz und Zweck, keine Detailregeln).
- **Gar nicht analysiert:** Produktion, PLM, QM, Survey, TelekomDive, PayersAndCostCenter, Massenupdates, PasswordManager (Funktionsdetails), OnlineBanking-Abgleichlogik, DSGVO-Funktionsdetails, "C-Sign", "C-FLOW". Diese sind im Ordnerinventar (WPF-UI-Survey bzw. Commit-Historie) benannt, aber inhaltlich nicht erschlossen.
### An welchen Stellen war der Beleg dünn?
- **Hoher SEKUNDÄR-Anteil:** Externe API-Integrationen (StRS-022 bis StRS-025) stützen sich überwiegend auf Client-Klassenexistenz statt auf gelesene Geschäftsregeln.
- **KONTEXT-lastig:** RMA (StRS-009), C-Sign/C-FLOW (nur in `Hypothesen.md` geführt) stützen sich im Wesentlichen auf Commit-Nachrichten.
- **Explizit als HYPOTHESE geführt:** StRS-028 (DSGVO-Funktionsumfang), SwRS-004 (Synchronität von `ReceiptState` und Legacy-`Status`-Feld), SyRS-029 (Fehlen von Rate-Limiting als vollständige Sicherheitsaussage). Details und die jeweils fehlende Information zur Klärung stehen in `Hypothesen.md`.
### Welche Erkenntnisse legen einen Nachschlag in einer Folge-Iteration nahe?
1. **Statusmodell-Fragmentierung**: Es existieren mindestens drei parallele Statusmodellierungen im System – das moderne `ReceiptState`-Enum (Active/Completed/Canceled), das numerische Legacy-Feld `AufKopf.Status`/`FreigabeStatus`, und das generische `PersistedEntity.StateEnum` (Existing/Deleted) für Soft-Delete, ergänzt um das datengetriebene `HelpdeskState`. Eine Folgeiteration sollte gezielt die Synchronisationslogik zwischen diesen Modellen lesen (`SaveReceipt*Repository.SynchronizeReceiptData`), um SwRS-004 von HYPOTHESE auf „belegt" zu heben oder eine tatsächliche Inkonsistenz zu dokumentieren.
2. **Sicherheitsrelevante Lücken (SyRS-029, SyRS-030, SyRS-031)**: Fehlendes API-Rate-Limiting, offene CORS-Konfiguration und im Docker-Referenzsetup hartkodierte Zugangsdaten sollten mit dem Betriebsteam abgeglichen werden, da unklar ist, inwieweit vorgelagerte Infrastruktur (Reverse Proxy, WAF) dies kompensiert – für eine SaaS-Neuimplementierung sind dies jedoch in jedem Fall explizit zu adressierende Sicherheitsanforderungen.
3. **Zwei-Generationen-API (SyRS-004/SyRS-005)**: Legacy-WCF-Bridge und moderne v1-Controller decken teils identische fachliche Bereiche ab (z. B. Kunden, Aufträge) – eine Folgeiteration sollte den Überlappungsgrad systematisch kartieren, um im Zielsystem eine einzige API-Generation zu definieren.
4. **Nexus-Migrationsstand (H-08, H-09 in `Hypothesen.md`)**: Da Nexus (Blazor) erkennbar als Web-/SaaS-Nachfolger des WPF-Clients entsteht (eigene CI-Pipeline-Familie, Playwright-Suite, OIDC-Konfiguration), ist eine Feature-für-Feature-Gegenüberstellung WPF- vs. Nexus-Funktionsumfang der wichtigste nächste Analyseschritt für das erklärte Ziel „Basis für Web-/SaaS-Neuimplementierung".
5. **WPF-Modultiefe**: Die 27 identifizierten WPF-Module (u. a. Production, PLM, QM, Purchasing-Detailprozesse) sollten in weiteren Iterationen priorisiert nach Geschäftskritikalität (z. B. anhand Ticketvolumen/Commit-Häufigkeit) vertieft werden, da diese erste Iteration bewusst auf die beleg-/abrechnungs- und sicherheitsnahen Bereiche fokussiert hat.
6. **Rechtegranularität im Legacy-API-Pfad (H-06)**: Ob der WCF-Bridge-Pfad dieselbe granulare Rechteprüfung wie die modernen Controller durchsetzt, wurde nicht verifiziert und ist sicherheitsrelevant für die Konsolidierungsentscheidung (SyRS-004 Konsolidierungshinweis).
## 5. Bekannte Grenzen dieser Iteration
- Kein Zugriff auf produktive Datenbankinstanzen, Kundenumgebungen oder Laufzeitverhalten – alle Aussagen sind statisch aus Quellcode/Dokumentation/Tests abgeleitet.
- Interne Entwicklerdokumentation (`docs/**`) wurde als SEKUNDÄR/teilweise PRIMÄR (bei wörtlichem Codezitat) eingestuft, jedoch nicht in jedem Fall durch eigenständiges Lesen der referenzierten Originaldatei gegengeprüft; sie stellt in einzelnen Fällen möglicherweise leicht veralteten oder aspirationalen Stand dar (z. B. Best-Practice-Abschnitte in Feature-Dokumenten).
- Die Anzahl von 106 formalisierten Anforderungen bildet eine bewusste Priorisierung der beleg-, abrechnungs-, EDI-, e-invoicing-, sicherheits- und betriebsrelevanten Kernarchitektur ab, nicht eine erschöpfende Eins-zu-eins-Abdeckung aller 15.554 Quelldateien. Dies entspricht der in der Aufgabenstellung vorgesehenen selbstständigen Tiefenpriorisierung mit dokumentierter Offenlegung der Lücken (siehe Abschnitt 2 und `Hypothesen.md`).
@@ -0,0 +1,44 @@
# Glossar – c-entron ERP
Dieses Glossar sammelt Domänen- und Architekturbegriffe, die in StRS/SyRS/SwRS verwendet werden. Deutsche Fachbegriffe aus der Codebasis werden beibehalten (Originalsprache), technische Bezeichner (Klassen, Methoden, Tabellen) ebenfalls.
Legende Quellentyp: `CODE` = aus Quellcode/DB abgeleitet, `DOC` = aus interner Entwicklerdokumentation (`docs/`), `HYPOTHESE` = nicht abschließend verifiziert.
| Begriff | Erklärung | Quelle |
|---|---|---|
| **I3D** | Primärschlüssel-Konvention in praktisch allen Tabellen ("ID 3develop"), `int IDENTITY(1,1) NOT NULL`, clustered. Fremdschlüsselspalten enden auf das Suffix `I3D` (z. B. `KundenI3D`). | DOC: `docs/guides/database/database-conventions.md` |
| **Beleg (Receipt)** | Sammelbegriff für die Dokumenttypen Angebot (Offer), Auftrag (Order), Lieferschein (DeliveryList), Rechnung (Invoice), Vertrag (Contract), Gutschrift (CreditVoucher), Abholschein (PickupList); alle erben von `ReceiptBase`. | DOC: `docs/reference/receipts/receipts-backend-architecture.md` |
| **Kopf/Pos-Tabellenpaar** | Legacy-DB-Muster: `*Kopf`-Tabelle (Belegkopf, z. B. `AufKopf`) + `*Pos`-Tabelle (Positionen, z. B. `AufPos`); dazu je eine `*Versions`-Tabelle als 1:1-Kopie für Versionierung/Audit-Trail. | DOC/CODE: `docs/reference/receipts/receipts-backend-architecture.md` |
| **Mandator** | Eigene Firma/Betreiber-Stammdaten (z. B. Name, HRB, Steuer-ID, Bankverbindungen) im Gegensatz zu `Branch` (Filiale). | DOC: `docs/reference/zugferd-field-mapping.md` |
| **Branch (Filiale)** | Organisatorische Unterebene des Mandanten; kann eigene Adress-/Kontaktdaten für Rechnungsausgabe tragen; Zugriffssteuerung z. T. filialbezogen ("Branch Isolation"). | DOC: `docs/reference/receipts/receipts-backend-architecture.md` |
| **Sichrech / UserRightsConst** | Datenbanktabelle für Benutzerrechte (`Sichrech`) und zugehörige C#-Konstanten-Klasse `UserRightsConst.cs`; Grundlage der rollenbasierten Zugriffssteuerung ("Rechteverwaltung"). | DOC: `docs/guides/development/check-userrights.md`, `add-a-new-right.md` |
| **Sichbenu / AppUser** | Benutzertabelle (`Sichbenu`), u. a. mit Spalte `OpenIdConnectSubjectIdentifier` für Microsoft-Entra-Kopplung. | DOC: `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` |
| **Ticket (Session-Ticket)** | Von der Webservice-Anmeldung ausgestellter, zeitlich begrenzter (Standard: 30 Minuten) Sitzungs-Token, der bei nachfolgenden API-Aufrufen als Authentifizierungsnachweis dient. Nicht zu verwechseln mit einem Helpdesk-Ticket. | DOC: `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` |
| **Lizenz (License)** | GUID-basiertes Berechtigungsmerkmal für Produkte/Einzelfunktionen; besitzt optional `count`, `valid until date`, `valid until version`. Unterschieden werden `Applications` (login-berechtigt, in `ApplicationKind.cs`) und `Only Licenses` (Einzelfunktionen, in `LicenseGuids.cs`). | DOC: `docs/reference/security/licensing-system.md` |
| **ApplicationSettings / Stammdat** | Zwei parallele DB-Tabellen für Anwendungseinstellungen: `Stammdat` (Legacy, über `AppSettingsConst`) und `ApplicationSettings` (aktueller Standard, über `ApplicationSettingID`). Neue Einstellungen nur in `ApplicationSettings`. | DOC: `docs/guides/development/settings-management.md` |
| **Script / ScriptMethod** | C#-Klasse (`ScriptMethod<Nummer>.cs`), die Datenbank-Migrationsschritte (DDL/DML) über `GetSqlQueries()` bereitstellt; Ausführung versioniert über `ApplicationVersion`. De-facto-Migrationsmechanismus des Systems (kein separates Migrations-Tool). | DOC: `docs/guides/database/create-scripts.md`, `docs/reference/database/script-rules.md` |
| **Result / Response** | Internes Fehler-/Ergebnisobjekt (`Result`, `Result<T>`) für die BL-Schicht mit Status `Success/Error/Warning`; wird an der Webservice-Grenze in `Response`/`Response<T>` (Status `Success/Failed`) übersetzt. | DOC: `docs/reference/architecture/results-and-responses.md` |
| **DTO (Data Transfer Object)** | Datenklasse zum Transport von Entitätsdaten zwischen BL/Webservice und ViewModel; darf keine Logik enthalten; `[DataContract]`/`[DataMember]`-attributiert. | DOC: `docs/reference/architecture/dtos-and-entities.md` |
| **Entity** | NHibernate-verwaltete Domänenklasse mit 1:1-Bezug zu einer DB-Tabellenzeile; erbt `BaseEntity` (liefert `I3D`); darf keine Geschäftslogik enthalten. | DOC: `docs/reference/architecture/dtos-and-entities.md` |
| **ILogic / BLLogic / WSLogic** | Dreiteiliges Zugriffsmuster im WPF-Client: `ILogic`-Interface, `BL<Modul>Logic` (Direktzugriff via NHibernate/`BLSession`) und `WS<Modul>Logic` (Zugriff via Webservice); Modul deklariert unterstützte `CentronConnectionType`s (SqlServer, CentronWebServices). | DOC: `docs/getting-started/general-structure.md` |
| **ObjectKind / AnlageArt** | Numerischer Diskriminator zur Identifikation eines Beleg-/Objekttyps über mehrere Tabellen hinweg (z. B. `AnlageArt`: 1=Angebot, 2=Auftrag, 3=Lieferschein, 4=Rechnung, 5=Abholschein, 6=Gutschrift, 22=Vertrag), verwendet u. a. im zentralen Log (`AnlageLog`). | DOC: `docs/reference/receipts/receipts-backend-architecture.md` |
| **Kontingent (Contingent)** | Vertragskomponente für vorab vereinbarte Nutzungs-/Stundenkontingente (z. B. Servicezeiten), mit Verbrauchs- und Restwert-Tracking (`ContingentUsedHours`, `ContingentBalanceUsedAmount`, ...). | DOC: `docs/reference/receipts/contracts-backend.md` |
| **RMM (Remote Monitoring & Management)** | Externes Überwachungssystem (z. B. "Riverbird"), aus dem Nutzungsstatistiken für nutzungsbasierte Vertragsabrechnung (`ContractArticleReferenzes`) abgerufen werden. | DOC: `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` |
| **EDI (Electronic Data Interchange)** | Automatisierter Belegaustausch mit Lieferanten (Bestellantwort, Lieferschein, Rechnung) über lieferantenspezifische Formate (OpenTrans 2.1, ALSO, ALSO CH, Herweck, Komsa, Alltron) sowie ZUGFeRD für Rechnungen. | DOC: `docs/reference/edi/edi-architecture.md` |
| **ZUGFeRD / XRechnung** | Hybrides bzw. rein strukturiertes elektronisches Rechnungsformat (XML), das aus Belegdaten generiert wird; unterstützt mehrere Versionen (1.0 bis 2.1/XRechnung 3.0.1). | DOC: `docs/reference/zugferd-field-mapping.md` |
| **Aktionspreis (ActionPrice)** | Zeitlich befristeter Sonderpreis von Distributoren/Herstellern, dargestellt in der Preismatrix neben weiteren externen Preisquellen (ITscope, COP, NEOS, TradersGuide, EGIS). | DOC: `docs/reference/receipts/actionprice-system.md` |
| **Preismatrix (Price Matrix)** | UI-/Datenaggregation mehrerer paralleler Preisquellen (intern und extern) zu einem Artikel. | DOC: `docs/reference/receipts/actionprice-system.md` |
| **Nexus** | Blazor-Server-Webportal (`CentronNexus`) inkl. zugehörigem Outlook-Add-In; u. a. Terminplanungs-/Synchronisationskomponente (Exchange/Microsoft Graph ↔ c-entron). | DOC: `docs/getting-started/ai-codebase-navigation.md`, `docs/features/exchange-sync-bugprotokoll.md` |
| **CenSU (CentronSystemUser)** | Technisches Systemkonto, unter dem automatisierte Hintergrundprozesse (u. a. Exchange-Synchronisation) laufen. | DOC: `docs/features/exchange-sync-bugprotokoll.md` |
| **Soft Delete** | Lösch-Konvention: Datensätze werden nicht physisch gelöscht, sondern über `IsDeleted=1` (+ `DeletedByI3D`, `DeletedDate`) markiert. | DOC: `docs/guides/database/database-conventions.md` |
| **BackgroundService** | ASP.NET-Core-Hintergrunddienst-Muster (u. a. `DataQualityService`, `EdiDownloadService`, Exchange-Sync-Dienst) für periodische Wartungs-/Synchronisationsaufgaben. | DOC: `docs/Background Service/DataQualityService.md`, `docs/reference/edi/edi-import-rules.md` |
| **Helpdesk / Ticket (Vorgang)** | Ticketing-/Vorgangsmodul für Kundenanfragen, Service-/RMA-Fälle; unterstützt automatische Ticketerstellung aus Aufträgen über konfigurierbare Vorlagen. | DOC: `docs/features/automatic-helpdesk-creation-templates.md` |
| **RMA** | Retourenprozess (Return Merchandise Authorization) für Fremd-/Lieferantenretouren, laut Commit-Historie mehrfach angepasst (z. B. Mehrfach-RMA-Erfassung). | CODE (Commit-Historie) |
| **C-Sign** | Modul für digitale Signatur von Web-Angeboten/Auftragsbestätigungen ("WebOffer & Acceptance"), laut Commit-Historie. | CODE (Commit-Historie) — Tiefe der Analyse: gering, siehe Analysebericht |
| **C-FLOW** | Erwähntes Modul im Kontext von Belegpositionen/Vorlagen; Funktionsumfang nicht im Detail verifiziert. | `[HYPOTHESE]` — Beleg nur aus Commit-Nachricht |
| **MSP (Managed Service Provider)** | Vertrags-/Abrechnungsszenario mit Geräte-/Positionsverwaltung für Managed-Service-Kunden. | CODE (Commit-Historie), DOC: `docs/reference/receipts/contracts-backend.md` |
| **ObjectType / ObjectTypeDictionary** | Zentrales, technisches "Objektart"-Enum (`Entities/ObjectTypes/ObjectType.cs`), das über viele fachlich unabhängige Tabellen hinweg als generischer Polymorphie-Diskriminator verwendet wird (z. B. Offer=1, Order=2, Invoice=4, Helpdesk=10, Contract=22, Customer=5000012). Wird u. a. bei `CreatedFromObjectKind`-Feldern verwendet, um die Herkunft eines Datensatzes typübergreifend zu referenzieren. | CODE: `src/backend/Centron.Entities/Entities/ObjectTypes/ObjectType.cs` |
| **AssetKindEnum** | Enum zur Kennzeichnung der Belegart eines "CustomerAsset" (Offer=1, Order=2, DeliveryList=3, Invoice=4, PickupList=5, CreditVoucher=6, Contract=22, Helpdesk=23 u. a.); ähnlich zu `ObjectType`, aber eigenständig und mit eigener Namensauflösung (`AssetKindValues.GetAssetName`). | CODE: `src/backend/Centron.Entities/Entities/Sales/CustomerAssets/AssetKindEnum.cs` |
| **HelpdeskState** | Datengetriebener Ticket-Status: keine feste C#-Enumeration, sondern eine administrierbare Stammdaten-Tabelle/-Entität (`HelpdeskStateBase`: `Name`, `Number`, `Description`, `State`), die im laufenden Betrieb erweiterbar ist. | CODE: `src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskStateBase.cs` |
| **PersistedEntity.StateEnum** | Generisches, historisch älteres Soft-Delete-Kennzeichen (`Existing=0`, `Deleted=1`) auf Basisklassenebene (`PersistedEntity`), parallel zum neueren, spaltenbasierten `IsDeleted`/`DeletedByI3D`/`DeletedDate`-Muster (siehe `database-conventions.md`). | CODE: `src/backend/Centron.Entities/PersistedEntity.cs` |
| **ChangeLog** | Generische, feldbezogene Änderungshistorie (`ObjectI3D`, `ObjectKind`, `Property`, `OldValue`, `NewValue`, `Date`, `AppUser`), die unabhängig vom `AnlageLog`-Belegprotokoll als zusätzlicher, entitätsübergreifender Audit-Mechanismus existiert. | CODE: `src/backend/Centron.Entities/Entities/ChangeTracking/ChangeLog.cs` |
@@ -0,0 +1,50 @@
# Hypothesen – Sammlung offener, nicht abschließend belegter Aussagen
Diese Datei sammelt alle mit `[HYPOTHESE]` bzw. Status `HYPOTHESE` gekennzeichneten Aussagen aus StRS/SyRS/SwRS, jeweils mit der konkret fehlenden Information zur Bestätigung. Zusätzlich sind Stellen aufgeführt, an denen die Analyse aus Zeit-/Umfangsgründen nicht vertieft wurde und die für eine Folgeiteration priorisiert werden sollten.
## Formal als HYPOTHESE gekennzeichnete Anforderungen
### H-01 (StRS-028 – Datenschutz-Compliance/DSGVO)
**Aussage:** Das System soll Funktionen zur Unterstützung datenschutzrechtlicher Anforderungen (Auskunft, Löschung, Anonymisierung) bereitstellen.
**Warum Hypothese:** Es wurde lediglich die Existenz eines UI-Moduls `Modules\Administration\DSGVO\CentronDataSecurityView.xaml` festgestellt (SEKUNDÄR-Beleg). Der konkrete Funktionsumfang (welche DSGVO-Artikel/-Prozesse tatsächlich unterstützt werden – Art. 15 Auskunft, Art. 17 Löschung, Datenexport, Verarbeitungsverzeichnis o. Ä.) wurde nicht durch Lesen der zugehörigen ViewModel-/BL-Klassen verifiziert.
**Fehlende Information zur Bestätigung:** Quelltext von `CentronDataSecurityViewModel` und zugehöriger BL-Klasse(n); ggf. Interview mit Produktverantwortlichem/Datenschutzbeauftragtem.
### H-02 (SwRS-004 – ReceiptState vs. Legacy-Status-Synchronisation)
**Aussage:** Unklar, ob `ReceiptState`-Enum (moderne Entity-Ebene) und das numerische `Status`/`FreigabeStatus`-Feld der Legacy-Spiegeltabelle (`AufKopf` u. a.) bei jeder Statusänderung synchron gehalten werden.
**Warum Hypothese:** Beide Felder wurden durch unterschiedliche Recherche-Agenten in unterschiedlichen Schichten (Interfaces/BL vs. Entities/DbEntities) identifiziert; eine gemeinsame Synchronisationsmethode wurde nicht gelesen.
**Fehlende Information zur Bestätigung:** Quelltext der `SaveReceipt*Repository.SynchronizeReceiptData()`-Methoden auf expliziten Statusabgleich zwischen `ReceiptState` und `AufKopf.Status`/`FreigabeStatus` prüfen.
### H-03 (SyRS-029 – Fehlende Ratenbegrenzung der Webservice-API)
**Aussage:** Das System besitzt keinen Schutz vor übermäßig häufigen/übergroßen Anfragen auf API-Ebene.
**Warum Hypothese:** Es handelt sich um einen Negativbefund (keine Rate-Limiting-Middleware im Code gefunden). Es ist nicht auszuschließen, dass eine Ratenbegrenzung außerhalb des Repositories (Reverse Proxy, API-Gateway, Firewall/WAF beim Kunden oder in der c-entron-Hosting-Infrastruktur) umgesetzt ist und daher im Quellcode nicht sichtbar wäre.
**Fehlende Information zur Bestätigung:** Betriebs-/Infrastrukturdokumentation der produktiven c-entron-SaaS-/Hosting-Umgebung (außerhalb dieses Repositories) einsehen; Interview mit Betriebsverantwortlichen.
## Weitere, nicht formal als eigene Anforderung geführte offene Punkte
### H-04 (Umfang von "C-Sign")
Die jüngste Commit-Historie (`89ccfd650d Ticket 168496 & 169060 - C-Sign (WebOffer & Acceptance)`) deutet auf ein digitales Signaturfeature für Web-Angebote hin; in der BL-Schicht wurde nur eine thematisch verwandte Klasse `Security\PdfSigningBL.cs` (PDF-Signierung) identifiziert, ohne dass eine explizite "C-Sign"-Komponente gelesen wurde. Es ist unklar, ob `PdfSigningBL` und "C-Sign" identisch, verwandt oder unabhängig sind.
**Fehlende Information:** Gezielte Codesuche nach "CSign"/"C-Sign"/"WebOffer.*Accept" in `Centron.BL`, `Centron.Controllers` und `CentronNexus` (WebOffer-Modul), die in dieser Iteration nicht durchgeführt wurde.
### H-05 (Umfang von "C-FLOW")
Der Commit `8e1ea85069 Ticket 167957 - Belegposition to receipt vorlagen in C-FLOW (#56)` erwähnt ein Modul/Feature "C-FLOW"; auf Entitätsebene wurde ein Feld `CFlowStateI3D` auf der `Helpdesk`-Entität gefunden (Hinweis auf einen workflow-artigen Zustandsautomaten für Tickets), aber keine dedizierte C-FLOW-Dokumentation oder -Klasse gelesen.
**Fehlende Information:** Gezielte Codesuche nach "CFlow"/"C-Flow" in `Centron.BL`/`Centron.Entities`, um Funktionsumfang und Beziehung zum Helpdesk-Statusmodell zu klären.
### H-06 (Vollständigkeit der Autorisierungsprüfung bei Legacy-WCF-Bridge)
`AuthenticateInterceptor`/`LoggedInUserInterceptor` (Castle-DynamicProxy-basiert) sichern den Legacy-REST-Pfad (`ICentronRestService`) ab; es wurde nicht verifiziert, ob dieselbe Rechtegranularität (`AuthorizeUserRightAttribute`) wie bei den modernen v1-Controllern durchgesetzt wird oder ob der Legacy-Pfad lediglich Authentifizierung (angemeldet ja/nein), nicht aber granulare Autorisierung prüft.
**Fehlende Information:** Quelltext von `AuthenticateInterceptor.cs` und Stichproben von `ICentronRestService`-Methoden auf rechte-spezifische Prüfungen (`HasUserRight`) innerhalb der Methodenimplementierung statt nur auf Attributebene.
### H-07 (Reichweite der finAPI-/Online-Banking-Integration)
Es wurde nicht verifiziert, ob der Abgleich importierter Banktransaktionen mit offenen Rechnungen automatisch (Matching-Algorithmus) oder rein manuell erfolgt.
**Fehlende Information:** Quelltext des `Modules\OnlineBanking`-Bereichs bzw. zugehöriger BL-Klassen (`AccountTransactions`) auf automatische Zuordnungslogik prüfen.
### H-08 (Tatsächlicher Migrationsstand Desktop → Nexus)
Aus CI/CD-Artefakten (separate `azure-blazor`-Pipeline-Familie, eigene Playwright-Suite, OIDC-/Branding-Konfiguration) lässt sich ableiten, dass Nexus eine im Aufbau befindliche Web-/SaaS-Alternative zum WPF-Client ist. Der genaue funktionale Deckungsgrad (welcher Anteil der WPF-Module bereits in Nexus verfügbar ist) wurde nicht systematisch Modul-für-Modul verglichen.
**Fehlende Information:** Vollständige Feature-Gegenüberstellung WPF-Modulliste (`ModuleRegistration.cs`) vs. Nexus-Seitenstruktur (`CentronNexus/**/*.razor`), was den Rahmen dieser Iteration überschritten hätte.
### H-09 (Multi-Tenant-Fähigkeit von Nexus)
`appsettings`-Konfiguration von Nexus (Docker-Referenzkonfiguration) enthält Hinweise auf einen OIDC-Block sowie mandantenspezifische Branding-Einstellungen; ob Nexus bereits echte Mandantentrennung (mehrere Kunden auf gemeinsamer Instanz) unterstützt oder weiterhin ein 1-Instanz-pro-Kunde-Modell voraussetzt, wurde nicht verifiziert.
**Fehlende Information:** Quelltext-/Konfigurationsanalyse zu mandantenübergreifender Datenisolation in `CentronNexus.Host` (z. B. Datenbankverbindungsauswahl pro Tenant).
## Empfehlung für Folgeiterationen
Die oben genannten Punkte (insbesondere H-04, H-05, H-06, H-08, H-09) sollten in einer Folgeiteration mit gezielter Tiefenanalyse (nicht nur Doku-/Struktur-Survey, sondern Quellcodelesen der konkret benannten Klassen) geklärt werden, da sie sowohl für die Vollständigkeit der StRS (Funktionsumfang) als auch für sicherheitsrelevante SyRS-Aussagen (Autorisierung im Legacy-Pfad) relevant sind.
@@ -0,0 +1,575 @@
# Stakeholder Requirements Specification (StRS) – c-entron ERP
Diese StRS beschreibt die fachliche Sicht (Akteure, Geschäftsziele, Kernfähigkeiten) des c-entron-ERP-Systems, wie sie aus der Codebasis (Modulstruktur, Webservice-Oberfläche, Dokumentation, Commit-Historie) rekonstruierbar ist. Sie bildet die Grundlage für SyRS/SwRS und für eine Web-/SaaS-Neuimplementierung.
Akteursübersicht (aus Rechte-/Modulstruktur abgeleitet, `[HYPOTHESE]` sofern nicht explizit benannt):
- **Innendienst-/Vertriebsmitarbeiter** (Beleg-, Kunden-, Artikelbearbeitung)
- **Lager-/Logistikmitarbeiter** (Warenwirtschaft, Kommissionierung, Inventur)
- **Einkäufer** (Bestellwesen, Lieferantenmanagement, EDI)
- **Service-/Support-Mitarbeiter** (Helpdesk, RMA, Zeiterfassung)
- **Buchhaltung** (Rechnungswesen, Mahnwesen, OPOS, Banking)
- **Administrator** (Rechte-, Mandanten-, Lizenz-, Systemverwaltung)
- **Endkunde / Webaccount-Nutzer** (Kundenportal, Web-Shop, Ticketeinsicht)
- **Externe Systeme** (Lieferanten-EDI-Server, Distributoren-APIs, Versanddienstleister, Bankdienste, Microsoft 365/Entra ID, RMM-System)
---
```
ID: StRS-001
Titel: Durchgängige Belegkette Angebot–Auftrag–Lieferschein–Rechnung–Gutschrift
Ebene: StRS
Typ: funktional
Akteur: Innendienst-/Vertriebsmitarbeiter
Vorbedingung: Kunde und Artikel sind im System erfasst.
Fakt: Alle Belegtypen (Angebot, Auftrag, Lieferschein, Rechnung, Gutschrift, Vertrag, Abholschein) erben von einer gemeinsamen Basisklasse `ReceiptBase` und werden über ein gemeinsames Backend (`ReceiptBL`) verwaltet; jeder Belegtyp definiert erlaubte Vorgänger-/Nachfolgebelege.
Aussage: Das System soll es Vertriebsmitarbeitern ermöglichen, einen Verkaufsvorgang durchgängig von Angebot über Auftrag und Lieferschein bis zur Rechnung (und ggf. Gutschrift) fortzuführen, ohne Daten erneut erfassen zu müssen.
Ergebnis: Ein Folgebeleg wird mit übernommenen Kopf- und Positionsdaten aus dem Ursprungsbeleg erzeugt.
Belege:
- [SEKUNDÄR] `docs/reference/receipts/receipts-backend-architecture.md` - Begründung: Beschreibt die gemeinsame Belegarchitektur und Tabellen/Views je Belegtyp.
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/IReceiptSpecificLogic.cs`, `SpecificLogics.cs` - Begründung: Definiert und prüft programmatisch, welche Belegtyp-Übergänge zulässig sind (`CanBeForwardedFrom`/`CanBeForwardedInto`).
Prüfidee: End-to-End-Test: Angebot anlegen → in Auftrag wandeln → in Rechnung wandeln; prüfen, dass Kundendaten, Positionen und Preise unverändert übernommen werden.
Tracelinks: SyRS-013, SyRS-014, SwRS-001, SwRS-002, SwRS-003, SwRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-002
Titel: Zentrale Kunden-/Interessentenverwaltung (CRM)
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter
Vorbedingung: -
Fakt: Eigenständiges CRM-Modul (`Modules\Finances\Crm`) mit Kundenstamm, Kontaktpersonen, Adressen sowie Finanz-/Beleghistorie je Kunde.
Aussage: Das System soll Kunden- und Interessentendaten inkl. Kontaktpersonen, Adressen und zugehöriger Belege zentral verwalten und im Vertriebsprozess referenzierbar machen.
Ergebnis: Kundendaten sind einmalig gepflegt und in allen Belegen/Modulen konsistent referenziert (`CustomerI3D`/`KundenI3D`).
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Finances/Crm/CrmMainView.xaml`, `CrmMainViewModel.cs` - Begründung: Eigenständige CRM-Hauptmaske mit Finanz-Tab.
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/v1/Accounts/AccountsController.cs`, `v1/Customers/CustomersController.cs` - Begründung: Dedizierte REST-Endpunkte für Kunden-/Account-Daten.
Prüfidee: Neuen Kunden anlegen, Adresse/Kontaktperson hinzufügen, anschließend in einem Angebot referenzieren und Übernahme der Stammdaten prüfen.
Tracelinks: SyRS-001, SyRS-003
Konsolidierung: Kandidat: CRM-Kundendaten (`Kunden`-Tabelle) und Webaccount-Kundenportalzugang (StRS-018) könnten im Zielsystem als ein Identitätsmodell konsolidiert werden.
Status: belegt
```
```
ID: StRS-003
Titel: Wiederkehrende Vertragsabrechnung mit Kontingenten
Ebene: StRS
Typ: funktional
Akteur: Vertrieb / Buchhaltung
Vorbedingung: Ein Vertrag (Belegtyp `ReceiptContract`) ist mit Kunde, Positionen und Abrechnungsintervall angelegt.
Fakt: `ReceiptContract` besitzt Felder für Abrechnungsintervall (`BillingIntervalKind`, `BillingIntervalDuration`), automatisierte Abrechnung (`AutomatedBilling`) sowie Kontingentverwaltung (`ContingentUsedHours`, `ContingentLimitValue`, `ContingentBalanceUsedAmount`).
Aussage: Das System soll Verträge mit wiederkehrenden Abrechnungsintervallen (täglich/monatlich/quartalsweise/jährlich) abbilden und automatisiert Rechnungen daraus erzeugen können, inkl. Verrechnung vereinbarter Nutzungskontingente.
Ergebnis: Zum fälligen Abrechnungstermin wird automatisiert eine Rechnung mit den vertraglich vereinbarten und kontingentbereinigten Positionen erzeugt.
Belege:
- [SEKUNDÄR] `docs/reference/receipts/contracts-backend.md` - Begründung: Beschreibt Vertragsentität, Abrechnungsintervall- und Kontingentfelder im Detail mit Codereferenzen.
- [PRIMÄR] `src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs` - Begründung: Enthält die automatisierte Rechnungserzeugung aus Verträgen (laut Dokumentation und Modulübersicht der BL-Schicht).
Prüfidee: Vertrag mit monatlichem Abrechnungsintervall anlegen, automatisierte Abrechnung aktivieren, Fälligkeitsdatum erreichen lassen (Testlauf) und Rechnungserzeugung prüfen.
Tracelinks: SyRS-013, SwRS-001, SwRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-004
Titel: Nutzungsbasierte Abrechnung über externe RMM-Systeme
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung / MSP-Dienstleister-Kunde
Vorbedingung: Vertrag ist für RMM-Abrechnung konfiguriert (`WhetherRMM` = true) und Artikelreferenzen sind hinterlegt.
Fakt: Bei aktivierter RMM-Abrechnung ruft `RiverConnectionBL` Nutzungsdaten aus dem externen RMM-System ("Riverbird") für den Abrechnungszeitraum ab und fügt daraus berechnete Positionen automatisiert in die Rechnung ein.
Aussage: Das System soll für Managed-Service-Verträge automatisiert Nutzungsdaten aus einem externen Monitoring-System (RMM) abrufen und in die Rechnungsstellung integrieren.
Ergebnis: Rechnungspositionen für RMM-Artikel enthalten die tatsächlich im Abrechnungszeitraum gemessene Nutzung; ist der RMM-Dienst nicht erreichbar, wird die Rechnungserstellung abgebrochen statt mit unvollständigen Daten fortzufahren.
Belege:
- [PRIMÄR] `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` (zitiert `RiverConnectionBL.GetContractBillingAmounts`, `RMMServiceUnavailableException`) - Begründung: Dokumentiert konkrete Abbruchlogik bei Nichterreichbarkeit des externen Dienstes, ein durchgesetztes Verhalten.
Prüfidee: RMM-Dienst simuliert nicht erreichbar → Rechnungserstellung für RMM-Vertrag muss mit Fehlermeldung abbrechen, keine Teil-Rechnung darf erzeugt werden.
Tracelinks: SyRS-013, SwRS-009, SwRS-010, SwRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-005
Titel: Einkauf und Lieferantenbestellwesen
Ebene: StRS
Typ: funktional
Akteur: Einkäufer
Vorbedingung: Artikel und Lieferant sind erfasst.
Fakt: Eigenständiges Modul `Modules\Purchasing` mit `OrderSuggestionList` (Bestellvorschlagsliste) sowie Belegtyp `SupplierOrder` mit spiegelbildlicher Belegkette (`SupplierOrderSpecificLogic` → `SupplierDeliveryList` → `SupplierInvoice` → `SupplierCreditVoucher`).
Aussage: Das System soll Einkäufern die Erstellung von Bestellvorschlägen und Lieferantenbestellungen sowie deren Verfolgung über Lieferschein und Lieferantenrechnung ermöglichen.
Ergebnis: Aus einem Bestellvorschlag wird eine Lieferantenbestellung erzeugt, deren Wareneingang und Rechnungsprüfung im System nachverfolgt werden können.
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Purchasing/OrderSuggestionList` - Begründung: Eigenständige UI für Bestellvorschläge.
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs` - Begründung: Definiert programmatisch die zulässige Belegfolge für Lieferantenbestellungen.
Prüfidee: Bestellvorschlag erzeugen, in Lieferantenbestellung wandeln, Lieferschein und Lieferantenrechnung erfassen; Mengen-/Preisübernahme prüfen.
Tracelinks: SyRS-013, SyRS-014, SwRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-006
Titel: Automatisierter EDI-Belegaustausch mit Lieferanten
Ebene: StRS
Typ: funktional
Akteur: Einkäufer / System (Hintergrunddienst)
Vorbedingung: Für einen Lieferanten ist eine EDI-Konfiguration (`SupplierEdiConfigurations`) hinterlegt.
Fakt: `SupplierEdiBL` unterstützt mehrere lieferantenspezifische EDI-Formate (OpenTrans 2.1, ALSO, ALSO CH, Herweck, Komsa, Alltron) für Bestellantwort, Lieferung und Rechnung; ein Hintergrunddienst lädt Dateien alle 30 Minuten automatisch herunter und verarbeitet sie.
Aussage: Das System soll Bestellantworten, Lieferavise und Lieferantenrechnungen automatisiert per EDI von unterstützten Distributoren abrufen und in die entsprechenden c-entron-Belege überführen, ohne manuelle Dateneingabe.
Ergebnis: Empfangene EDI-Dokumente werden automatisch in c-entron-Belege umgesetzt bzw. mit bestehenden Bestellungen abgeglichen; fehlerhafte Dateien werden protokolliert und nach mehrfachem Fehlschlag von weiteren Verarbeitungsversuchen ausgeschlossen.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-architecture.md`, `docs/reference/edi/edi-import-rules.md` (zitieren `EdiDownloadService`, `SupplierEdiBL.DownloadStartAsync`, konkrete Blacklist-SQL) - Begründung: Beschreiben eine tatsächlich implementierte, automatisiert laufende Verarbeitungskette inkl. Fehlerbehandlung.
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Purchasing/EDIManagement/EDIManagementView.xaml` - Begründung: UI zur Konfiguration/Überwachung der EDI-Anbindung.
Prüfidee: EDI-Testdatei eines unterstützten Lieferantenformats bereitstellen, Download-Zyklus abwarten, Übernahme in c-entron-Beleg prüfen.
Tracelinks: SyRS-021, SyRS-022, SyRS-026, SwRS-026, SwRS-027, SwRS-028
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-007
Titel: Artikelstamm- und Lagerverwaltung
Ebene: StRS
Typ: funktional
Akteur: Lager-/Logistikmitarbeiter
Vorbedingung: -
Fakt: Modul `Modules\Warehousing` mit Untermodulen `ArticleManagement`, `InventoryManagement` (Inventur), `StockManagement`, `CommissioningManagement`, `BarcodeManagement`.
Aussage: Das System soll die Verwaltung von Artikelstammdaten, Lagerbeständen, Inventuren, Kommissionierung und Barcode-/Seriennummernerfassung ermöglichen.
Ergebnis: Artikel- und Bestandsdaten sind zentral gepflegt und werden bei Beleganlage (z. B. Lieferschein) automatisch fortgeschrieben.
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Warehousing/ArticleManagement`, `Inventory`, `Commissioning*`, `BarcodeManagement` - Begründung: Eigenständige UI-Module je Teilfunktion.
- [SEKUNDÄR] `docs/reference/receipts/receipts-backend-architecture.md` (Abschnitt "Inventory System") - Begründung: Beschreibt Echtzeit-Bestandsprüfung und automatische Lagerbuchung bei Belegverarbeitung.
Prüfidee: Artikel anlegen, Lieferschein mit diesem Artikel buchen, Bestandsfortschreibung im Lagerbestand prüfen.
Tracelinks: SyRS-013, SwRS-001
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-008
Titel: Mehrquellen-Preisfindung inkl. externer Distributorpreise
Ebene: StRS
Typ: funktional
Akteur: Einkäufer / Vertriebsmitarbeiter
Vorbedingung: Artikel ist mit Hersteller-/Distributorcode versehen.
Fakt: Die "Preismatrix" aggregiert bis zu sieben parallele Preisquellen (ITscope, Artikelimport, COP, NEOS, TradersGuide, EGIS, interne Aktionspreise) zu einem Artikel und filtert Aktionspreise nach Gültigkeitszeitraum.
Aussage: Das System soll Einkaufs-/Verkaufspreise aus mehreren internen und externen Quellen konsolidiert darstellen, um eine informierte Preisentscheidung zu unterstützen.
Ergebnis: Für einen Artikel werden alle aktuell gültigen Preise mehrerer Quellen gleichzeitig angezeigt.
Belege:
- [PRIMÄR] `docs/reference/receipts/actionprice-system.md` (zitiert `PriceMatrixViewModel.GetPriceItemsFromArticleActionPrices()`, Zeilen 416-459) - Begründung: Konkrete Methode mit Datumsfilterlogik für Aktionspreise, PRIMÄR belegt.
- [SEKUNDÄR] `src/apis/Centron.APIs.ITscopeDataAccess`, `Centron.APIs.IcecatDataAccess`, `Centron.APIs.EgisDataAccess`, `Centron.APIs.CopDataAccess` - Begründung: Client-Bibliotheken für die genannten externen Preis-/Produktdatenquellen.
Prüfidee: Artikel mit gültigem Aktionspreis und externem API-Preis öffnen; Preismatrix muss beide Quellen gleichzeitig mit korrekter Kennzeichnung anzeigen.
Tracelinks: SyRS-013, SwRS-007
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-009
Titel: Retouren- und Reklamationsmanagement (RMA)
Ebene: StRS
Typ: funktional
Akteur: Service-/Vertriebsmitarbeiter
Vorbedingung: Ursprungsbeleg/Artikel mit Seriennummer ist vorhanden.
Fakt: Eigenständiges Modul `Modules\Rma` mit Untermodulen `SendBack`, `SendForth`, `NewRma`; Commit-Historie zeigt aktive Weiterentwicklung ("mehrere Fremd-RMA-Fälle auf einmal erfassen").
Aussage: Das System soll die Erfassung, Bearbeitung und Nachverfolgung von Kunden- und Lieferantenretouren (RMA) unterstützen, einschließlich Sammelerfassung mehrerer Fälle.
Ergebnis: Ein RMA-Vorgang ist mit Bezug zum Ursprungsartikel/-beleg nachvollziehbar dokumentiert.
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Rma/RmaOverviewView.xaml`, `SendBack/SendBackViewModel.cs`, `SendForth/SendForthViewModel.cs` - Begründung: Eigenständige RMA-UI-Module.
- [KONTEXT] Commit `79e6512154 Ticket 165253: mehrere Fremd-RMA-Fälle auf einmal erfassen (#49)` - Begründung: Bestätigt aktive fachliche Weiterentwicklung der Sammelerfassung.
Prüfidee: RMA-Fall für retournierten Artikel anlegen, Status bis Abschluss verfolgen.
Tracelinks: SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-010
Titel: Helpdesk-/Ticketsystem für Kundenanfragen
Ebene: StRS
Typ: funktional
Akteur: Service-/Support-Mitarbeiter, Endkunde
Vorbedingung: Kunde ist erfasst.
Fakt: Modul `Modules\Helpdesk` (WPF) sowie eigenständiges "ServiceBoard" im Nexus-Webportal (Dashboard, Kanban, Ticketliste, Ticketdetails) bilden ein durchgängiges Ticketsystem; REST-Endpunkte `v1/Helpdesks`.
Aussage: Das System soll die Erfassung, Kategorisierung, Bearbeitung, Weiterleitung und den Abschluss von Kundenservice-Tickets sowohl im Desktop-Client als auch im Webportal unterstützen.
Ergebnis: Ein Ticket durchläuft nachvollziehbar Status von Eingang bis Abschluss inkl. Historie, Dokumenten und Kommentaren.
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Helpdesk/TicketList`, `TicketDetails` - Begründung: WPF-Ticket-UI.
- [SEKUNDÄR] `src/nexus/CentronNexus/ServiceBoard/Dashboard`, `Kanban`, `TicketList/TicketSearchPage.razor` - Begründung: Web-Ticket-UI (Nexus/Blazor).
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/v1/Helpdesks/HelpdesksController.cs` - Begründung: REST-Endpunkte für Ticketabschluss/Kommentare.
Prüfidee: Ticket im WPF-Client anlegen, im Webportal auffindbar und bearbeitbar prüfen, Status bis "geschlossen" verfolgen.
Tracelinks: SyRS-003, SyRS-037, SwRS-034
Konsolidierung: Kandidat: WPF-Helpdesk-Modul und Nexus-ServiceBoard bilden zwei parallele UI-Implementierungen derselben fachlichen Funktion – im Zielsystem konsolidierungsbedürftig.
Status: belegt
```
```
ID: StRS-011
Titel: Automatische Ticketerstellung aus Aufträgen über Vorlagen
Ebene: StRS
Typ: funktional
Akteur: Service-/Vertriebsmitarbeiter
Vorbedingung: Ein Auftrag mit Positionen existiert; mindestens eine Ticket-Erstellungsvorlage ist gepflegt.
Fakt: Feature "Automatische Helpdeskfallerstellung" erlaubt das Speichern, Laden und Verwalten mehrerer Vorlagen (Kategorie, Priorität, Bearbeiter, Erstellungsmodus Single/Group/Custom); eine Vorlage kann als Standard markiert werden.
Aussage: Das System soll es ermöglichen, aus Auftragspositionen automatisiert Helpdesk-Tickets nach konfigurierbaren, wiederverwendbaren Vorlagen zu erzeugen.
Ergebnis: Beim Auslösen der automatischen Ticketerstellung werden je nach gewähltem Modus ein Ticket pro Position, ein Sammelticket oder eine benutzerdefinierte Auswahl erzeugt, vorbelegt mit den Vorlagenwerten.
Belege:
- [PRIMÄR] `docs/features/automatic-helpdesk-creation-templates.md` (zitiert `HelpdeskCreationTemplateBL.SetStandardTemplate`, Tabelle `HelpdeskCreationTemplate`) - Begründung: Vollständig dokumentierte, mit Datenbankschema und Business-Logik belegte Funktion.
Prüfidee: Vorlage mit Modus "Group" anlegen, als Standard setzen, aus Auftrag Tickets erzeugen lassen; genau ein Sammelticket mit Vorlagenwerten muss entstehen.
Tracelinks: SyRS-013, SwRS-034
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-012
Titel: Zeiterfassung und automatisierte Zeitabrechnung
Ebene: StRS
Typ: funktional
Akteur: Service-Mitarbeiter, Buchhaltung
Vorbedingung: Mitarbeiter ist einem Ticket/Auftrag zugeordnet.
Fakt: Modul `Modules\Finances\TimerBilling` sowie Rechteprüfung für Änderungen an Rechnungs-/Lieferscheindatum in den Timer-Billing-Einstellungen ("added rights check for editing invoice or delivery list date in the settings of timer billing").
Aussage: Das System soll erfasste Arbeitszeiten (Timer) mit Bezug zu Tickets/Aufträgen erfassen und automatisiert in Rechnungen überführen können, wobei kritische Datumseinstellungen rechtebeschränkt sind.
Ergebnis: Erfasste Zeiten werden gemäß Abrechnungsregeln in Rechnungspositionen umgewandelt; Nutzer ohne entsprechendes Recht erhalten beim Versuch, das Rechnungs-/Lieferscheindatum zu ändern, einen Hinweis statt der Möglichkeit zur Änderung.
Belege:
- [PRIMÄR] Commit `baa9e7bd9b feat: added rights check for editing invoice or delivery list date in the settings of timer billing. If user has no right an info field is shown. (#97)` - Begründung: Beschreibt eine tatsächlich umgesetzte, rechtegeschützte Regel (Commit-Titel + Verhalensbeschreibung).
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling` - Begründung: Eigenständiges UI-Modul für Zeitabrechnung.
Prüfidee: Benutzer ohne das entsprechende Recht öffnet Timer-Billing-Einstellungen; Datumseingabe für Rechnungs-/Lieferscheindatum muss gesperrt sein und ein Hinweisfeld anzeigen.
Tracelinks: SyRS-011, SwRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-013
Titel: Mahnwesen für überfällige Rechnungen
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Offene, überfällige Rechnung(en) für einen Kunden liegen vor.
Fakt: `DunningBL` (~1060 Zeilen) implementiert Mahnstufenberechnung, Mahnlauf-Statistiken und automatisierte Mahnschreiben-Texterzeugung; Ausführung ist über `ThrowIfUserHasInsufficentRights` rechtegeschützt.
Aussage: Das System soll überfällige Kundenrechnungen erkennen, Mahnstufen berechnen und Mahnläufe mit automatisiert generierten Mahntexten durchführen, wobei nur berechtigte Buchhaltungsmitarbeiter Mahnläufe auslösen können.
Ergebnis: Ein Mahnlauf erzeugt je überfälligem Kunden eine Mahnung der korrekten Mahnstufe; Benutzer ohne Recht können keinen Mahnlauf starten.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs` (Zeile ~1059, Methode `ThrowIfUserHasInsufficentRights`) - Begründung: Konkrete, im Code durchgesetzte Rechteprüfung vor Ausführung eines abrechnungsrelevanten Vorgangs (erfüllt PRIMÄR-Anforderung für Abrechnungslogik).
- [SEKUNDÄR] `DunningRunWebServiceBL.cs` - Begründung: Web-Service-Fassade für den Mahnlauf.
Prüfidee: Mahnlauf mit Benutzer ohne Mahnungsrecht auslösen → Abbruch mit Fehlermeldung; mit berechtigtem Benutzer → korrekte Mahnstufenzuordnung je Kunde.
Tracelinks: SyRS-011, SwRS-012, SwRS-013, SwRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-014
Titel: Verwaltung offener Posten (OPOS)
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Rechnungen mit offenem Zahlungsstatus liegen vor.
Fakt: `OposBL`/`OposRunBL` verwalten offene Posten; Ausführung ist ebenfalls über `ThrowIfUserHasInsufficentRights` rechtegeschützt.
Aussage: Das System soll offene Forderungen (offene Posten) je Kunde konsolidiert darstellen und Verarbeitungsläufe (z. B. Zahlungsabgleich) nur berechtigten Benutzern erlauben.
Ergebnis: Offene-Posten-Liste zeigt korrekt saldierte, noch nicht ausgeglichene Rechnungsbeträge je Kunde; ein OPOS-Lauf durch einen nicht berechtigten Benutzer wird abgelehnt.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/Invoices/Opos/OposBL.cs` (Zeile ~28, `ThrowIfUserHasInsufficentRights`) - Begründung: Durchgesetzte Rechteprüfung vor abrechnungsrelevanter Verarbeitung.
Prüfidee: OPOS-Lauf durch nicht berechtigten Benutzer auslösen → Abbruch; Saldenkontrolle einer Testrechnung mit Teilzahlung.
Tracelinks: SyRS-011, SwRS-013, SwRS-014
Konsolidierung: Kandidat: OPOS und Mahnwesen (StRS-013) teilen dieselbe Rechteschutz-Idiom (`ThrowIfUserHasInsufficentRights`) und denselben fachlichen Kontext (Zahlungsüberwachung) – ggf. im Zielsystem als ein "Forderungsmanagement"-Baustein konsolidierbar.
Status: belegt
```
```
ID: StRS-015
Titel: Elektronische Rechnungsstellung (ZUGFeRD/XRechnung/ebInterface)
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, System
Vorbedingung: Rechnung ist final erstellt.
Fakt: `InvoiceZugferdBL` generiert ZUGFeRD-/XRechnung-konforme XML in mehreren Versionen (1.0 bis 2.1/XRechnung 3.0.1); `Centron.Api.EbInterface` erzeugt zusätzlich das österreichische ebInterface-Format.
Aussage: Das System soll Rechnungen in strukturierten, europäisch/national genormten elektronischen Rechnungsformaten (ZUGFeRD, XRechnung, ebInterface) erzeugen können, um gesetzlichen E-Invoicing-Pflichten nachzukommen.
Ergebnis: Zu einer Rechnung wird eine normkonforme XML-Datei erzeugt, deren Summen mit den Belegsummen übereinstimmen (Toleranzprüfung).
Belege:
- [PRIMÄR] `docs/reference/zugferd-field-mapping.md` (zitiert `InvoiceZugferdBL.cs:117-158`, Toleranzregel ±3,00) - Begründung: Konkrete Methoden- und Regelreferenzen im Code.
- [SEKUNDÄR] `src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs` - Begründung: Eigenständiger Generator für das österreichische Format.
Prüfidee: Rechnung mit mehreren Steuersätzen erzeugen, ZUGFeRD-Export prüfen (KOSIT-Validator), Summenabgleich innerhalb der Toleranz verifizieren.
Tracelinks: SyRS-023, SyRS-024, SwRS-029, SwRS-030
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-016
Titel: Rollenbasierte Benutzer- und Rechteverwaltung
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator
Vorbedingung: -
Fakt: Eigenständiges Modul "Rechteverwaltung" (`Modules\Administration\RightsManagement`); Rechte sind in DB-Tabelle `Sichrech` hinterlegt und werden im Code 318-mal über `HasUserRight(UserRightsConst...)` in 93 Dateien der BL-Schicht geprüft.
Aussage: Das System soll es Administratoren ermöglichen, Benutzern und Gruppen granulare, modul- und funktionsspezifische Rechte zuzuweisen, die im gesamten System konsistent durchgesetzt werden.
Ergebnis: Ein Benutzer ohne zugewiesenes Recht kann die zugehörige Funktion weder in der UI aufrufen noch über die Business-Logik ausführen.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` (`HasUserRight`) - Begründung: Zentrale, im Code durchgesetzte Autorisierungsprüfung, 318 Aufrufstellen.
- [SEKUNDÄR] `docs/guides/development/check-userrights.md`, `add-a-new-right.md` - Begründung: Entwicklerdokumentation des Rechte-Konzepts.
Prüfidee: Benutzer ohne Recht "Kunde anlegen" versucht, einen Kunden anzulegen → UI-Funktion ist deaktiviert und BL-Aufruf liefert Fehlermeldung "Fehlende Rechte...".
Tracelinks: SyRS-011, SyRS-012, SwRS-014, SwRS-015, SwRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-017
Titel: Produkt-/Feature-Lizenzierung
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator, System
Vorbedingung: Kunde hat eine oder mehrere Lizenzen erworben.
Fakt: Lizenzen sind GUID-basiert, mit optionalem Zähler, Ablaufdatum und Versionsgrenze; unterschieden werden `Applications` (login-berechtigt) und `Only Licenses` (Einzelfunktionen); zentrale Prüfung über `LicenseManager.Instance.HasLicense(...)`.
Aussage: Das System soll den Zugriff auf Anwendungen und Einzelfunktionen anhand erworbener Lizenzen (inkl. Mengen- und Zeitbegrenzung) steuern.
Ergebnis: Nicht lizenzierte Funktionen/Module sind für den Kunden nicht sichtbar bzw. nicht nutzbar; bei mengenbegrenzten Lizenzen wird die vereinbarte Obergrenze durchgesetzt.
Belege:
- [PRIMÄR] `docs/reference/security/licensing-system.md` (zitiert `LicenseManager.Instance.HasLicense`, `GetLicenseCount`) - Begründung: Beschreibt konkrete, im Code aufgerufene Prüfmethoden.
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/v1/Administration/LicenseController.cs` - Begründung: REST-Endpunkt zur Lizenzverwaltung.
Prüfidee: Kunde ohne Lizenz für Modul X öffnet c-entron → Modul ist nicht im Modul-Menü sichtbar (`ModuleRegistration.IsModuleAvailable`).
Tracelinks: SyRS-018, SwRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-018
Titel: Kundenportal mit Web-Shop und Angebotsannahme
Ebene: StRS
Typ: funktional
Akteur: Endkunde (Webaccount-Nutzer)
Vorbedingung: Kunde besitzt einen Webaccount-Zugang.
Fakt: Nexus-Blazor-Portal enthält "WebCart"/"WebOffer"-Komponenten (`CustomerPortal`) für Warenkorb, Angebotsansicht und -annahme; Playwright-Tests (`WebaccountTests.cs`) bestätigen einen Warenkorb-mit-Freigabe-Workflow und eine "Receipts"-Übersicht (Angebote/Aufträge/Lieferscheine/Rechnungen/Gutschriften).
Aussage: Das System soll Endkunden über ein Webportal Selbstbedienungsfunktionen bieten: Produkte in den Warenkorb legen, Bestellungen/Angebote freigeben lassen und eigene Belege (Angebote, Aufträge, Rechnungen) einsehen.
Ergebnis: Ein Endkunde kann ohne Mitwirkung eines internen Mitarbeiters eine Bestellung anlegen, zur Freigabe einreichen und nach Freigabe den Bestellstatus sowie zugehörige Belege einsehen.
Belege:
- [PRIMÄR] `tests/PlaywrightTests/WebaccountTests.cs` (`CheckWebAccount`: "Request approval" → "Approve" → "Ready for order") - Begründung: Automatisierter Test beweist den tatsächlich funktionsfähigen Freigabe-Workflow im Livesystem.
- [SEKUNDÄR] `src/nexus/CentronNexus/WebCart/CustomerPortal`, `WebOffer/Components` - Begründung: Zugehörige UI-Komponenten.
Prüfidee: Als Webaccount-Nutzer Artikel in Warenkorb legen, Freigabe anfordern, als Freigebender genehmigen, Status "bestellbereit" prüfen.
Tracelinks: SyRS-003, SyRS-037, SwRS-001
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-019
Titel: Rollenbasierte Sichtbarkeit von Tickets im Kundenportal
Ebene: StRS
Typ: Sicherheit
Akteur: Endkunde (Webaccount-Nutzer)
Vorbedingung: Mehrere Webaccount-Rollen (unterschiedliche Nutzer desselben Kunden) existieren.
Fakt: Playwright-Tests unterscheiden explizit Testkonten (Alpha/Beta/Gamma) mit unterschiedlicher Ticketsichtbarkeit sowie eine datumsbasierte Sichtbarkeitsregel (`CheckWebAccountTicketsAfter240101`).
Aussage: Das System soll die Sichtbarkeit von Tickets im Kundenportal je nach Nutzerrolle und ggf. Erstellungsdatum einschränken, sodass ein Kundenkontakt nur die für ihn freigegebenen Tickets sieht.
Ergebnis: Ein Webaccount-Nutzer ohne entsprechende Freigabe sieht bestimmte Tickets nicht, unabhängig davon, dass sie demselben Kundenkonto zugeordnet sind.
Belege:
- [PRIMÄR] `tests/PlaywrightTests/WebaccountTests.cs` (`CheckWebAccountTicketsCanSeeDisabled` vs. `CanSeeEnabled`, `CheckWebAccountTicketsAfter240101`) - Begründung: Automatisierte Tests belegen eine tatsächlich durchgesetzte, zeilenspezifische Sichtbarkeitsregel.
Prüfidee: Zwei Webaccount-Nutzer desselben Kunden mit unterschiedlicher Ticket-Sichtbarkeitskonfiguration anlegen; prüfen, dass jeder nur die für ihn freigegebenen Tickets sieht.
Tracelinks: SyRS-011, SyRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-020
Titel: Outlook-Integration für Ticket- und Kundenzuordnung
Ebene: StRS
Typ: funktional
Akteur: Service-/Vertriebsmitarbeiter
Vorbedingung: Outlook-Add-in ist installiert und mit c-entron verbunden.
Fakt: `CentronNexus.OutlookAddIn` stellt eine Taskpane bereit, mit der E-Mails Tickets/Vorgängen zugeordnet oder neue Tickets direkt aus einer E-Mail erstellt werden können (Manifest-Beschreibung: "Mails direkt Vorgängen zuordnen und Tickets in Outlook finden").
Aussage: Das System soll es Mitarbeitern ermöglichen, direkt aus Microsoft Outlook heraus E-Mails bestehenden Tickets/Kunden zuzuordnen oder neue Tickets zu erstellen.
Ergebnis: Eine im Outlook-Add-in bearbeitete E-Mail ist im c-entron-Ticket nachvollziehbar verknüpft bzw. hat ein neues Ticket erzeugt.
Belege:
- [SEKUNDÄR] `src/nexus/CentronNexus.OutlookAddIn/Manifest/Manifest.xml`, `OfficeDialog/NewTicketForm.razor`, `Ticket/ManageTicketTab.razor` - Begründung: Konkrete Add-in-UI-Komponenten und Manifestbeschreibung des Funktionsumfangs.
Prüfidee: E-Mail in Outlook öffnen, Add-in nutzen, um ein neues Ticket zu erstellen; Ticket muss im c-entron-System mit E-Mail-Bezug erscheinen.
Tracelinks: SyRS-038
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-021
Titel: Kalendersynchronisation mit Microsoft Exchange/Outlook
Ebene: StRS
Typ: funktional
Akteur: Mitarbeiter (Techniker/Service)
Vorbedingung: Exchange-Synchronisation ist für den Mitarbeiter aktiviert (Exchange Online via Microsoft Graph).
Fakt: `ExchangeSyncService` synchronisiert bidirektional zwischen c-entron-Terminplanung und Outlook-Kalender; für Helpdesk-Zeiterfassungstermine gilt c-entron als "Source of Truth", reine Outlook-Termine werden von Outlook aus aktualisiert.
Aussage: Das System soll Termine zwischen c-entron-Zeitplanung und Microsoft Outlook/Exchange automatisiert synchronisieren, wobei bei Helpdesk-Zeiterfassungsterminen c-entron die maßgebliche Datenquelle bleibt.
Ergebnis: Ein in c-entron erfasster Helpdesk-Zeittermin erscheint im Outlook-Kalender; eine nachträgliche Änderung des Termins direkt in Outlook überschreibt nicht Datum/Uhrzeit des c-entron-Datensatzes.
Belege:
- [PRIMÄR] `docs/features/exchange-sync-bugprotokoll.md` (zitiert `IsHelpdeskSchedule()`, `SyncOldSchedule()`, `UpdateScheduleByGraph()` mit Codebeispielen) - Begründung: Konkrete, im Code umgesetzte und durch QS-Testfälle verifizierte Source-of-Truth-Regel.
Prüfidee: Helpdesk-Zeit in c-entron anlegen (Datum X), Sync abwarten, Termin in Outlook manuell auf Datum Y ändern, erneut synchronisieren → c-entron-Datensatz muss weiterhin Datum X zeigen.
Tracelinks: SyRS-027, SwRS-031, SwRS-032
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-022
Titel: Anbindung von Versanddienstleistern
Ebene: StRS
Typ: Schnittstelle
Akteur: Lager-/Logistikmitarbeiter
Vorbedingung: Lieferschein/Paket ist versandfertig.
Fakt: Zwei eigenständige API-Clients: `Centron.Api.Gls` (direkte GLS-API) und `Centron.Api.Shipcloud` (Multi-Carrier-Aggregator) für Versandauftrag, Label-Erzeugung und Sendungsverfolgung.
Aussage: Das System soll Versandaufträge und Versandlabels für unterstützte Paketdienstleister (u. a. GLS, über Shipcloud weitere Carrier) direkt aus dem Lieferschein erzeugen und den Sendungsstatus zurückmelden können.
Ergebnis: Zu einem Lieferschein wird ein Versandlabel erzeugt; Statusänderungen des Paketdienstes werden dem Beleg zugeordnet.
Belege:
- [SEKUNDÄR] `src/apis/Centron.Api.Gls/CentronGlsLogic.cs`, `src/apis/Centron.Api.Shipcloud/CentronShipcloudLogic.cs` - Begründung: Konkrete Client-Implementierungen mit Versand-/Tracking-Endpunkten.
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/v1/Receipts/ShipcloudPackageTemplatesController.cs` - Begründung: REST-Endpunkt für Versandvorlagen.
Prüfidee: Lieferschein abschließen, Versandlabel über GLS/Shipcloud erzeugen, Tracking-Nummer im Beleg prüfen.
Tracelinks: SyRS-003
Konsolidierung: Kandidat: GLS-Direktanbindung und Shipcloud-Aggregator decken teils überlappende Funktionalität ab – im Zielsystem auf einen Versand-Abstraktionsdienst konsolidierbar.
Status: belegt
```
```
ID: StRS-023
Titel: Abgleich von Produktdaten mit externen Distributoren/Katalogen
Ebene: StRS
Typ: Schnittstelle
Akteur: Einkäufer, Artikelstammpfleger
Vorbedingung: Artikel besitzt Hersteller-/EAN-Code.
Fakt: Vier eigenständige API-Clients (ITscope, Icecat, COP, EGIS) liefern Produktstammdaten, Beschreibungen, Bilder, Verfügbarkeiten und Preise von IT-Distributoren/-Katalogen.
Aussage: Das System soll Artikelstammdaten (Beschreibungen, Bilder, Verfügbarkeit, Distributorpreise) automatisiert mit mehreren externen Produktdatenquellen abgleichen können.
Ergebnis: Ein Artikel kann mit angereicherten Herstellerinhalten (Icecat) sowie tagesaktuellen Distributorpreisen/-verfügbarkeiten (ITscope/COP/EGIS) dargestellt werden.
Belege:
- [SEKUNDÄR] `src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs`, `Centron.APIs.IcecatDataAccess/IcecatApi.cs`, `Centron.APIs.CopDataAccess/CopApi.cs`, `Centron.APIs.EgisDataAccess/EgisApi.cs` - Begründung: Vier eigenständige, dokumentierte API-Clients mit spezifischen Produktdaten-Endpunkten.
Prüfidee: Artikel mit bekanntem Herstellercode über Icecat-Abgleich anreichern lassen, Ergebnis (Beschreibung/Bild) im Artikelstamm prüfen.
Tracelinks: SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-024
Titel: Bankdatenabgleich (Online-Banking)
Ebene: StRS
Typ: Schnittstelle
Akteur: Buchhaltung
Vorbedingung: Bankverbindung ist über finAPI verknüpft.
Fakt: `Centron.APIs.FinAPI` implementiert einen REST/OAuth2-Client für den PSD2-Bankdaten-Aggregator finAPI (Konten, Bankverbindungen, Transaktionen); eigenständiges WPF-Modul `Modules\OnlineBanking`.
Aussage: Das System soll Kontobewegungen und Bankverbindungen automatisiert über einen Banking-Aggregationsdienst abrufen, um den manuellen Abgleich von Zahlungseingängen zu reduzieren.
Ergebnis: Neue Kontotransaktionen werden importiert und können offenen Rechnungen zugeordnet werden.
Belege:
- [SEKUNDÄR] `src/apis/Centron.APIs.FinAPI/FinApiClient.cs`, `Data/Transaction.cs` - Begründung: Konkrete Transaktions-/Konto-Datenmodelle und Client.
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/OnlineBanking` - Begründung: Zugehöriges UI-Modul.
Prüfidee: Testkonto über finAPI-Sandbox verbinden, Transaktionsimport auslösen, Zuordnung zu offener Rechnung prüfen.
Tracelinks: SyRS-013, StRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-025
Titel: Fernüberwachung angebundener Drucksysteme (Managed Print Services)
Ebene: StRS
Typ: Schnittstelle
Akteur: Service-Mitarbeiter (Kopierer-/Druckerfachhändler-Kontext)
Vorbedingung: Gerät ist bei docuFORM registriert und in c-entron verknüpft.
Fakt: `Centron.Api.docuFORM` bindet die docuFORM-MPS-API an (`/dfmserver/v2/devices`), liefert Zählerstände, Verbrauchsmaterial-Status, SNMP-Daten und Gewährleistungsinformationen von Druckern/Kopierern.
Aussage: Das System soll Zählerstände und Verbrauchsmaterialdaten angebundener Drucker/Kopierer über eine externe MPS-Plattform automatisiert abrufen, um Klickabrechnung und Serviceplanung zu unterstützen.
Ergebnis: Aktuelle Zählerstände eines Gerätes stehen für die Vertragsabrechnung (Klickabrechnung) automatisiert zur Verfügung, ohne manuelle Zählerablesung.
Belege:
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/v1/DataExchange/DocuFormApiSettingsController.cs`, `Centron.Api.docuFORM/Models/Swagger/DeviceCounters.cs` - Begründung: Konkrete Konfigurations-/Datenmodelle für Gerätezähler.
Prüfidee: Gerät mit docuFORM verknüpfen, Zählerstand-Abfrage auslösen, Übernahme in Vertragskontingent-Verbrauch (StRS-004) prüfen.
Tracelinks: SyRS-013, StRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-026
Titel: Reporting und betriebswirtschaftliche Statistiken
Ebene: StRS
Typ: funktional
Akteur: Geschäftsführung, Vertriebsleitung
Vorbedingung: Ausreichend Beleg-/Bewegungsdaten liegen vor.
Fakt: Module `Modules\Statistics` (u. a. `SaleStatistics`, `ManagementInfo`) und `Modules\Reports` sowie eine eigene ReportEngine-Schicht in der BL (`ReportEngine`, `Reporting`).
Aussage: Das System soll konfigurierbare betriebswirtschaftliche Auswertungen und Berichte (u. a. Verkaufsstatistiken, Management-Informationen) auf Basis der Beleg- und Stammdaten bereitstellen.
Ergebnis: Ein Bericht liefert aggregierte, dem gewählten Zeitraum/Filter entsprechende Kennzahlen.
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Statistics/SaleStatistics`, `Modules/Reports` - Begründung: Eigenständige UI-Module.
Prüfidee: Verkaufsstatistik für definierten Zeitraum abrufen und Summenkontrolle gegen manuell aggregierte Belegdaten durchführen.
Tracelinks: SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-027
Titel: Mandanten- und Filialverwaltung
Ebene: StRS
Typ: funktional
Akteur: Administrator
Vorbedingung: -
Fakt: Modul `Modules\Administration\MandatorManagement`; Entitäten `Mandator` (Firmenstammdaten) und `Branch` (Filiale) werden u. a. für Rechnungsausstellerdaten und Zugriffsisolation ("Branch Isolation") verwendet.
Aussage: Das System soll die Verwaltung mehrerer Mandanten/Filialen mit eigenen Stammdaten (Adresse, Bankverbindung, Steuer-ID) unterstützen und den Datenzugriff optional auf die eigene Filiale beschränken.
Ergebnis: Rechnungen einer Filiale weisen automatisch deren Absenderdaten aus; ein filialbeschränkter Benutzer sieht nur Belege der eigenen Filiale.
Belege:
- [SEKUNDÄR] `docs/reference/zugferd-field-mapping.md` (Abschnitt "Data Sources": "If BranchI3D is set: Load from Branch table") - Begründung: Konkrete Datenherkunftsregel für Rechnungsabsenderdaten.
- [SEKUNDÄR] `docs/reference/receipts/receipt-search-architecture.md` (Abschnitt "Branch Isolation") - Begründung: Beschreibt filialbezogene Zugriffsbeschränkung in der Belegsuche.
Prüfidee: Benutzer mit "nur eigene Filiale"-Recht sucht Belege → nur Belege der eigenen Filiale werden zurückgegeben.
Tracelinks: SyRS-012
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-028
Titel: Datenschutz-Compliance (DSGVO)
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator, Datenschutzbeauftragter
Vorbedingung: -
Fakt: Eigenständiges Modul `Modules\Administration\DSGVO` (`CentronDataSecurityView.xaml`).
Aussage: Das System soll Funktionen zur Unterstützung datenschutzrechtlicher Anforderungen (DSGVO), z. B. Auskunfts- oder Löschprozesse, bereitstellen.
Ergebnis: `[HYPOTHESE]` – der konkrete Funktionsumfang (Auskunft, Löschung, Anonymisierung) ist aus dem Vorhandensein des Moduls allein nicht ableitbar.
Belege:
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Administration/DSGVO/CentronDataSecurityView.xaml` - Begründung: Belegt Existenz des Moduls, nicht dessen genauen Funktionsumfang.
Prüfidee: Modul öffnen und konkrete Funktionen (Auskunft/Löschung/Anonymisierung) inventarisieren; mit Datenschutzbeauftragtem abgleichen.
Tracelinks: -
Konsolidierung: nein
Status: HYPOTHESE
```
```
ID: StRS-029
Titel: KI-gestützte Assistenzfunktionen
Ebene: StRS
Typ: funktional
Akteur: Mitarbeiter (diverse Rollen)
Vorbedingung: KI-Funktion ist lizenziert/aktiviert.
Fakt: Eigenes WPF-Modul `Modules\ArtificialIntelligence`, REST-Controller `ArtificialIntelligenceChatsController` (Chats, Nachrichten, Tool-Ergebnisse, Instruktions-Prompt-Einstellungen je Mandant/Filiale/Mitarbeiter) sowie ein Kontextmenüeintrag "Zeitbeschreibungen mit KI prüfen"/"Textvorschlag mit KI generieren" in der Zeitabrechnung.
Aussage: Das System soll KI-gestützte Assistenzfunktionen (Chat-Assistent, Textvorschläge, z. B. für Zeitbeschreibungen) mit konfigurierbaren Instruktions-Prompts je Organisationsebene bereitstellen.
Ergebnis: Ein Mitarbeiter kann über einen Chat-Assistenten Anfragen stellen bzw. sich Textvorschläge (z. B. für Zeitbeschreibungen) generieren lassen.
Belege:
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/v1/Administration/ArtificialIntelligenceChatsController.cs` - Begründung: Konkrete REST-Endpunkte für Chat-/Prompt-Verwaltung je Mandant/Filiale/Mitarbeiter.
- [SEKUNDÄR] `src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingAITextRatingPageView.xaml` - Begründung: Konkreter UI-Anwendungsfall (KI-Textvorschlag für Zeitbeschreibung).
Prüfidee: Chat-Assistenten mit Testanfrage aufrufen, Antwortverhalten und Rechteschutz (Mandanten-/Filial-/Mitarbeiterebene) prüfen.
Tracelinks: SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-030
Titel: Gleichwertiger Zugriff über Desktop-Client und Webservice
Ebene: StRS
Typ: nicht-funktional
Akteur: Alle internen Benutzerrollen, externe Anwendungen
Vorbedingung: -
Fakt: Jedes fachliche Modul soll laut Entwicklerdokumentation sowohl eine direkte Datenbankanbindung (`BLLogic`/SqlServer) als auch eine Webservice-Anbindung (`WSLogic`/CentronWebServices) unterstützen ("Every module MUST implement both data access methods").
Aussage: Das System soll fachliche Funktionen unabhängig vom gewählten Zugriffsweg (lokale Datenbankverbindung des Desktop-Clients oder zentraler Webservice) mit gleichem Funktionsumfang bereitstellen.
Ergebnis: Ein Anwender erhält unabhängig vom konfigurierten Verbindungstyp (`CentronConnectionType.SqlServer` vs. `CentronWebServices`) dieselben Ergebnisse bei gleicher Funktion.
Belege:
- [PRIMÄR] `docs/getting-started/general-structure.md` (Abschnitt "Dual Implementation Architecture") - Begründung: Dokumentiert eine als verpflichtend beschriebene Architekturregel mit Codebeispielen (`IAccountContractsLogic`, `BLAccountContractsLogic`, `WSAccountContractsLogic`).
Prüfidee: Gleiche fachliche Aktion (z. B. Kunde anlegen) einmal über Direktverbindung, einmal über Webservice-Verbindung ausführen; Ergebnis muss identisch sein.
Tracelinks: SyRS-001
Konsolidierung: nein
Status: belegt; Workaround (historisch aus On-Premise-Modell mit optionaler Direkt-DB-Anbindung entstanden – für eine SaaS-Neuimplementierung mit zentralem Mehrmandanten-Backend voraussichtlich obsolet)
```
@@ -0,0 +1,693 @@
# Software Requirements Specification (SwRS) – c-entron ERP
Diese SwRS beschreibt Komponenten, Datenmodelle und softwareinterne Regeln auf Ebene konkreter Klassen, Methoden und Datenbankobjekte. Jede Anforderung konkretisiert eine übergeordnete SyRS-Anforderung.
---
```
ID: SwRS-001
Titel: ReceiptBase als gemeinsame Basisklasse aller Belegtypen
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: -
Fakt: `ReceiptBase` (abstrakt, `src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs`) definiert Kopf-Informationen (Nummer, Datum, Version, State, Editor), Filial-, Währungs-, Kontakt-, Adress- und Audit-Felder sowie abstrakte Methoden `GetReceiptItems()`, `AddItem()`, `RemoveItem()`; alle sieben Belegtypen (Offer, Order, DeliveryList, Invoice, Contract, CreditVoucher, PickupList) erben davon.
Aussage: Das System soll gemeinsame Kopf-Attribute und Grundoperationen aller Belegtypen in einer einzigen Basisklasse kapseln, um Redundanz zwischen den sieben Belegarten zu vermeiden.
Ergebnis: Eine Änderung an einem gemeinsamen Kopf-Attribut (z. B. `ConcurrencyControlGuid`) wirkt einheitlich für alle Belegtypen.
Belege:
- [PRIMÄR] `src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs` - Begründung: Konkrete abstrakte Basisklasse mit den genannten Feldern/Methoden (dokumentiert in `docs/reference/receipts/receipts-backend-architecture.md`).
Prüfidee: Neues gemeinsames Kopf-Feld in `ReceiptBase` hinzufügen und Sichtbarkeit in allen sieben abgeleiteten Belegtypen ohne Zusatzaufwand prüfen.
Tracelinks: SyRS-013, SyRS-015
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-002
Titel: IReceiptSpecificLogic als typspezifische Übergangs- und Verhaltensschnittstelle
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: -
Fakt: `IReceiptSpecificLogic` (`src/backend/Centron.BL/Sales/Receipts/IReceiptSpecificLogic.cs`, >250 Member) deklariert je Belegtyp u. a. `CanBeForwardedFrom()`, `CanBeForwardedInto()`, `OnReceiptCreated`, `UpdatesStock`, `IsCostCenterNeeded`, `CanBeAutomaticallyOpened/Closed`; konkrete Implementierungen je Belegtyp (`OfferSpecificLogic`, `OrderSpecificLogic`, `DeliveryListSpecificLogic`, `InvoiceSpecificLogic`, `CreditVoucherSpecificLogic`, `PickupListSpecificLogic`, `ContractSpecificLogic`) sowie gespiegelt für Lieferantenbelege.
Aussage: Das System soll belegtypspezifisches Verhalten (erlaubte Übergänge, Lagerwirkung, Kostenstellenpflicht, Automatisierungsregeln) über eine einheitliche Strategie-Schnittstelle kapseln statt über verstreute Fallunterscheidungen.
Ergebnis: Neues belegtypspezifisches Verhalten wird durch Implementierung/Überschreiben der Schnittstelle hinzugefügt, ohne die generische `ReceiptBL` zu verändern.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/IReceiptSpecificLogic.cs`, `Offers/OfferSpecificLogic.cs`, `Orders/OrderSpecificLogic.cs`, `Invoices/InvoiceSpecificLogic.cs`, `CreditVouchers/CreditVoucherSpecificLogic.cs` u. a. - Begründung: Konkrete Interface- und Implementierungsklassen laut Agentenrecherche der BL-Schicht.
Prüfidee: Für Belegtyp "Rechnung" prüfen, dass `CanBeForwardedInto` ausschließlich `CreditVoucherClass` erlaubt; Versuch, eine Rechnung in einen Auftrag zu wandeln, muss abgelehnt werden.
Tracelinks: SyRS-013, SyRS-014, SwRS-001
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-003
Titel: SpecificLogics-Dispatcher mit Start-Konsistenzprüfung
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Anwendung startet.
Fakt: `SpecificLogics.cs` löst über `_specificLogics.Execute(receipt.ReceiptKind, f => ...)` die passende `IReceiptSpecificLogic`-Implementierung anhand des `ReceiptKind`/`CentronObjectKindNumeric` auf; `ValidateConsistency()` (Zeilen ~148–170) prüft die Symmetrie aller `CanBeForwardedInto`/`CanBeForwardedFrom`-Paare und wirft bei Verletzung eine `ApplicationException`.
Aussage: Das System soll die Zuordnung von Belegtyp zu Verhalten über eine zentrale, beim Start selbstprüfende Registry vornehmen, um Inkonsistenzen im Übergangsmodell frühzeitig (zur Startzeit, nicht erst zur Laufzeit eines betroffenen Belegs) zu erkennen.
Ergebnis: Eine fehlerhafte Konfiguration des Übergangsmodells verhindert den Systemstart, statt erst bei Benutzung des betroffenen Belegtyps sichtbar zu werden.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/SpecificLogics.cs` (Zeilen ~148–170) - Begründung: Konkrete Konsistenzprüfmethode mit definiertem Fehlerverhalten.
Prüfidee: Unit-Test: `ValidateConsistency()` mit absichtlich asymmetrischer Testkonfiguration aufrufen → `ApplicationException` erwarten.
Tracelinks: SyRS-014, SwRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-004
Titel: ReceiptState-Enum als kanonischer Belegstatus
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: -
Fakt: `src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs` definiert `Active`, `Completed`, `Canceled`; daneben führt die Legacy-Spiegeltabelle `Entities/DbEntities/AufKopf.cs` ein rein numerisches Feld `Status` (int?, kein Enum-Typ) sowie ein zusätzliches Feld `FreigabeStatus` (Freigabe-/Genehmigungsstatus) parallel.
Aussage: Das System soll den Verarbeitungsstatus eines Belegs über ein einziges, typsicheres Enum abbilden; aktuell existiert dieses Enum nur auf der modernen Entitätsebene, während die Legacy-Tabellenebene weiterhin einen unabhängigen, nicht typsicheren Integer-Status führt.
Ergebnis: `[HYPOTHESE]` Es ist unklar, ob und wie `ReceiptState` und das Legacy-`AufKopf.Status`-Feld bei jeder Statusänderung synchron gehalten werden oder ob beide Felder unabhängig fortgeschrieben werden können. Zur Bestätigung fehlt eine Codeanalyse der `SaveReceipt*Repository`-Synchronisationsmethoden (`SynchronizeReceiptData`) auf Statusabgleich.
Belege:
- [PRIMÄR] `src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs`, `src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs` (Statuszuweisungen) - Begründung: Belegt das moderne Enum und dessen Verwendung.
- [PRIMÄR] `src/backend/Centron.Entities/Entities/DbEntities/AufKopf.cs` (Feld `Status`, `FreigabeStatus`, int?) - Begründung: Belegt das parallel existierende, nicht typisierte Legacy-Statusfeld.
Prüfidee: Beleg-Statuswechsel auslösen und beide Felder (`ReceiptState` auf modernem Entity, `Status` in Legacy-Tabelle `AufKopf`) per SQL-Abfrage vergleichen.
Tracelinks: SyRS-013
Konsolidierung: Kandidat: Konsolidierung von `ReceiptState`-Enum und Legacy-`Status`/`FreigabeStatus`-Feldern zu einem einzigen Statusmodell im Zielsystem.
Status: HYPOTHESE
```
```
ID: SwRS-005
Titel: Kopf/Pos/Versions-Tabellenschema je Belegtyp
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: -
Fakt: Je Belegtyp existiert ein Tripel aus Legacy-Tabelle (`*Kopf`/`*Pos`), Versionstabelle (`*KopfVersions`/`*PosVersions`, exakte 1:1-Struktur) und moderner View (`Offers`, `OfferItems`, `OfferVersions`, `OfferItemVersions` usw., analog für alle sieben Belegtypen).
Aussage: Das System soll für jeden Belegtyp ein durchgängiges Dreifach-Schema aus operativer Tabelle, Versionshistorie und lesefreundlicher View pflegen; beim Hinzufügen einer neuen Spalte müssen alle zehn in der Dokumentation genannten Stellen (Basistabelle, Versionstabelle, beide Views, Entity, Mapping, temporäre Legacy-Entity/-Mapping, `SaveReceipt*Repository`, DTO/Interfaces) konsistent aktualisiert werden.
Ergebnis: Fehlt eine dieser zehn Anpassungen, tritt laut Dokumentation ein Laufzeitfehler beim Speichern der Versionshistorie auf, oder ein Feld wird beim Laden angezeigt, aber beim Speichern verworfen.
Belege:
- [PRIMÄR] `docs/reference/receipts/receipts-backend-architecture.md` (Abschnitt "Adding New Columns - Complete Checklist", "Critical Save Warning") - Begründung: Explizit dokumentierte, technisch erzwungene Konsistenzkette mit zwei unterschiedlichen Fehlermodi.
Prüfidee: Neue Spalte nur in Basistabelle und modernem Entity hinzufügen (bewusst unvollständig) → Speichern über `SaveReceipt*Repository` muss den Wert NICHT persistieren (Nachweis des dokumentierten Fehlerbilds).
Tracelinks: SyRS-015, SyRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-006
Titel: SaveReceipt*Repository als zusätzlicher Legacy-Persistenzpfad
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Beleg wird gespeichert.
Fakt: Belegspeicherung läuft nicht ausschließlich über das moderne NHibernate-Entity-Mapping, sondern zusätzlich über `SaveReceipt*Repository`-Klassen (z. B. `SaveReceiptContractRepository`, `SaveReceiptInvoiceRepository`), die Werte explizit in temporäre Legacy-Tabellenentities synchronisieren (`SynchronizeReceiptData` für Kopf-, `SynchronizeReceiptItemData` für Positionsfelder).
Aussage: Das System soll sicherstellen, dass jedes persistierte Belegfeld sowohl über das moderne Entity-Mapping als auch über den Legacy-Repository-Pfad korrekt geschrieben wird, da beide Pfade beim Speichern gemeinsam wirken.
Ergebnis: Ein Feld, das nur im modernen Mapping, nicht aber im Repository-Pfad berücksichtigt ist, wird beim Laden angezeigt, geht aber beim erneuten Speichern verloren.
Belege:
- [PRIMÄR] `docs/reference/receipts/receipts-backend-architecture.md` (Abschnitt "Critical Save Warning") - Begründung: Explizit als kritische, tatsächlich beobachtete Fehlerquelle dokumentiert.
Prüfidee: End-to-End-Test gemäß Empfehlung der Dokumentation: Feld setzen, speichern, Beleg neu laden, Rohwert in Legacy-Tabelle per SQL prüfen.
Tracelinks: SyRS-015, SwRS-005
Konsolidierung: nein
Status: belegt; Workaround
```
```
ID: SwRS-007
Titel: ReceiptPriceHelperBL zentrale Preis-/Steuerberechnung
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Belegposition mit Menge, Basispreis, Rabatt und Steuersatz liegt vor.
Fakt: `ReceiptPriceHelperBL` (`src/backend/Centron.BL/Sales/Receipts/ReceiptPriceHelperBL.cs`) stellt `CalculateReceiptPrices()`, `CalculateReceiptVatPrices()` (Netto-/Brutto-Split je Steuersatz) und mehrere Überladungen von `CalculateReceiptItemPrices()`/`CalculateReceiptItemBasePrice()` bereit.
Aussage: Das System soll die Berechnung von Positions- und Belegsummen (netto, Steuer, brutto, je nach Steuersatzgruppe getrennt) zentral in einer wiederverwendbaren Berechnungskomponente kapseln, statt sie in jedem Belegtyp separat zu implementieren.
Ergebnis: Alle Belegtypen berechnen Summen nach identischer Logik; eine Änderung der Rundungs- oder Rabattregel wirkt einheitlich für alle Belegtypen.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/ReceiptPriceHelperBL.cs` (laut Agentenrecherche der BL-Schicht, konkrete Methodensignaturen) - Begründung: Zentrale, tatsächlich vorhandene Berechnungsklasse.
Prüfidee: Beleg mit gemischten Steuersätzen (7 %/19 %) anlegen; Summenberechnung je Steuersatzgruppe manuell nachrechnen und mit Systemergebnis vergleichen.
Tracelinks: StRS-008, SyRS-013
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-008
Titel: TaxBL effektivdatierte Steuersatzkette
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Steuersatzänderung (z. B. gesetzliche MwSt-Änderung) ist im System hinterlegt.
Fakt: `TaxBL.GetTaxRateChain(taxRateI3D)` und `GetTaxRateForReceiptItem(taxRateI3D, receiptDate, articleI3D)` lösen den zum Belegdatum gültigen Steuersatz anhand einer historisierten Steuersatzkette auf, statt immer den aktuellen Satz zu verwenden.
Aussage: Das System soll bei rückwirkender oder historischer Belegbearbeitung stets den zum jeweiligen Belegdatum gesetzlich gültigen Steuersatz anwenden, auch wenn sich der Steuersatz zwischenzeitlich geändert hat.
Ergebnis: Ein am 30.06. erfasster Beleg verwendet auch nach einer zum 01.07. wirksamen Steuersatzänderung weiterhin den bis 30.06. gültigen Satz.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Warehousing/TaxBL.cs` (`GetTaxRateChain`, `GetTaxRateForReceiptItem`) - Begründung: Konkrete, datumsparametrisierte Methode zur historisierten Steuersatzauflösung.
Prüfidee: Steuersatzänderung zu einem Stichtag anlegen; Beleg mit Datum vor und nach dem Stichtag erzeugen und jeweils angewandten Steuersatz prüfen.
Tracelinks: StRS-008, SyRS-013, SwRS-007
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-009
Titel: Kontingent-Berechnung in ContractBL/ContractSpecificLogic
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Vertrag mit Kontingent ist angelegt.
Fakt: `ReceiptContractBL.ContractContingentBalanceCalculation()`, `CalculateContingentWithRecalculationArticle()`, `UpdateContractContingentBalanceCalculationForReceiptChange()` und `UpdateTakeRestAndOverBooking()` berechnen Kontingentverbrauch, Restwerte und Überbuchungsfälle.
Aussage: Das System soll bei jeder abrechnungsrelevanten Änderung eines Vertragsbelegs (z. B. Mengenänderung) automatisch die betroffenen Kontingentsalden (verbrauchte Stunden/Beträge, Restwert) neu berechnen.
Ergebnis: Eine nachträgliche Änderung einer Vertragsposition führt zu einer konsistenten Neuberechnung des Kontingentsaldos, inklusive korrekter Behandlung von Restwert- und Überbuchungsfällen.
Belege:
- [PRIMÄR] `docs/reference/receipts/contracts-backend.md` (konkrete Methodenliste `ReceiptContractBL`) - Begründung: Dokumentierte, im Code vorhandene Berechnungsmethoden.
Prüfidee: Vertrag mit Kontingent 10h anlegen, 4h verbrauchen, Position nachträglich auf 6h Verbrauch ändern; Kontingentsaldo muss korrekt auf 4h Rest aktualisiert werden.
Tracelinks: StRS-003, StRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-010
Titel: RMM-Artikel-Abrechnung via RiverConnectionBL
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Vertrag mit `WhetherRMM=true` und konfigurierten `ContractArticleReferenzes`.
Fakt: Während `CreateInvoiceToContractComplete` ruft `CheckRMMArticle` die Methode `RiverConnectionBL.GetContractBillingAmounts(from, to, customerI3D, rmmArticleReferences)` auf; das Ergebnis wird an der Position des Platzhalters `@@RMMArtikel@@` im Rechnungstext eingefügt oder, falls kein Platzhalter vorhanden, an vorletzter Position.
Aussage: Das System soll bei der Rechnungserstellung für RMM-abrechnungspflichtige Verträge automatisiert Nutzungsdaten vom externen RMM-Dienst abrufen und als zusätzliche Rechnungsposition(en) an einer im Rechnungstext markierten oder impliziten Position einfügen.
Ergebnis: Die erzeugte Rechnung enthält für jede Artikelreferenz mit verfügbaren Nutzungsdaten eine berechnete Position mit erläuterndem Text.
Belege:
- [PRIMÄR] `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` (Codebeispiel `rmmItem = invoice.Items.FirstOrDefault(...)`, `RiverConnectionBL.GetContractBillingAmounts(...)`) - Begründung: Konkreter, zitierter Quellcodeausschnitt.
Prüfidee: Rechnung für RMM-Vertrag mit Platzhalter `@@RMMArtikel@@` im Textbaustein erzeugen; RMM-Position muss exakt an der Platzhalterstelle erscheinen und der Platzhaltertext entfernt sein.
Tracelinks: StRS-004, SwRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-011
Titel: Abbruchregel bei Nichterreichbarkeit des RMM-Dienstes
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Externer RMM-Dienst ist nicht erreichbar; Vertrag erwartet RMM-Positionen.
Fakt: Liefert `RiverConnectionBL.GetContractBillingAmounts` einen Fehlerstatus und existieren erwartete RMM-Artikelreferenzen oder ein `@@RMMArtikel@@`-Platzhalter, wird eine `RMMServiceUnavailableException` geworfen und die Rechnungserstellung abgebrochen; ohne erwartete RMM-Referenzen wird die Verarbeitung stillschweigend fortgesetzt (`return`).
Aussage: Das System soll die Erstellung einer Rechnung mit erwarteten, aber nicht abrufbaren RMM-Nutzungsdaten zwingend verhindern, um eine fehlerhafte (zu niedrige) Abrechnung des Kunden auszuschließen.
Ergebnis: Bei Nichterreichbarkeit des RMM-Dienstes und vorhandenem RMM-Bezug wird keine Rechnung erzeugt; stattdessen wird ein Fehler mit Diagnoseinformation geloggt.
Belege:
- [PRIMÄR] `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` (Codebeispiel mit `RMMServiceUnavailableException`, Bedingung `rmmItem != null || rmmArticleReferences.Any()`) - Begründung: Konkrete, im Code durchgesetzte Abbruchbedingung für einen abrechnungsrelevanten Vorgang (erfüllt PRIMÄR-Anforderung).
Prüfidee: RMM-Dienst in Testumgebung deaktivieren, Rechnungserstellung für Vertrag mit RMM-Artikelreferenz auslösen → Erstellung muss mit definierter Fehlermeldung abbrechen, keine Rechnung darf im System entstehen.
Tracelinks: StRS-004, SwRS-010
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-012
Titel: DunningBL Mahnstufenberechnung
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Überfällige Rechnung(en) liegen vor.
Fakt: `DunningBL.GetDunningCustomers()`, `CalculateDunningStatistics()`, `UpdateDunningSettingsForCustomer()`, `UpdateDunningStopAndInfo()` implementieren die Mahnstufenlogik inkl. Textbaustein-basierter Mahnschreiben-Generierung (`GetTextWithReplacedVariablesForCustomerEmail`).
Aussage: Das System soll je Kunde und überfälliger Rechnung die korrekte Mahnstufe anhand konfigurierbarer Fristen berechnen und daraus automatisiert ein Mahnschreiben mit variablen Textbausteinen generieren.
Ergebnis: Ein Kunde mit mehreren unterschiedlich lang überfälligen Rechnungen erhält eine Mahnung auf der höchsten zutreffenden Mahnstufe mit korrekt eingesetzten Variablen (Betrag, Fälligkeitsdatum).
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs` (konkrete Methoden laut Agentenrecherche der BL-Schicht) - Begründung: Zentrale Mahnwesen-Klasse, ~1060 Zeilen fachlicher Logik.
Prüfidee: Kunde mit Rechnungen unterschiedlicher Überfälligkeit anlegen, Mahnlauf ausführen, korrekte Mahnstufenzuordnung und Textvariablen prüfen.
Tracelinks: StRS-013, SwRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-013
Titel: Rechteschutz vor Ausführung abrechnungsrelevanter Läufe
Ebene: SwRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Benutzer löst Mahnlauf oder OPOS-Lauf aus.
Fakt: Sowohl `DunningBL.cs` (Zeile ~1059) als auch `OposBL.cs` (Zeile ~28) rufen vor Ausführung `ThrowIfUserHasInsufficentRights(LoggedInUser)` auf (Methodenname mit Tippfehler "Insufficent" im Original-Code beibehalten).
Aussage: Das System soll vor dem Anstoßen eines Mahnlaufs oder eines Offene-Posten-Laufs zwingend prüfen, ob der auslösende Benutzer über das erforderliche Recht verfügt, und die Ausführung andernfalls mit einer Exception verhindern.
Ergebnis: Ein Benutzer ohne das erforderliche Recht kann weder einen Mahnlauf noch einen OPOS-Lauf tatsächlich starten, unabhängig davon, ob die UI die entsprechende Schaltfläche anzeigt.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs:1059`, `src/backend/Centron.BL/Sales/Receipts/Invoices/Opos/OposBL.cs:28` (`ThrowIfUserHasInsufficentRights`) - Begründung: Direkter, im BL-Code durchgesetzter Rechte-Check unmittelbar vor abrechnungsrelevanter Verarbeitung (PRIMÄR-Beleg für Abrechnungslogik gemäß Risikoklassifikation).
Prüfidee: BL-Methode `RunDunning`/`RunOpos` direkt (unter Umgehung der UI) mit einem Benutzer ohne Recht aufrufen → Exception muss geworfen werden, kein Lauf darf erzeugt werden.
Tracelinks: StRS-013, StRS-014, SyRS-011
Konsolidierung: Kandidat: identisches Rechteschutz-Idiom in Dunning und Opos – im Zielsystem als gemeinsamer Decorator/Cross-Cutting-Concern (z. B. Attribut) statt Code-Duplikation umsetzbar.
Status: belegt
```
```
ID: SwRS-014
Titel: UserRightsConst/HasUserRight-Autorisierungsmuster
Ebene: SwRS
Typ: Sicherheit
Akteur: System
Vorbedingung: -
Fakt: `UserRightsExt.HasUserRight(this AppUser, int rightId)` prüft ein Recht gegen die vom Benutzer geladenen Rechte; Aufrufkonvention verwendet stets Konstanten aus `UserRightsConst` (z. B. `UserRightsConst.Sales.Customer.CustomerCommon.CREATE_CUSTOMER`) statt numerischer Literale; 318 Aufrufstellen in 93 Dateien der BL-Schicht.
Aussage: Das System soll jede Rechteprüfung ausschließlich über benannte Konstanten (`UserRightsConst`) und eine einheitliche Extension-Methode (`HasUserRight`) vornehmen, um Lesbarkeit und Konsistenz der Autorisierung sicherzustellen.
Ergebnis: Eine Änderung der internen Rechte-ID erfordert keine Anpassung an den 318 Aufrufstellen, solange die Konstante unverändert bleibt.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` - Begründung: Zentrale, tatsächlich 318-fach verwendete Methode (durch Agentenrecherche gezählt).
- [SEKUNDÄR] `docs/guides/development/check-userrights.md` - Begründung: Dokumentiertes Verwendungsmuster mit Codebeispiel aus `AccountBL.cs`.
Prüfidee: Statische Codeprüfung: Keine direkte numerische Rechte-ID (Literal) in einem `HasUserRight`-Aufruf ohne `UserRightsConst`-Referenz.
Tracelinks: StRS-016, SyRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-015
Titel: AppRightsBL zentrale Rechteverwaltung
Ebene: SwRS
Typ: Sicherheit
Akteur: Administrator
Vorbedingung: -
Fakt: `AppRightsBL` bietet `GetAllRights()`, `GetAllRightGroups(AppUser)`, `GetRightsFromCurrentUser(AppUser)`, `CheckRightsFromUser(currentUserI3D, rightIds)`; `AppUserGroupBL` verwaltet Gruppen-Rechte-Zuordnungen.
Aussage: Das System soll Rechtevergabe strukturiert über Gruppen ermöglichen, wobei einem Benutzer über seine Gruppenzugehörigkeit(en) ein aggregiertes Rechteset zugeordnet wird.
Ergebnis: Ein Benutzer erhält alle Rechte, die einer seiner zugeordneten Gruppen zugewiesen sind (Vereinigungsmenge).
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs`, `AppUserGroupBL.cs` - Begründung: Konkrete, zentrale Rechteverwaltungsklassen laut Agentenrecherche.
Prüfidee: Benutzer zwei Gruppen mit unterschiedlichen Rechten zuordnen; `GetRightsFromCurrentUser` muss die Vereinigungsmenge beider Gruppenrechte liefern.
Tracelinks: StRS-016, SwRS-014, SwRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-016
Titel: Skriptbasierte Rechtevergabe über die Sichrech-Tabelle
Ebene: SwRS
Typ: Daten
Akteur: Entwickler (bei Erweiterung), System (Migration)
Vorbedingung: Neues Recht soll eingeführt werden.
Fakt: Neue Rechte werden über Migrationsskripte in die Tabelle `Sichrech` eingefügt (`I3D`, `Text`, `OwnerRecht`, `NumChildren`, `Beschreibung`); empfohlener Weg ist `ScriptHelpers.AddRightIfNotExists(...)`, das zusätzlich den `NumChildren`-Zähler des übergeordneten Rechts konsistent hochzählt.
Aussage: Das System soll neue Berechtigungen ausschließlich über den standardisierten Migrationsmechanismus in die zentrale Rechtetabelle einfügen, inklusive korrekter Pflege der Eltern-Kind-Beziehung (`OwnerRecht`/`NumChildren`).
Ergebnis: Ein neu eingeführtes Recht erscheint korrekt eingeordnet in der Rechtebaum-Hierarchie der Rechteverwaltung, ohne dass der `NumChildren`-Zähler des Elternrechts manuell inkonsistent gepflegt werden muss.
Belege:
- [PRIMÄR] `docs/guides/development/add-a-new-right.md` (konkretes SQL-Beispiel `INSERT INTO Sichrech`, `ScriptHelpers.AddRightIfNotExists`) - Begründung: Verbindlich dokumentierter, im Code umgesetzter Mechanismus.
Prüfidee: Neues Recht per `AddRightIfNotExists` unterhalb eines bestehenden Elternrechts anlegen; `NumChildren` des Elternrechts muss automatisch um 1 erhöht sein.
Tracelinks: StRS-016, SwRS-015, SyRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-017
Titel: TicketAuthenticationHandler
Ebene: SwRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Anfrage enthält `Authorization: Bearer <ticket>` oder Query-Parameter `access_token`.
Fakt: `TicketAuthenticationHandler` (Default-Authentifizierungsschema) validiert das Ticket gegen `AuthenticationTicketBL.GetAuthTicketInfo` und erstellt bei Erfolg einen `ClaimsPrincipal`; Ticket-Erstellung protokolliert IP-Adresse und angefragte API-Methode.
Aussage: Das System soll jede eingehende Anfrage anhand eines gültigen, in der Datenbank hinterlegten Tickets authentifizieren und dabei IP-Adresse sowie aufgerufene Methode zu Prüfzwecken protokollieren.
Ergebnis: Eine Anfrage ohne gültiges Ticket wird mit 401 abgelehnt; jede erfolgreiche Authentifizierung ist mit IP und Methode nachvollziehbar.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/AspNetCore/TicketAuthenticationHandler.cs` - Begründung: Konkrete Handler-Implementierung laut Agentenrecherche.
Prüfidee: Anfrage mit manipuliertem/gefälschtem Ticket senden → 401; erfolgreiche Anfrage im Audit-Log mit korrekter IP/Methode wiederfinden.
Tracelinks: SyRS-007
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-018
Titel: OpenIdConnectAuthenticator (oid-Claim-Lookup)
Ebene: SwRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Gültiges Microsoft-ID-Token liegt vor.
Fakt: `OpenIdConnectAuthenticator` extrahiert den `oid`-Claim aus dem validierten JWT und sucht den zugehörigen Benutzer über `OpenIdConnectSubjectIdentifier` in der Tabelle `Sichbenu`; `AuthenticatorFactory` routet abhängig von `SystemAuthenticationMethod` (0=Any, 3=OpenIdConnect) dorthin.
Aussage: Das System soll die Zuordnung eines extern authentifizierten Microsoft-Kontos zu einem c-entron-Benutzerkonto ausschließlich über die eindeutige, unveränderliche Entra-Object-ID (`oid`) vornehmen, nicht über E-Mail-Adresse oder Anzeigenamen.
Ergebnis: Eine Änderung der E-Mail-Adresse oder des Anzeigenamens im Microsoft-Konto hat keinen Einfluss auf die Benutzerzuordnung.
Belege:
- [PRIMÄR] `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` (Codebeispiel `identity.Claims.FirstOrDefault(c => c.Type == "oid")`, konkreter Dateipfad `OpenIdConnectAuthenticator.cs`) - Begründung: Konkrete, code-referenzierte Zuordnungslogik.
Prüfidee: E-Mail-Adresse des verknüpften Microsoft-Kontos ändern; Anmeldung muss weiterhin denselben c-entron-Benutzer zuordnen.
Tracelinks: SyRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-019
Titel: JWT-Bearer-Validierung (Issuer/Audience/Lifetime/Signatur)
Ebene: SwRS
Typ: Sicherheit
Akteur: System
Vorbedingung: JWT-Authentifizierung ist konfiguriert (`JwtAuthority`/`JwtAudience`).
Fakt: `CentronHost.cs` konfiguriert `AddJwtBearer(...)` mit Validierung von Issuer, Audience, Lifetime und Signatur, `ValidateTokenReplay = true`; Fehlschläge werden inkl. Header/Payload über `LoggingJwtBearerEvents` protokolliert.
Aussage: Das System soll eingehende JWTs vollständig gegen Aussteller, Empfänger, Gültigkeitszeitraum und kryptografische Signatur validieren und zusätzlich Replay-Angriffe durch Token-Wiederverwendung verhindern.
Ergebnis: Ein abgelaufenes, mit falschem Schlüssel signiertes oder bereits verwendetes Token wird abgelehnt und der Vorgang protokolliert.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/CentronHost.cs` (Zeilen ~184–205) - Begründung: Konkrete Validierungsparameter im Code laut Agentenrecherche.
Prüfidee: Manipuliertes JWT (falsche Signatur, abgelaufen, wiederverwendet) gegen `POST /jwt/login` senden → Ablehnung in allen drei Fällen, mit Log-Eintrag.
Tracelinks: SyRS-008
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-020
Titel: AccessTokensController (Personal Access Tokens)
Ebene: SwRS
Typ: Sicherheit
Akteur: Benutzer, externe Anwendung
Vorbedingung: Benutzer ist per JWT authentifiziert.
Fakt: `AccessTokensController` (nur `[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]`) bietet `GET my`, `GET {id}`, `GET {id}/logs`, `GET {id}/statistics`, `POST my`, `PUT {id}`, `PUT {id}/deactivate|activate`, `DELETE {id}`.
Aussage: Das System soll persönliche API-Zugriffstoken ausschließlich über einen eigenen, JWT-geschützten Verwaltungsendpunkt erzeugen, deaktivieren und deren Nutzung protokollieren lassen.
Ergebnis: Ein deaktivierter Token wird sofort für alle nachfolgenden API-Aufrufe ungültig, unabhängig vom bisherigen Ablaufdatum.
Belege:
- [PRIMÄR] `src/webservice/Centron.Controllers/Controllers/v1/Administration/AccessTokensController.cs` - Begründung: Konkrete Endpunktliste laut Agentenrecherche.
Prüfidee: Access Token erstellen, erfolgreichen API-Aufruf durchführen, Token per `PUT {id}/deactivate` deaktivieren, identischen Aufruf wiederholen → Ablehnung.
Tracelinks: SyRS-009
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-021
Titel: LicenseManager/LicenseGuids/ApplicationKind
Ebene: SwRS
Typ: Sicherheit
Akteur: System
Vorbedingung: -
Fakt: `LicenseGuids.cs` listet alle vergebenen Lizenz-GUIDs (Applications und Einzelfunktionen); `ApplicationKind.cs` listet die Teilmenge, die zum Login am Webservice berechtigt (dort werden `count`, `valid until date`, `valid until version` automatisch geprüft); `LicenseManager.Instance.HasLicense(guid)`/`GetLicenseCount(guid)` sind die zentralen Prüfmethoden.
Aussage: Das System soll zwischen login-berechtigenden "Applications" und reinen Feature-Lizenzen technisch unterscheiden und für Applications automatisch Mengen-, Zeit- und Versionsgrenzen durchsetzen, für einfache Feature-Lizenzen hingegen nur eine Ja/Nein-Prüfung anbieten.
Ergebnis: Eine Anwendung, die nicht in `ApplicationKind.cs` gelistet ist, kann sich nicht am Webservice anmelden, selbst wenn eine gültige Lizenz-GUID vorliegt.
Belege:
- [PRIMÄR] `docs/reference/security/licensing-system.md` - Begründung: Vollständig dokumentiertes, im Code verwendetes Unterscheidungsmuster mit konkreten Dateinamen.
Prüfidee: Lizenz-GUID, die nur in `LicenseGuids.cs`, nicht aber in `ApplicationKind.cs` gelistet ist, für einen Login-Versuch verwenden → Ablehnung.
Tracelinks: StRS-017, SyRS-018
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-022
Titel: ApplicationSettings/Stammdat Dual-Table-Konfigurationszugriff
Ebene: SwRS
Typ: Daten
Akteur: Entwickler, System
Vorbedingung: -
Fakt: Legacy-Einstellungen liegen in `Stammdat` (Zugriff über `AppSettingsConst`, `AppSettingsBL.GetSettings(AppSettingsConst)`), neue Einstellungen ausschließlich in `ApplicationSettings` (Zugriff über `ApplicationSettingID`, `ApplicationSettingDefinitions`); Zugriff stets über typisierte Gruppen-Settings-Klassen, nie direkt auf die Tabellen.
Aussage: Das System soll neue Konfigurationseinstellungen ausschließlich in der aktuellen `ApplicationSettings`-Tabelle mit eindeutiger, fortlaufend vergebener ID und dokumentierter Beschreibung anlegen; die Legacy-`Stammdat`-Tabelle wird nur noch gelesen, nicht erweitert.
Ergebnis: Jede neue Einstellung ist über eine eindeutige `ApplicationSettingID` mit zugehöriger Beschreibung in `ApplicationSettingDefinitions.cs` auffindbar; kein direkter SQL-Zugriff auf die Einstellungstabellen durch den Client.
Belege:
- [PRIMÄR] `docs/guides/development/settings-management.md` (Codebeispiele `AppSettingsBL.GetSettings`, `GetSettingsForUpdate`) - Begründung: Verbindlich dokumentiertes, im Code umgesetztes Konfigurationsmuster.
Prüfidee: Neue Einstellung mit nächster freier ID gemäß Kommentar in `ApplicationSettingID.cs` anlegen, Lese-/Schreibzugriff über `AppSettingsBL` prüfen.
Tracelinks: SyRS-016
Konsolidierung: Kandidat: Doppelte Konfigurationsablage (`Stammdat` vs. `ApplicationSettings`) ist ein expliziter Migrationskandidat für das Zielsystem.
Status: belegt; Workaround
```
```
ID: SwRS-023
Titel: ScriptMethod/ScriptHelpers Migrationsklassen
Ebene: SwRS
Typ: Daten
Akteur: System (Anwendungsstart)
Vorbedingung: Neue Anwendungsversion enthält neue Skripte.
Fakt: 764 Klassen `ScriptMethod<Nummer>.cs` implementieren `BaseScriptMethod.GetSqlQueries()`; `ScriptHelpers.cs` erzeugt idempotente DDL (`AddTableIfNotExists`, `AddColumnIfNotExists`, `AddForeignKeyIfNotExists`, `AddIndexIfNotExists`, `ChangeColumnTypeIfExists`); `AddTableIfNotExists` erzeugt automatisch die `I3D`-Primärschlüsselspalte.
Aussage: Das System soll beim Start automatisch alle noch nicht ausgeführten, nach Skriptnummer sortierten Migrationsskripte anwenden und dabei stets die generierenden Hilfsmethoden (`ScriptHelpers`) statt handgeschriebener DDL verwenden, um Idempotenz sicherzustellen.
Ergebnis: Ein wiederholter Start mit bereits angewendeten Skripten führt zu keiner erneuten Änderung oder Fehlermeldung (Idempotenz durch `IF NOT EXISTS`-Prüfungen).
Belege:
- [PRIMÄR] `docs/reference/database/script-rules.md`, `docs/guides/database/create-scripts.md` - Begründung: Verbindlich dokumentierter Mechanismus mit konkreten Beispielskripten (`ScriptMethod11699.cs` u. a.).
Prüfidee: Anwendung zweimal hintereinander gegen dieselbe (bereits migrierte) Datenbank starten; zweiter Start darf keine SQL-Fehler und keine erneuten Schemaänderungen erzeugen.
Tracelinks: SyRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-024
Titel: Fluent-NHibernate-Mapping-Konventionen
Ebene: SwRS
Typ: Daten
Akteur: Entwickler
Vorbedingung: -
Fakt: Jede Entität besitzt eine zugehörige `ClassMap<T>`-Klasse unter `Centron.DAO/Mappings/`, die Tabelle, ID und alle Eigenschaften explizit mit `.Not.Nullable()`/`.Length(n)` beschreibt; ca. 600+ Mapping-Klassen im Repository.
Aussage: Das System soll jede persistierte Eigenschaft explizit (nicht implizit über NHibernate-Konvention) hinsichtlich Spaltenname, Nullbarkeit und Länge abbilden, um Diskrepanzen zwischen Datenbankschema und Objektmodell zu vermeiden.
Ergebnis: Eine über NHibernate gespeicherte Entität erzeugt exakt die im Mapping deklarierte Spaltenstruktur, ohne stillschweigende Konventionsannahmen.
Belege:
- [PRIMÄR] `docs/reference/architecture/dtos-and-entities.md` (Codebeispiel `ThingyMaps : ClassMap<Thingy>`) - Begründung: Verbindlich dokumentiertes Mapping-Muster.
- [PRIMÄR] Agentenrecherche `Centron.DAO`: ca. 600+ `*Maps.cs`-Dateien unter `Mappings/` - Begründung: Tatsächlicher Umfang des Musters im Code.
Prüfidee: Neue Entität ohne explizite Längenangabe in einem Mapping anlegen und Abweichung vom tatsächlichen DB-Schema als Codereview-Fehler identifizieren.
Tracelinks: SyRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-025
Titel: GenericStoredProcedureDAO als Rohzugriffs-Fallback
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Eine Operation ist mit reinem NHibernate-Mapping nicht praktikabel (z. B. komplexe Reporting-Abfrage, Massenoperation).
Fakt: `GenericStoredProcedureDAO`/`RawSqlAccessDAO` bieten `GetRawSqlResult`, `ExecuteSqlScalarWithIntResult`, `CreateSQLQuery(...).ExecuteUpdate()` als expliziten Rohzugriffspfad neben dem generischen NHibernate-CRUD (`GenericDAO`); ein umfangreicher externer Abfragekatalog (`NamedQueryPool.xml`, 11.477 Zeilen) hält parametrisierte SQL-/HQL-Abfragen vor.
Aussage: Das System soll für performancekritische oder mit dem ORM nicht abbildbare Datenzugriffe einen kontrollierten Rohzugriffspfad (parametrisierte Named Queries bzw. direkte SQL-Ausführung) bereitstellen, statt das ORM in solchen Fällen zu erzwingen.
Ergebnis: Komplexe Reporting- und Massenverarbeitungs-Abfragen laufen performant über parametrisierte Rohabfragen, ohne die NHibernate-Session-Semantik zu verletzen.
Belege:
- [PRIMÄR] `src/backend/Centron.DAO/GenericStoredProcedureDAO.cs`, `AdoNETDataAccess/RawSqlAccessDAO.cs`, `NamedQueries/NamedQueryPool.xml` - Begründung: Konkrete, umfangreiche Rohzugriffsschicht laut Agentenrecherche der DAO-Schicht.
- [KONTEXT] `src/backend/Centron.DAO/TradePool/TradePoolDAO.cs:21` (`"EXECUTE dbo.spInsertNewArticle ..."`, stringverkettet, unparametrisiert) - Begründung: Als Negativbeispiel/Risikohinweis dokumentiert (siehe Analysebericht), nicht als durchgesetzte Regel.
Prüfidee: Alle Verwendungsstellen von `RawSqlAccessDAO`/`GenericStoredProcedureDAO` auf konsequente Parametrisierung prüfen (keine Stringverkettung von Benutzereingaben).
Tracelinks: SyRS-016
Konsolidierung: nein
Status: belegt; Workaround
```
```
ID: SwRS-026
Titel: SupplierEdiBL Partial-Klassen je Lieferant
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: -
Fakt: `SupplierEdiBL` ist als `partial class` über mehrere Dateien (`SupplierEdiBL.AlsoCH.cs`, `.Also.cs`, `.Alltron.cs`, `.Herweck.cs`, `.Komsa.cs`, `.Opentrans.cs`) organisiert; zentrale Dispatch-Methode `ApplyDistriToCentron` routet je nach `EdiDataType` und `ObjectKind` in die passende lieferantenspezifische Parsing-Methode.
Aussage: Das System soll lieferantenspezifische EDI-Parsing- und Mapping-Logik über das Partial-Class-Muster organisieren, sodass eine gemeinsame Klassenschnittstelle nach außen besteht, während die Implementierung je Lieferant isoliert wartbar bleibt.
Ergebnis: Eine Änderung an der ALSO-CH-spezifischen Verarbeitung (z. B. Swiss-ESR-Handling) wirkt sich nicht auf andere Lieferantenformate aus.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-architecture.md` (Abschnitt "Partial Class Architecture", konkrete Dateiliste) - Begründung: Dokumentierte Klassenstruktur mit Codebeispiel.
Prüfidee: EDI-Datei im ALSO-CH-Format mit Swiss-ESR-Code verarbeiten und prüfen, dass andere Lieferantenformate (z. B. Herweck) unverändert funktionieren (Regressionstest).
Tracelinks: StRS-006, SyRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-027
Titel: EdiDataType/EDIConnectionObjectKind-Enums
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: -
Fakt: `EdiDataType` (OpenTrans21=1, Also=2, AlsoCH=3, Herweck=4, Komsa=5, Alltron=6, Zugferd=7) und `EDIConnectionObjectKind` (Order=1, OrderResponse=2, Delivery=3, Invoice=4) steuern zusammen mit `SupplierEdiConfigurations` (`SupplierI3D`, `EdiDataType`, `ObjectKind`, `ConnectionString`), welcher Parser für welches Dokument einer Lieferantenkonfiguration verwendet wird.
Aussage: Das System soll die Kombination aus Lieferant, Datenformat und Dokumenttyp eindeutig über zwei orthogonale Enums konfigurierbar machen, sodass ein Lieferant potenziell mehrere Formate/Dokumenttypen parallel nutzen kann.
Ergebnis: Für denselben Lieferanten können z. B. Bestellantworten im ALSO-Format und Rechnungen im ZUGFeRD-Format parallel konfiguriert und verarbeitet werden.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-architecture.md` (Enum-Definitionen im Original-Code zitiert) - Begründung: Direkte Übernahme der Enum-Deklarationen aus dem Quellcode laut Dokumentation.
Prüfidee: Lieferantenkonfiguration mit zwei unterschiedlichen `EdiDataType`/`ObjectKind`-Kombinationen anlegen und getrennte, korrekte Verarbeitung beider Dokumentarten prüfen.
Tracelinks: SwRS-026
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-028
Titel: EDI-Dateiblacklist-Mechanismus
Ebene: SwRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: System
Vorbedingung: EDI-Datei ist mehrfach fehlgeschlagen.
Fakt: `GetDownloadWithError(distributorI3D, objectKind)` zählt fehlgeschlagene Verarbeitungsversuche je Dateiname aus `EDIManagementLog` (Status `Exception`); Dateien mit mehr als drei Fehlversuchen werden in nachfolgenden Downloadzyklen (`Ftp_DownloadAsync`/`sFtp_DownloadAsync`) explizit übersprungen (`if (badFiles.Any(f => f.Value.Contains(file.Name))) continue;`).
Aussage: Das System soll pro EDI-Datei die Anzahl fehlgeschlagener Verarbeitungsversuche zählen und die Datei nach Überschreiten eines Schwellenwerts (3 Fehlversuche) von weiteren automatischen Verarbeitungsversuchen ausschließen.
Ergebnis: Eine dauerhaft defekte Datei blockiert nicht wiederholt Systemressourcen und Log-Volumen durch endlose erneute Verarbeitungsversuche.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-import-rules.md` (konkrete SQL-Abfrage und Codezeile `badFiles.Where(f => f.ID > 3)`) - Begründung: Direkt zitierter Quellcode mit konkretem Schwellenwert.
Prüfidee: Testdatei erzeugen, die 4-mal hintereinander eine Exception auslöst; Datei darf beim 5. Downloadzyklus nicht mehr verarbeitet werden, bleibt aber im Log sichtbar.
Tracelinks: SyRS-022
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-029
Titel: InvoiceZugferdBL Feldmapping-Engine
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Rechnung/Gutschrift ist final erstellt.
Fakt: `InvoiceZugferdBL.cs` (`GenerateZugferdFile`, Zeilen 117-158; `GetZugferdExportItem`, Zeilen 237-434; `DoGenerateZugferdXRechnungXmlDocument`, Zeilen 727-750; `GetTaxCategoryCode`/`GetTaxExemptionReason`, Zeilen 1369-1400) mappt interne Belegfelder (`IBookKeepingReceipt`, `ReceiptReceiver`, `BookKeepingReceiptItem`, `Mandator`, `Branch`) auf die ZUGFeRD-/XRechnung-XML-Struktur inkl. Steuerkategorie-Ableitung und Bankverbindungsauswahl.
Aussage: Das System soll die vollständige Ableitung aller ZUGFeRD-/XRechnung-Pflichtfelder (Verkäufer, Käufer, Steuerkategorien, Zahlungsbedingungen, Positionsdaten) aus den internen Belegentitäten in einer zentralen, versionsfähigen Mapping-Komponente kapseln.
Ergebnis: Für jede unterstützte ZUGFeRD-/XRechnung-Version wird aus denselben internen Belegdaten eine versionskonforme XML-Struktur erzeugt.
Belege:
- [PRIMÄR] `docs/reference/zugferd-field-mapping.md` (vollständige Feld-für-Feld-Mapping-Tabelle mit exakten Codezeilenreferenzen) - Begründung: Höchster Detailgrad der verfügbaren Dokumentation, direkte Zeilenverweise auf Quellcode.
Prüfidee: Rechnung mit Skonto-Zahlungsbedingung erzeugen; generierte XML muss BR-DE-18-konforme Skonto-Beschreibung inkl. korrekter Zeilenumbrüche (`&#xD;`) enthalten.
Tracelinks: StRS-015, SyRS-023, SyRS-024
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-030
Titel: EbInterfaceLogic (österreichisches Rechnungsformat)
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Rechnung für österreichischen Kunden/Mandanten ist zu exportieren.
Fakt: `Centron.Api.EbInterface/EbInterfaceLogic.cs` konvertiert eine interne `ReceiptInfo` in ebInterface-4.3-konforme XML (Namespace `http://www.ebinterface.at/schema/4p3/`).
Aussage: Das System soll für den österreichischen Markt Rechnungen zusätzlich zum ZUGFeRD-Format im landesspezifischen ebInterface-Standard exportieren können.
Ergebnis: Eine für den österreichischen E-Rechnungsversand vorgesehene Rechnung kann als ebInterface-konforme Datei erzeugt werden.
Belege:
- [SEKUNDÄR] `src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs` - Begründung: Eigenständige, klar abgegrenzte Konverterklasse laut Agentenrecherche.
Prüfidee: Rechnung exportieren und resultierende XML gegen das ebInterface-4.3-XSD-Schema validieren.
Tracelinks: StRS-015
Konsolidierung: Kandidat: ZUGFeRD- (SwRS-029) und ebInterface-Export (SwRS-030) bilden zwei unabhängige Implementierungen für die fachlich verwandte Aufgabe "elektronische Rechnung erzeugen" – im Zielsystem auf eine gemeinsame E-Invoicing-Abstraktion mit länderspezifischen Profilen konsolidierbar.
Status: belegt
```
```
ID: SwRS-031
Titel: ScheduleBL.SyncByGraphV2/SyncOldSchedule
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Exchange-Online-Anbindung ist aktiv.
Fakt: `ExchangeSyncService` (`src/webservice/Centron.Host/AspNetCore/HostedServices/ExchangeSyncService.cs`) ruft im Standardintervall von 60 Sekunden `ScheduleBL.SyncByGraphV2()` (Outlook→Nexus, Microsoft-Graph-Delta-Abfrage) und `ScheduleBL.SyncOldSchedule()` (Nexus→Outlook, für Termine ohne `MailEntryID`) auf.
Aussage: Das System soll Terminänderungen zwischen c-entron und Exchange Online über einen inkrementellen Delta-Abgleich (Microsoft Graph Delta-Query) synchronisieren, um nicht bei jedem Zyklus den vollständigen Kalender neu abfragen zu müssen.
Ergebnis: Nur seit dem letzten Abgleich geänderte Termine werden übertragen; ein vollständiger Kalenderabgleich erfolgt nur bei Erstsynchronisation.
Belege:
- [PRIMÄR] `docs/features/exchange-sync-bugprotokoll.md` (Abschnitt "Sync-Architektur") - Begründung: Konkrete Methodennamen und Architekturbeschreibung mit Dateipfad.
Prüfidee: Einzelnen Termin in Outlook ändern und Netzwerkverkehr/Log des nächsten Sync-Zyklus prüfen: nur der geänderte Termin darf übertragen werden, nicht der gesamte Kalender.
Tracelinks: StRS-021, SyRS-027
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-032
Titel: IsHelpdeskSchedule Source-of-Truth-Schutzregel
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Termin ist ein Helpdesk-Zeiterfassungstermin (`ObjectType = HelpdeskTimerClass` oder `HelpdeskClass`).
Fakt: `IsHelpdeskSchedule(Schedule schedule)` identifiziert Helpdesk-gebundene Termine; `UpdateScheduleByGraph()` überschreibt `DateStart`/`DateEnd` solcher Termine nicht mit aus Exchange zurückgelieferten Werten; `SyncOldSchedule()` schließt Helpdesk-Termine explizit von der Weiterleitung an Exchange über diesen Pfad aus.
Aussage: Das System soll für Helpdesk-Zeiterfassungstermine c-entron als alleinige maßgebliche Datenquelle (Source of Truth) behandeln und jede Rücküberschreibung von Datum/Uhrzeit aus Exchange technisch verhindern.
Ergebnis: Eine manuelle Änderung von Datum/Uhrzeit eines Helpdesk-Zeittermins direkt in Outlook wird beim nächsten Sync-Zyklus nicht in c-entron übernommen.
Belege:
- [PRIMÄR] `docs/features/exchange-sync-bugprotokoll.md` (Ticket 164020, 158813; konkreter Code `if (!this.IsHelpdeskSchedule(schedule)) { schedule.DateStart = ...; }`) - Begründung: Durch QS-Testfälle verifizierte, im Code umgesetzte Schutzregel.
Prüfidee: Helpdesk-Zeittermin in c-entron anlegen, Sync abwarten, Termin in Outlook manuell auf anderes Datum ändern, erneut synchronisieren → c-entron-Datensatz muss unverändert bleiben (siehe StRS-021 Prüfidee).
Tracelinks: StRS-021, SwRS-031
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-033
Titel: DataQualityService Hintergrundaufgabenliste
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Webservice läuft, stündlicher Zyklus ist erreicht.
Fakt: `DataQualityService.ExecuteAsync` führt sequenziell u. a. `TicketPatternUpdateCustomerMappingsFilter`, `DirectoryCheckBL.ExecuteDirectoryCheck()`, `CentronNotificationsBL.CleanupCentronNotifications()`, `AccountBL.CheckAndRepairAccountTypeToAccountsTable()`, `HelpdeskTimerBL.DataQualityUpdateMissingHelpdeskTimerProperties()`, `SecondStockArticleBL.DataQualityCleanupSecondaryStockArticles()` aus; jede Aufgabe läuft in eigener `BLSession`, ist einzeln try-catch-isoliert und wird bei Abbruchanforderung zwischen den Aufgaben unterbrochen.
Aussage: Das System soll eine feste, erweiterbare Liste von Datenkorrektur- und Aufräumaufgaben stündlich automatisiert und fehlerisoliert ausführen.
Ergebnis: Datenintegritätsprobleme (fehlende Fremdschlüssel, verwaiste Zuordnungen) werden auch ohne manuellen Eingriff innerhalb einer Stunde selbstständig behoben.
Belege:
- [PRIMÄR] `docs/Background Service/DataQualityService.md` (vollständige Aufgabenliste mit BL-Methodenreferenzen) - Begründung: Vollständig dokumentierte, im Code umgesetzte Aufgabenliste.
Prüfidee: Fehlende `AccountI3D`-Zuordnung in einem Todo-Eintrag künstlich erzeugen; nach einem Ausführungszyklus muss `ToDoBL.DataQualityFillAccountI3D()` den Wert korrigiert haben.
Tracelinks: SyRS-025
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-034
Titel: ModuleRegistration/ICentronAppModuleController Rechteprüfung je Modul
Ebene: SwRS
Typ: Sicherheit
Akteur: System (WPF-Client)
Vorbedingung: Benutzer meldet sich am WPF-Client an.
Fakt: `ModuleRegistration.IsModuleAvailable<T>()` prüft `CentronCache.Instance.CurrentUserAppRights` gegen die für ein Modul über `ModuleRegistrationItem.For<TController>(() => Helper.HasRights(...))` deklarierten Rechte sowie optional gegen `ModuleFeatures`-Freischaltflags (Feature-Flag für unfertige Module) und Lizenzprüfung (`LicenseManager.Instance.HasLicense`).
Aussage: Das System soll die Sichtbarkeit jedes Moduls im Modulmenü des Desktop-Clients aus drei unabhängigen Bedingungen ableiten: zugewiesenes Benutzerrecht, aktivierte Lizenz und (für unfertige Module) ein Feature-Flag.
Ergebnis: Ein Modul erscheint im Modulmenü nur, wenn alle drei zutreffenden Bedingungen erfüllt sind; fehlt eine, ist das Modul für den Benutzer nicht sichtbar.
Belege:
- [PRIMÄR] `src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs` (`IsModuleAvailable<T>()`, `GetRightsForModule()`, `GetPersonalSettings()`) - Begründung: Zentrale, im Code durchgesetzte Sichtbarkeitslogik laut Agentenrecherche.
Prüfidee: Modul mit Recht X und Lizenz Y konfigurieren; Benutzer mit Recht, aber ohne Lizenz → Modul nicht sichtbar; Benutzer mit Lizenz, aber ohne Recht → Modul nicht sichtbar.
Tracelinks: StRS-016, StRS-017, SyRS-011, SwRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-035
Titel: DeveloperSecurity Mailversand-Schutz (DEBUG)
Ebene: SwRS
Typ: Sicherheit
Akteur: System (DEBUG-Build)
Vorbedingung: Anwendung läuft als DEBUG-Build.
Fakt: `DeveloperSecurity.cs` ersetzt in DEBUG-Builds jede externe (nicht auf `nexoware.com` endende) E-Mail-Adresse vor dem Versand durch `test@nexoware.com`; internes Verhalten ist über die Property `AllowSendingEmailToExternalAddresses` deaktivierbar; in RELEASE-Builds ist dieser Mechanismus nicht aktiv.
Aussage: Das System soll ausschließlich im DEBUG-Kompilat einen automatischen Adress-Ersatzmechanismus für externe E-Mail-Empfänger bereitstellen, um versehentliche Testmails an reale Kunden während der Entwicklung zu verhindern.
Ergebnis: Ein in einer lokalen Entwicklungsumgebung ausgelöster Testversand an eine beliebige externe Adresse erreicht immer nur die interne Testadresse.
Belege:
- [PRIMÄR] `docs/reference/security/developer-security.md` (Verweis auf konkrete Implementierungsdatei und Property) - Begründung: Konkret benannte Implementierung mit eindeutigem Verhalten.
Prüfidee: In DEBUG-Konfiguration Mailversand an fiktive externe Adresse `kunde@fremdefirma.de` auslösen; tatsächlicher SMTP-Empfänger muss `test@nexoware.com` sein.
Tracelinks: SyRS-028
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-036
Titel: CentronWcfBridge Legacy-Endpunkt-Mapping
Ebene: SwRS
Typ: Schnittstelle
Akteur: System
Vorbedingung: -
Fakt: `CentronWcfBridge.cs` reflektiert zur Startzeit über alle mit `[WebInvoke(UriTemplate=...)]` dekorierten Methoden von `ICentronRestService` (partial interface, aufgeteilt in Dateien wie `ICentronRestService.Accounts.cs`, `ICentronRestService.Administration.cs`) und registriert je Methode zwei Minimal-API-Endpunkte (`/REST/<UriTemplate>`, komprimiert `/RESTC/<UriTemplate>`) mit eigenem `MethodHandler` für (De-)Serialisierung von DataContract-Objekten.
Aussage: Das System soll die Erschließung neuer bzw. bestehender Legacy-REST-Methoden automatisiert durch Reflexion vornehmen, sodass keine manuelle Registrierung einzelner Endpunkte im Hosting-Code notwendig ist.
Ergebnis: Eine neue Methode mit `[WebInvoke(UriTemplate="X")]` in `ICentronRestService` ist ohne weitere Hosting-Änderung automatisch unter `/REST/X` erreichbar.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/AspNetCore/WcfBridge/CentronWcfBridge.cs` - Begründung: Konkrete Reflection-basierte Implementierung laut Agentenrecherche.
Prüfidee: Neue Testmethode mit `[WebInvoke(UriTemplate="TestPing")]` hinzufügen, Neustart des Hosts, Aufruf von `/REST/TestPing` ohne weitere Codeänderung muss funktionieren.
Tracelinks: SyRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-037
Titel: GlobalExceptionFilter/LoggingInterceptor
Ebene: SwRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: System
Vorbedingung: Unbehandelte Exception tritt während eines API-Aufrufs auf.
Fakt: `GlobalExceptionFilter` (moderne Controller) loggt die Exception, ruft `DAOFactory.Instance.TryRecoverConnectionPool(exception)` auf und liefert eine generische 500-Antwort ohne Stacktrace; für den Legacy-Pfad protokolliert `LoggingInterceptor` Methodenname, Ticket und Laufzeit je Aufruf (bei aktivierter `veryDetailedWebServiceLogging`-Einstellung inkl. vollständiger Payload).
Aussage: Das System soll unbehandelte Fehler zentral abfangen, protokollieren, eine Wiederherstellung des Datenbankverbindungspools versuchen und dem Client keine internen Implementierungsdetails preisgeben.
Ergebnis: Ein interner Fehler führt nicht zum Absturz des Webservice-Prozesses und liefert dem Client keine sicherheitsrelevanten Details (Stacktrace) außerhalb der Entwicklungsumgebung.
Belege:
- [PRIMÄR] `src/webservice/Centron.Controllers/Configuration/GlobalExceptionFilter.cs`, `src/webservice/Centron.Host/AspNetCore/WcfBridge/Interception/Interceptors/LoggingInterceptor.cs` - Begründung: Konkrete Filter-/Interceptor-Implementierungen laut Agentenrecherche.
Prüfidee: Endpunkt mit provozierter NullReferenceException aufrufen (Produktionsmodus) → Antwort darf keinen Stacktrace enthalten, Fehler muss im Log erscheinen.
Tracelinks: SyRS-002
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-038
Titel: PersistedEntity.StateEnum als generisches Soft-Delete-Muster
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: -
Fakt: `PersistedEntity.cs` definiert `enum StateEnum { Existing = 0, Deleted = 1 }`; `DBEntity` (Basisklasse vieler Domänenentitäten, u. a. `CustomerBase`, `Helpdesk`) führt zusätzlich `State` (int?), `CreatedBy`/`CreatedDate`/`CreatedVersion`, `ChangedBy`/`ChangedDate`/`ChangedVersion`.
Aussage: Das System soll den Soft-Delete-Zustand einer Entität sowie deren Erstellungs-/Änderungs-Audit-Informationen einheitlich über eine gemeinsame Basisklasse (`DBEntity`) statt individuell je Entität abbilden.
Ergebnis: Eine als gelöscht markierte Entität (`State = Deleted`) bleibt in der Datenbank erhalten und kann für Audit-Zwecke rekonstruiert werden, ist aber für reguläre Abfragen ausgeblendet.
Belege:
- [PRIMÄR] `src/backend/Centron.Entities/PersistedEntity.cs` (`enum StateEnum`), `src/backend/Centron.Entities/DBEntity.cs` - Begründung: Konkrete Basisklassen laut Agentenrecherche der Entitätsschicht.
Prüfidee: Entität löschen (Soft Delete), per SQL prüfen, dass der Datensatz weiterhin existiert mit `State=1`; reguläre fachliche Abfrage darf den Datensatz nicht mehr zurückliefern.
Tracelinks: SyRS-016
Konsolidierung: Kandidat: Doppelte Soft-Delete-Modellierung – generisches `DBEntity.State` (StateEnum, ältere Entitäten) versus das in `docs/guides/database/database-conventions.md` beschriebene, neuere `IsDeleted`/`DeletedByI3D`/`DeletedDate`-Spaltenmuster (neue Tabellen). Im Zielsystem auf ein einheitliches Muster konsolidierbar.
Status: belegt
```
@@ -0,0 +1,702 @@
# System Requirements Specification (SyRS) – c-entron ERP
Diese SyRS beschreibt Systemverhalten, Schnittstellen sowie Performance-/Sicherheitsanforderungen, abgeleitet aus der technischen Analyse der Architektur (Backend-Schichten, Webservice, Nexus-Webportal, Datenbank, Betrieb). Nicht-funktionale Anforderungen sind zusätzlich mit ihrem ISO/IEC-25010-Qualitätsmerkmal gekennzeichnet.
---
```
ID: SyRS-001
Titel: Dreischichtige Architektur mit austauschbarem Zugriffspfad
Ebene: SyRS
Typ: nicht-funktional (Wartbarkeit / Übertragbarkeit, ISO 25010)
Akteur: System
Vorbedingung: -
Fakt: Jedes Modul folgt dem Muster ViewModel → `ILogic`-Interface → `BL<Modul>Logic` (Direktzugriff via NHibernate) bzw. `WS<Modul>Logic` (Webservice) → `WebServiceBL` (DTO↔Entity) → `BL` (NHibernate/DB); Verbindungstypen werden je Modul über `CentronConnectionType[]` deklariert.
Aussage: Das System soll fachliche Logik strikt in klar getrennten Schichten (ViewModel, Zugriffslogik, Web-Service-Fassade, Geschäftslogik, Datenzugriff) kapseln, sodass ein Modul wahlweise über Direktverbindung oder Webservice angesprochen werden kann, ohne dass Geschäftslogik dupliziert wird.
Ergebnis: Neue oder geänderte Geschäftsregeln müssen nur einmal in der BL-Schicht implementiert werden und wirken unabhängig vom Zugriffsweg.
Belege:
- [PRIMÄR] `docs/getting-started/general-structure.md` (Codebeispiele `IAccountContractsLogic`, `BLAccountContractsLogic`, `WSAccountContractsLogic`) - Begründung: Als verbindliche Implementierungsregel dokumentiertes, im Code wiederkehrendes Muster.
Prüfidee: Statische Codeprüfung: Für ein Stichprobenmodul existieren `I*Logic`, `BL*Logic`, `WS*Logic` mit identischer Methodensignatur.
Tracelinks: StRS-030
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-002
Titel: Einheitliches Fehler-/Ergebnisprotokoll über alle Schichten
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: System
Vorbedingung: -
Fakt: BL-Methoden liefern `Result`/`Result<T>` mit Status `Success/Error/Warning`; an der Webservice-Grenze erfolgt Übersetzung in `Response`/`Response<T>` mit Status `Success/Failed` (Warning wird zu Success gemappt).
Aussage: Das System soll Operationsergebnisse konsistent über ein einheitliches Result-/Response-Objektmodell mit Status, Nachricht und optionalem Fehlercode kommunizieren, statt Exceptions als regulären Kontrollfluss zu nutzen.
Ergebnis: Jeder Aufruf einer Geschäftsoperation liefert ein einheitlich auswertbares Ergebnisobjekt; Aufrufer können Erfolg/Warnung/Fehler ohne Try-Catch unterscheiden.
Belege:
- [PRIMÄR] `src/backend/Centron.Interfaces/Results/Result.cs`, `src/webservice/Centron.WebServices.Core/Messages/Response.cs` - Begründung: Konkrete, im gesamten Backend verwendete Klassen (laut Dokumentation Kernbestandteil, mehrfach in anderen Agenten-Berichten referenziert, u. a. `OposBL`, `DunningBL`, alle WebServiceBL-Klassen).
Prüfidee: BL-Methode mit provoziertem Fehler aufrufen; Response muss `StatusCode.Failed` mit aussagekräftiger `Message` liefern, kein unbehandelter Exception-Durchschlag zum Client.
Tracelinks: StRS-030
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-003
Titel: REST-Webservice als zentrale Systemschnittstelle
Ebene: SyRS
Typ: Schnittstelle
Akteur: WPF-Client, Nexus-Webportal, Outlook-Add-in, externe Anwendungen
Vorbedingung: -
Fakt: Selbst gehosteter ASP.NET-Core-Prozess (`Centron.Host`), Kestrel unter Linux/HttpSys unter Windows; kombiniert legacy WCF-Bridge-Endpunkte (`/REST/...`, `/RESTC/...`) mit modernen versionierten Controllern (`v1/...`).
Aussage: Das System soll sämtliche Client-Anwendungen (Desktop, Web, Outlook-Add-in, Drittsysteme) über eine zentrale, selbst gehostete Webservice-Schicht mit einheitlicher Authentifizierung bedienen.
Ergebnis: Alle Clients erreichen dieselbe Geschäftslogik über HTTP(S)-Endpunkte, unabhängig vom Betriebssystem des Clients.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/CentronHost.cs` - Begründung: Konkrete Host-Konfiguration (Kestrel/HttpSys, Routing, Auth) laut Agentenrecherche.
Prüfidee: Gleichen Endpunkt von WPF-Client und einer unabhängigen HTTP-Anfrage (z. B. curl) mit gültigem Ticket aufrufen; identisches Ergebnis erwarten.
Tracelinks: StRS-002, StRS-010, StRS-018, StRS-022
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-004
Titel: Legacy-WCF-Bridge-Kompatibilität
Ebene: SyRS
Typ: Schnittstelle
Akteur: WPF-Client (Bestandsclient)
Vorbedingung: -
Fakt: `CentronWcfBridge.cs` reflektiert über `ICentronRestService`-Methoden mit `[WebInvoke(UriTemplate=...)]` und bildet sie manuell auf ASP.NET-Core-Minimal-Endpunkte (`MapPost("/REST"+uri, ...)`) ab, inkl. eigenem Interceptor-basiertem Auth-/Logging-Stack (Castle DynamicProxy).
Aussage: Das System soll die historisch gewachsene WCF-artige REST-Schnittstelle (Data-Contract-Objekte, `UriTemplate`) technologisch unter ASP.NET Core weiterbetreiben, um Kompatibilität mit dem bestehenden WPF-Client ohne dessen Neuentwicklung sicherzustellen.
Ergebnis: Alle in `ICentronRestService` deklarierten Altmethoden bleiben unter `/REST/<UriTemplate>` und `/RESTC/<UriTemplate>` (komprimierte Variante) erreichbar.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/AspNetCore/WcfBridge/CentronWcfBridge.cs` - Begründung: Konkrete, reflektionsbasierte Bridge-Implementierung laut Agentenrecherche.
Prüfidee: Bestandsmethode aus `ICentronRestService` über `/REST/<Name>` aufrufen und Antwortformat/-inhalt gegen Erwartung prüfen.
Tracelinks: SyRS-003
Konsolidierung: Kandidat: Legacy-WCF-Bridge (SyRS-004) und moderne v1-Controller (SyRS-005) bilden zwei parallele API-Generationen für teils gleiche fachliche Funktionen (z. B. Kunden/Aufträge existieren in beiden) – zentraler Konsolidierungskandidat für die Web-/SaaS-Neuimplementierung.
Status: belegt; Workaround
```
```
ID: SyRS-005
Titel: Versionierte moderne REST-Controller
Ebene: SyRS
Typ: Schnittstelle
Akteur: Nexus-Webportal, externe Anwendungen, Drittintegrationen
Vorbedingung: -
Fakt: `Centron.Controllers` nutzt ASP.NET-Core-MVC-Controller mit `Asp.Versioning` (`VersionByNamespaceConvention`), URL-Segment-Versionierung (`v{version:apiVersion}/...`), Kebab-Case-Routentransformation.
Aussage: Das System soll für neu entwickelte Programmierschnittstellen ein versioniertes, standardkonformes REST-Muster (ASP.NET-Core-Controller, semantische Versionierung im URL-Pfad) bereitstellen.
Ergebnis: Endpunkte sind unter `/v1/<ressource>` erreichbar; künftige Breaking Changes können unter `/v2/...` parallel angeboten werden.
Belege:
- [PRIMÄR] `src/webservice/Centron.Controllers/Controllers/v1/**` (u. a. `CustomersController.cs`, `OrdersController.cs`, `ContractsController.cs`, `HelpdesksController.cs`, `AccessTokensController.cs`) - Begründung: Konkrete, im Repository vorhandene versionierte Controller-Klassen.
Prüfidee: `GET v1/customers/{id}` mit gültigem Token aufrufen und Response-Schema gegen DTO-Definition prüfen.
Tracelinks: SyRS-004
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-006
Titel: Echtzeitkommunikation über SignalR
Ebene: SyRS
Typ: Schnittstelle
Akteur: WPF-Client, Nexus-Webportal
Vorbedingung: -
Fakt: Mehrere SignalR-Hubs (`ChatHub`, `NotificationsHub`, `AvailabilityStatusHub`, `TapiClientHub`), teils zusätzlich per `SecretKeyRequirement`/`SecretKeyHandler` abgesichert.
Aussage: Das System soll Echtzeit-Benachrichtigungen (Chat, Systembenachrichtigungen, Verfügbarkeitsstatus, Telefonie-Events) über eine bidirektionale WebSocket-/SignalR-Verbindung an verbundene Clients ausliefern.
Ergebnis: Ein serverseitiges Ereignis (z. B. neue Chat-Nachricht) wird ohne Polling zeitnah an alle betroffenen, verbundenen Clients zugestellt.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/RealTimeServices/ChatHub.cs`, `NotificationsHub.cs`, `AvailabilityStatusHub.cs`, `TapiClientHub.cs` - Begründung: Konkrete Hub-Implementierungen laut Agentenrecherche.
Prüfidee: Zwei Clients verbinden, Chat-Nachricht von Client A senden, Zustellzeit/-inhalt bei Client B prüfen.
Tracelinks: StRS-010
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-007
Titel: Sitzungsbasierte Ticket-Authentifizierung
Ebene: SyRS
Typ: Sicherheit
Akteur: WPF-Client
Vorbedingung: Benutzer hat sich erfolgreich angemeldet.
Fakt: `TicketAuthenticationHandler` validiert ein per `Authorization: Bearer <ticket>` oder Query-Parameter `access_token` übergebenes Ticket gegen `AuthenticationTicketBL.GetAuthTicketInfo`; Tickets sind laut OIDC-Doku standardmäßig 30 Minuten gültig.
Aussage: Das System soll nach erfolgreicher Anmeldung ein zeitlich begrenztes Sitzungs-Ticket ausstellen, das für nachfolgende API-Aufrufe als Authentifizierungsnachweis dient.
Ergebnis: Ein abgelaufenes oder ungültiges Ticket führt zur Ablehnung des API-Aufrufs (401).
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/AspNetCore/TicketAuthenticationHandler.cs` - Begründung: Konkrete, als Default-Scheme registrierte Authentifizierungslogik.
- [PRIMÄR] `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` (Ticket-Erstellung: `expireDate = DateTime.Now.AddMinutes(30)`) - Begründung: Konkreter, dokumentierter Gültigkeitszeitraum mit Codebeleg.
Prüfidee: Mit abgelaufenem Ticket einen geschützten Endpunkt aufrufen → Antwort 401.
Tracelinks: StRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-008
Titel: Anmeldung über OpenID Connect (Microsoft Entra ID)
Ebene: SyRS
Typ: Sicherheit
Akteur: Benutzer mit Microsoft-Konto
Vorbedingung: Azure-AD-App-Registrierung und `JwtAuthority`/`JwtAudience`-Einstellungen sind konfiguriert.
Fakt: Client erhält per MSAL ein Microsoft-ID-Token, tauscht es über `POST /jwt/login` gegen ein c-entron-Ticket; Server validiert das JWT (Signatur, Issuer, Audience, Lifetime) und sucht den Benutzer über den `oid`-Claim in `Sichbenu.OpenIdConnectSubjectIdentifier`.
Aussage: Das System soll die Anmeldung mittels Single-Sign-On über Microsoft Entra ID (Azure AD) unterstützen und dabei ein extern ausgestelltes ID-Token gegen ein internes Sitzungs-Ticket austauschen.
Ergebnis: Ein Benutzer mit verknüpftem Microsoft-Konto kann sich ohne c-entron-Passwort anmelden; ein Benutzer ohne verknüpfte `OpenIdConnectSubjectIdentifier` erhält eine Fehlermeldung.
Belege:
- [PRIMÄR] `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` (vollständiger Sequenzablauf mit Dateireferenzen: `JwtAuthController.cs`, `OpenIdConnectAuthenticator.cs`) - Begründung: Vollständig dokumentierter, mit konkreten Datei-/Klassenreferenzen belegter Sicherheitsfluss.
Prüfidee: Anmeldung mit verknüpftem Microsoft-Testkonto durchführen, gültiges Ticket erhalten; Anmeldung mit nicht verknüpftem Konto → Fehler.
Tracelinks: StRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-009
Titel: Authentifizierung über persönliche Access Tokens
Ebene: SyRS
Typ: Sicherheit
Akteur: Externe Anwendungen/Integrationen
Vorbedingung: Benutzer hat einen Access Token erstellt.
Fakt: `AccessTokensController` (JWT-geschützt) erlaubt Erstellung/Aktivierung/Deaktivierung/Löschung persönlicher Access Tokens inkl. Nutzungsprotokoll (`/logs`) und Statistiken (`/statistics`).
Aussage: Das System soll es Benutzern ermöglichen, persönliche API-Zugriffstoken für Drittanwendungen zu erstellen, zu deaktivieren und deren Nutzung nachzuvollziehen.
Ergebnis: Ein deaktivierter Access Token wird bei nachfolgenden API-Aufrufen abgelehnt; Nutzungsprotokoll zeigt historische Aufrufe.
Belege:
- [PRIMÄR] `src/webservice/Centron.Controllers/Controllers/v1/Administration/AccessTokensController.cs` - Begründung: Konkrete CRUD-/Statistik-Endpunkte laut Agentenrecherche.
Prüfidee: Access Token erstellen, damit Aufruf durchführen (Erfolg), Token deaktivieren, gleichen Aufruf wiederholen (Ablehnung).
Tracelinks: StRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-010
Titel: Zwei-Faktor-Authentifizierung (RADIUS)
Ebene: SyRS
Typ: Sicherheit
Akteur: Benutzer, RADIUS-Server
Vorbedingung: `TwoFactorAuthEnabled`/`TwoFactorAuthType=RadiusServer` ist konfiguriert.
Fakt: `WebServiceConfig.xml` unterstützt `TwoFactorAuthEnabled`/`TwoFactorAuthType`; ein dedizierter Test `RadiusMessageAuthenticationTest.cs` (`PacketTestAccessRequestWithoutClass`, `SendFlow`) verifiziert das RADIUS-Protokollverhalten; `TwoFactorAuthController` (`GET 2fa/validate`) bietet den zugehörigen Validierungsendpunkt.
Aussage: Das System soll optional eine Zwei-Faktor-Authentifizierung über einen RADIUS-Server als zusätzliche Absicherung der Anmeldung unterstützen.
Ergebnis: Bei aktivierter 2FA wird eine Anmeldung erst nach erfolgreicher RADIUS-Validierung des zweiten Faktors abgeschlossen.
Belege:
- [PRIMÄR] `tests/Centron.Tests.EndToEnd/Tests/Radius/RadiusMessageAuthenticationTest.cs` - Begründung: Automatisierter Test des RADIUS-Nachrichtenflusses belegt eine tatsächlich funktionsfähige Implementierung (nicht nur Konfigurationsschalter).
- [SEKUNDÄR] `src/webservice/Centron.Controllers/Controllers/Unversioned/TwoFactorAuthController.cs` - Begründung: Zugehöriger Validierungsendpunkt.
Prüfidee: 2FA aktivieren, Anmeldung ohne zweiten Faktor → Ablehnung; mit korrektem RADIUS-Code → Erfolg.
Tracelinks: StRS-016
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-011
Titel: Rollenbasierte Autorisierung pro Endpunkt/Funktion
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Benutzer ist authentifiziert.
Fakt: `AuthorizeUserRightAttribute`/`AuthorizeAllUserRightsAttribute`/`AuthorizeAnyUserRightAttribute` prüfen `currentUser.HasUserRight(id)` und liefern 401/403; im WPF-Client und in der BL-Schicht wird dieselbe Grundprüfung (`HasUserRight`) 318-mal in 93 Dateien eingesetzt.
Aussage: Das System soll den Zugriff auf einzelne API-Endpunkte, Module und Funktionen konsistent anhand feingranularer, pro Benutzer/Gruppe vergebener Rechte einschränken.
Ergebnis: Ein Aufruf eines rechtegeschützten Endpunkts durch einen Benutzer ohne das erforderliche Recht wird mit 401/403 abgelehnt.
Belege:
- [PRIMÄR] `src/webservice/Centron.Controllers/Authorization/AuthorizeUserRightAttribute.cs` - Begründung: Konkretes, im Code durchgesetztes Autorisierungsattribut.
- [PRIMÄR] `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` (`HasUserRight`, 318 Aufrufstellen) - Begründung: Durchgängig verwendetes Autorisierungsmuster auf BL-Ebene.
Prüfidee: Endpunkt mit `[AuthorizeUserRight(X)]` durch Benutzer ohne Recht X aufrufen → 401/403; mit Recht X → Erfolg.
Tracelinks: StRS-016, StRS-013, StRS-014
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-012
Titel: Filialbezogene Zugriffsisolation (Branch Isolation)
Ebene: SyRS
Typ: Sicherheit
Akteur: Benutzer mit filialbeschränktem Recht
Vorbedingung: Benutzer besitzt ein "nur eigene Filiale"-Recht (`OnlyOwnBranchRight`).
Fakt: `ReceiptSearchConfiguration` definiert je Belegtyp `ShowRight`, `OnlyOwnRight`, `OnlyOwnBranchRight`; fehlt das passende Recht, liefert `CreateSqlStatementAndParameters` `null` (keine Ergebnisse für diesen Belegtyp).
Aussage: Das System soll die Sichtbarkeit von Belegen für filialbeschränkte Benutzer serverseitig in der Suchlogik durchsetzen, nicht nur in der Benutzeroberfläche ausblenden.
Ergebnis: Ein filialbeschränkter Benutzer erhält bei einer Belegsuche ausschließlich Belege der eigenen Filiale, unabhängig vom verwendeten Client.
Belege:
- [PRIMÄR] `docs/reference/receipts/receipt-search-architecture.md` (zitiert `ReceiptSearchConfiguration.OnlyOwnBranchRight`, `ReceiptSearcher.CreateSqlStatementAndParameters`) - Begründung: Konkrete, serverseitig durchgesetzte Filterlogik.
Prüfidee: Filialbeschränkter Benutzer sucht Belege anderer Filialen über direkten API-Aufruf (nicht UI) → Ergebnis darf keine fremden Filialbelege enthalten.
Tracelinks: StRS-027, SyRS-011
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-013
Titel: Belegstatusmaschine (Active/Completed/Canceled)
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Beleg existiert.
Fakt: `src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs` definiert die Zustände `Active`, `Completed`, `Canceled`; `ReceiptBL.cs` setzt/liest diese Zustände (`receipt.State = ReceiptState.Completed`, Prüfungen `if (receipt.State != ReceiptState.Canceled)`).
Aussage: Das System soll jeden Beleg (Angebot, Auftrag, Lieferschein, Rechnung, Gutschrift, Vertrag) einer von drei einheitlichen Statuswerten zuordnen und Statuswechsel nur über definierte BL-Methoden zulassen.
Ergebnis: Ein stornierter Beleg (`Canceled`) kann nicht mehr in nachgelagerte Prozesse (z. B. Rechnungsstellung) einfließen.
Belege:
- [PRIMÄR] `src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs` - Begründung: Enum-Definition der drei Statuswerte.
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs` (Zeilen ~3274, ~4148, ~4178, ~4936) - Begründung: Konkrete Statusprüfungen/-zuweisungen im Code.
Prüfidee: Beleg stornieren, danach Versuch, ihn in einen Folgebeleg zu wandeln → muss vom System verhindert werden.
Tracelinks: StRS-001, StRS-003, StRS-005, StRS-007, StRS-008, StRS-010, StRS-011, StRS-018, StRS-023, StRS-024, StRS-025, StRS-026, StRS-029, SwRS-004
Konsolidierung: Kandidat: Die Legacy-Spiegeltabellen (`Entities/DbEntities/AufKopf.cs` u. a.) führen ein rein numerisches `Status`-Feld (kein Enum) parallel zum modernen `ReceiptState`-Enum – im Zielsystem auf ein einziges Statusmodell konsolidierungsbedürftig.
Status: belegt
```
```
ID: SyRS-014
Titel: Selbstprüfender Belegtyp-Übergangsgraph
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Anwendung startet.
Fakt: `IReceiptSpecificLogic` deklariert `CanBeForwardedFrom()`/`CanBeForwardedInto()` je Belegtyp; `SpecificLogics.ValidateConsistency()` prüft beim Start, dass alle Vorwärts-/Rückwärtsreferenzen symmetrisch sind, und wirft andernfalls eine `ApplicationException`.
Aussage: Das System soll den Übergangsgraphen zwischen Belegtypen (welcher Beleg aus welchem hervorgehen darf) als konsistentes, beim Systemstart automatisch validiertes Modell führen.
Ergebnis: Eine inkonsistente Konfiguration des Übergangsgraphen (z. B. Beleg A erlaubt Übergang zu B, aber B erlaubt keinen Ursprung aus A) verhindert den erfolgreichen Systemstart.
Belege:
- [PRIMÄR] `src/backend/Centron.BL/Sales/Receipts/SpecificLogics.cs` (Zeilen ~148–170, `ValidateConsistency`) - Begründung: Konkrete, beim Start ausgeführte Konsistenzprüfung mit Exception bei Verletzung.
Prüfidee: Testweise inkonsistente `CanBeForwardedFrom`/`CanBeForwardedInto`-Konfiguration einspielen → Systemstart muss mit `ApplicationException` fehlschlagen.
Tracelinks: StRS-001, StRS-005, SwRS-002, SwRS-003
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-015
Titel: Vollständiger Audit-Trail durch Kopf-/Positions-Versionierung
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit / Sicherheit, ISO 25010)
Akteur: System
Vorbedingung: Beleg wird gespeichert.
Fakt: Je Belegtyp existiert eine 1:1-Kopie-Versionstabelle (`*KopfVersions`/`*PosVersions`); jede Spalte der Basistabelle muss zwingend auch in der Versionstabelle vorhanden sein, sonst schlägt `AssetHeadDAO.SaveAssetVersion` zur Laufzeit fehl.
Aussage: Das System soll bei jeder Beleg-Speicherung eine vollständige, strukturidentische Historienkopie des vorherigen Zustands anlegen, um lückenlose Nachvollziehbarkeit von Änderungen zu gewährleisten.
Ergebnis: Zu jedem Beleg lässt sich der Stand zu jedem früheren Speicherzeitpunkt rekonstruieren.
Belege:
- [PRIMÄR] `docs/reference/receipts/receipts-backend-architecture.md` (Abschnitt "Version Tables: 1:1 Copies of Original Tables", zitiert `AssetHeadDAO.SaveAssetVersion`) - Begründung: Konkrete, technisch erzwungene Struktur mit dokumentiertem Fehlerverhalten bei Abweichung.
Prüfidee: Beleg mehrfach ändern und speichern; Anzahl und Inhalt der Einträge in `<Typ>KopfVersions` gegen die Änderungshistorie prüfen.
Tracelinks: StRS-001, SwRS-005
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-016
Titel: Einheitliche Datenbank-Schemakonventionen
Ebene: SyRS
Typ: Daten
Akteur: System / Entwickler
Vorbedingung: -
Fakt: Verbindliche Konventionen: Primärschlüssel `I3D` (`int IDENTITY(1,1)`, clustered), Fremdschlüsselsuffix `I3D`, Pflicht-Audit-Spalten (`CreatedByI3D`, `CreatedDate`, `ChangedByI3D`, `ChangedDate`), Soft-Delete-Muster (`IsDeleted`, `DeletedByI3D`, `DeletedDate`), `nvarchar` statt `varchar`, Schema `dbo`.
Aussage: Das System soll für alle (neuen) Datenbanktabellen ein einheitliches Schema-Muster (Primärschlüssel, Fremdschlüsselnamensgebung, Audit-Spalten, Soft-Delete) verbindlich durchsetzen.
Ergebnis: Neue Tabellen sind ohne zusätzliche Dokumentation anhand ihrer Spaltennamen konsistent interpretierbar (z. B. Fremdschlüssel immer per `*I3D`-Suffix erkennbar).
Belege:
- [PRIMÄR] `docs/guides/database/database-conventions.md` - Begründung: Verbindlich dokumentierte Konvention mit konkreten Beispieltabellen (`AccountDevices`, `AccountDeviceUris`).
- [PRIMÄR] `src/backend/Centron.DAO/Repositories/Administration/CentronConfigDb/CentronConfigurationDbRepository.cs` (Zeilen ~393–420, `PRIMARY KEY CLUSTERED`, `FOREIGN KEY` mit `WITH CHECK`) - Begründung: Tatsächlich ausgeführte DDL, die die Konvention umsetzt.
Prüfidee: Stichprobenprüfung mehrerer neuerer Tabellen (z. B. `HelpdeskCreationTemplate`) auf Einhaltung aller Konventionspunkte.
Tracelinks: -
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-017
Titel: Versionsgesteuerter Datenbank-Migrationsmechanismus
Ebene: SyRS
Typ: nicht-funktional (Wartbarkeit, ISO 25010)
Akteur: System (Anwendungsstart), Entwickler
Vorbedingung: Anwendungsversion wurde erhöht.
Fakt: 764 Klassen `ScriptMethod<Nummer>.cs` unter `Centron.BL/Administration/Scripts/ScriptMethods/Scripts/` implementieren `BaseScriptMethod` und liefern über `GetSqlQueries()` idempotente SQL-Anweisungen (häufig via `ScriptHelpers.AddColumnIfNotExists`/`AddTableIfNotExists`/`AddForeignKeyIfNotExists`), verknüpft mit einer `ApplicationVersion`.
Aussage: Das System soll Datenbankschema-Änderungen ausschließlich über versionierte, beim Anwendungsstart automatisch ausgeführte, idempotente Migrationsskripte vornehmen (kein manuelles Schema-Deployment).
Ergebnis: Ein Upgrade auf eine neue Anwendungsversion führt alle noch nicht angewendeten Skripte automatisch und reproduzierbar aus.
Belege:
- [PRIMÄR] `docs/guides/database/create-scripts.md`, `docs/reference/database/script-rules.md` - Begründung: Verbindlich dokumentierter Mechanismus mit Codebeispielen (`ScriptMethod11699.cs` u. a.).
- [PRIMÄR] 764 Dateien unter `src/backend/Centron.BL/Administration/Scripts/ScriptMethods/Scripts/` (durch Agentenrecherche gezählt) - Begründung: Tatsächlicher Umfang des Mechanismus im Code.
Prüfidee: Anwendung mit älterer DB-Version starten und Ausführung aller ausstehenden Skripte in der Konsolenausgabe verifizieren (vgl. Testvorgehen in `docs/guides/database/create-scripts.md`).
Tracelinks: -
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-018
Titel: Lizenzprüfung als Systemzugriffsvoraussetzung
Ebene: SyRS
Typ: Sicherheit
Akteur: System
Vorbedingung: Anwendung/Modul wird aufgerufen.
Fakt: `LicenseManager.Instance.HasLicense(...)`/`GetLicenseCount(...)` werden zur Steuerung von Modul-Sichtbarkeit (`ModuleRegistration.IsModuleAvailable`) und Login-Berechtigung (`ApplicationKind`) verwendet; Lizenzen besitzen GUID, optionalen Zähler, Ablaufdatum, Versionsgrenze.
Aussage: Das System soll den Zugriff auf Anwendungen (Login) und Einzelfunktionen (Module) zentral gegen eine GUID-basierte Lizenzprüfung mit optionaler Mengen- und Zeitbegrenzung absichern.
Ergebnis: Eine abgelaufene oder mengenmäßig ausgeschöpfte Lizenz verhindert Login bzw. Nutzung der betroffenen Funktion.
Belege:
- [PRIMÄR] `docs/reference/security/licensing-system.md` (Codebeispiele `LicenseManager.Instance.HasLicense`, `GetLicenseCount`) - Begründung: Dokumentiertes, im Code verwendetes Prüfmuster.
Prüfidee: Lizenz mit `count=0` bzw. abgelaufenem Datum simulieren → betroffene Funktion muss verweigert werden.
Tracelinks: StRS-017
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-019
Titel: Mehrsprachige Benutzeroberfläche (Deutsch/Englisch)
Ebene: SyRS
Typ: nicht-funktional (Übertragbarkeit, ISO 25010)
Akteur: Benutzer
Vorbedingung: -
Fakt: Separate `.resx`-Ressourcendateien je Schicht (`LocalizedStrings.resx` = Deutsch/Standard, `LocalizedStrings.en.resx` = Englisch) in WPF-UI und BL; Sprachwahl über `CultureInfo.CurrentUICulture`, bei Webservice-Aufrufen über `Accept-Language`-Header.
Aussage: Das System soll alle benutzersichtbaren Texte standardmäßig auf Deutsch und zusätzlich auf Englisch bereitstellen, wobei Deutsch die verbindliche Ausgangssprache für neue Texte ist.
Ergebnis: Bei Umschaltung der UI-Kultur auf Englisch werden alle vorhandenen Textressourcen in Englisch angezeigt; für neue Texte ohne Übersetzung wird der deutsche Standardtext angezeigt (Fallback).
Belege:
- [PRIMÄR] `docs/guides/ui/localization.md` (konkrete Ressourcenpfade, Namenskonvention `[ClassName]_[MethodName]_[Description]`) - Begründung: Verbindlich dokumentiertes, im Code umgesetztes Lokalisierungsmuster.
Prüfidee: UI-Kultur auf Englisch umstellen, Stichprobe von Dialogen auf vollständige Übersetzung prüfen.
Tracelinks: -
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-020
Titel: Verbindliche UTF-8-BOM-Dateikodierung
Ebene: SyRS
Typ: nicht-funktional (Wartbarkeit, ISO 25010)
Akteur: Entwickler / Build-System
Vorbedingung: -
Fakt: Für alle `.cs`- und `.xaml`-Dateien ist UTF-8 mit BOM vorgeschrieben, um Sonderzeichen und Merge-Konflikte zu vermeiden.
Aussage: Das System soll für sämtliche Quelltextdateien eine einheitliche Zeichenkodierung (UTF-8 mit BOM) sicherstellen, um korrekte Darstellung deutscher Sonderzeichen (Umlaute, ß) durchgängig zu gewährleisten.
Ergebnis: Deutsche Sonderzeichen in Quelltext, Ressourcendateien und UI werden in allen Umgebungen korrekt dargestellt.
Belege:
- [SEKUNDÄR] `docs/getting-started/general-structure.md` (Abschnitt "File Encoding Requirements") - Begründung: Dokumentierte Konvention, jedoch nicht durch ein automatisiertes Prüfwerkzeug im Repository verifiziert (kein Encoding-Linter gefunden).
Prüfidee: Stichprobenprüfung der Byte-Order-Mark in neu committeten `.cs`-Dateien.
Tracelinks: -
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-021
Titel: Mehrformatiger EDI-Dokumentenaustausch mit Lieferanten
Ebene: SyRS
Typ: Schnittstelle
Akteur: Externe Lieferanten-EDI-Server
Vorbedingung: Lieferant ist für EDI konfiguriert.
Fakt: `SupplierEdiBL` (partial classes je Lieferant) unterstützt OpenTrans 2.1, ALSO, ALSO CH, Herweck, Komsa, Alltron, ZUGFeRD; Verbindung per FTP/SFTP/FTPS; Dateien werden alle 30 Minuten automatisiert abgerufen.
Aussage: Das System soll Bestellantwort-, Liefer- und Rechnungsdokumente in mehreren lieferantenspezifischen EDI-Formaten über gesicherte Protokolle (FTPS/SFTP) automatisiert austauschen.
Ergebnis: Neue Dateien im konfigurierten Format werden innerhalb des 30-Minuten-Intervalls abgeholt und verarbeitet.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-architecture.md`, `docs/reference/edi/edi-import-rules.md` (konkrete Klassen `EdiDownloadService`, `EDIConnectBL`, Intervall "every 30 minutes") - Begründung: Vollständig dokumentierter, technisch belegter Mechanismus.
Prüfidee: Testdatei auf konfiguriertem SFTP-Server ablegen, 30-Minuten-Zyklus abwarten, Verarbeitung im `EDIManagementLog` prüfen.
Tracelinks: StRS-006
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-022
Titel: Fehlerresilienz bei EDI-Verarbeitung (Datei-Blacklist)
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: System
Vorbedingung: Eine EDI-Datei ist mehrfach fehlgeschlagen.
Fakt: Dateien mit mehr als 3 protokollierten Exceptions (`EDIManagementLog`, `State = Exception`) werden von weiteren Verarbeitungsversuchen ausgeschlossen (`badFiles.Where(f => f.ID > 3)`).
Aussage: Das System soll wiederholt fehlschlagende EDI-Dateien nach einer definierten Fehleranzahl automatisch von erneuten Verarbeitungsversuchen ausschließen, um Endlos-Fehlerschleifen und unnötige Systemlast zu vermeiden.
Ergebnis: Eine dauerhaft fehlerhafte Datei wird nach dem vierten Fehlschlag nicht mehr automatisch erneut verarbeitet, bleibt aber protokolliert und für manuelle Behebung sichtbar.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-import-rules.md` (konkrete SQL-Abfrage gegen `EDIManagementLog`, Schwellenwert `f.ID > 3`) - Begründung: Konkrete, im Code durchgesetzte Schwellenwertlogik.
Prüfidee: Datei erzeugen, die 4-mal hintereinander einen Parsing-Fehler auslöst; fünfter Verarbeitungsversuch darf nicht mehr erfolgen.
Tracelinks: StRS-006, SyRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-023
Titel: Normkonforme E-Invoicing-Generierung
Ebene: SyRS
Typ: Schnittstelle
Akteur: System, Empfänger (Kunde/Behörde)
Vorbedingung: Rechnung ist final erstellt.
Fakt: `InvoiceZugferdBL` erzeugt ZUGFeRD/XRechnung-XML in vier Versionsgruppen (1.0 bis 2.1/XRechnung 3.0.1); Tax-Category-Codes (S/E/K/G/AE) und Steuerbefreiungstexte werden regelbasiert abgeleitet.
Aussage: Das System soll elektronische Rechnungen in strukturierten, versionsspezifisch konfigurierbaren XML-Formaten nach ZUGFeRD-/XRechnung-Standard erzeugen, inklusive korrekter Steuerkategorie- und Befreiungslogik.
Ergebnis: Die erzeugte XML-Datei ist gegen die jeweilige ZUGFeRD-/XRechnung-Version schemakonform (z. B. mittels KOSIT-Validator prüfbar).
Belege:
- [PRIMÄR] `docs/reference/zugferd-field-mapping.md` (vollständige Feldtabellen, Codereferenzen `InvoiceZugferdBL.cs:117-158`, `:1369-1400`) - Begründung: Detailliert dokumentierte, code-referenzierte Generierungslogik.
Prüfidee: Rechnung mit Reverse-Charge-Position erzeugen; generierte XML muss Tax-Category "AE" und den vorgeschriebenen Befreiungstext enthalten.
Tracelinks: StRS-015
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-024
Titel: Toleranzprüfung bei E-Invoicing-Summenabgleich
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: ZUGFeRD-Export wird ausgelöst.
Fakt: System validiert, dass die Summe der Positionsnetto-/-bruttopreise mit dem Kopfbetrag übereinstimmt; bei Abweichung ≤ 3,00 wird eine Warnung geloggt und der Wert korrigiert, bei Überschreitung schlägt der Export fehl.
Aussage: Das System soll vor dem Export einer elektronischen Rechnung die rechnerische Konsistenz zwischen Kopf- und Positionssummen prüfen und den Export bei signifikanten Abweichungen verhindern.
Ergebnis: Eine Rechnung mit einer Summenabweichung von mehr als 3,00 Währungseinheiten kann nicht als ZUGFeRD-Datei exportiert werden.
Belege:
- [PRIMÄR] `docs/reference/zugferd-field-mapping.md` (Abschnitt "Validation Tolerances", "±3.00") - Begründung: Konkret dokumentierter Schwellenwert mit unterschiedlichem Verhalten (Warnung vs. Fehler).
Prüfidee: Testrechnung mit künstlicher Summenabweichung von 5,00 erzeugen → ZUGFeRD-Export muss mit Fehler abbrechen.
Tracelinks: StRS-015, SyRS-023
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-025
Titel: Periodischer Hintergrunddienst zur Datenqualitätssicherung
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: System
Vorbedingung: Webservice läuft.
Fakt: `DataQualityService` (ASP.NET-Core `BackgroundService`) führt stündlich eine feste Liste von Wartungsaufgaben aus (u. a. Bereinigung von Benachrichtigungen, Reparatur von `AccountTypeToAccounts`, Nachpflege fehlender `AccountI3D` bei Todos), jede Aufgabe einzeln try-catch-isoliert und mit eigener kurzlebiger DB-Session.
Aussage: Das System soll wiederkehrende Datenkonsistenz- und Aufräumaufgaben automatisiert im Hintergrund ausführen, ohne dass ein Fehler in einer Aufgabe den gesamten Wartungslauf oder den Webservice beeinträchtigt.
Ergebnis: Ein Fehler in einer einzelnen Wartungsaufgabe wird geloggt, verhindert aber nicht die Ausführung der übrigen Aufgaben im selben oder nächsten Zyklus.
Belege:
- [PRIMÄR] `docs/Background Service/DataQualityService.md` (konkrete Aufgabenliste mit BL-Methodenreferenzen, Try-Catch-Vorgabe) - Begründung: Vollständig dokumentiertes, im Code umgesetztes Verhalten.
Prüfidee: Eine Wartungsaufgabe künstlich zum Fehlschlagen bringen; nachfolgende Aufgaben im selben Zyklus müssen dennoch ausgeführt werden (Log-Analyse).
Tracelinks: -
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-026
Titel: Intervallgesteuerter EDI-Download-Hintergrunddienst
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: System
Vorbedingung: Webservice läuft.
Fakt: `EdiDownloadService` (ASP.NET-Core `BackgroundService`) läuft alle 30 Minuten (initiale Verzögerung 1 Minute nach Start); Log-Bereinigung für Einträge älter als 185 Tage erfolgt zwischen 00:00–02:00 Uhr.
Aussage: Das System soll den EDI-Abruf als eigenständigen, konfigurierbaren Hintergrunddienst mit fester Wiederholungsfrequenz betreiben, getrennt von der interaktiven Benutzeranwendung.
Ergebnis: Auch ohne aktiven Benutzer-Client werden EDI-Dokumente regelmäßig automatisch abgerufen.
Belege:
- [PRIMÄR] `docs/reference/edi/edi-import-rules.md` (Abschnitt "Execution Frequency") - Begründung: Konkret dokumentierte Zeitparameter.
Prüfidee: Webservice ohne verbundenen WPF-Client betreiben; EDI-Abruf muss dennoch planmäßig laufen (Log-Zeitstempel prüfen).
Tracelinks: StRS-006, SyRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-027
Titel: Bidirektionaler Kalender-Synchronisationsdienst
Ebene: SyRS
Typ: Schnittstelle
Akteur: System, Microsoft Exchange/Graph
Vorbedingung: Exchange-Online-Anbindung ist konfiguriert.
Fakt: `ExchangeSyncService` (HostedService, Standardintervall 60s) führt `ScheduleBL.SyncByGraphV2()` (Outlook→Nexus, Graph-API-Delta) und `ScheduleBL.SyncOldSchedule()` (Nexus→Outlook) aus; für On-Premise-Exchange-Kunden existiert laut Dokumentation ein separater, älterer EWS-Agent mit eingeschränktem Funktionsumfang.
Aussage: Das System soll Termine zwischen c-entron-Zeitplanung und Microsoft Exchange (Online via Graph-API, On-Premise via EWS) in konfigurierbarem Intervall automatisiert synchronisieren.
Ergebnis: Änderungen an Terminen werden innerhalb des Sync-Intervalls in beide Richtungen abgeglichen, wobei bekannte Graph-spezifische Funktionen (z. B. Serientermin-Kaskadenlöschung) für On-Premise-Kunden nicht verfügbar sind.
Belege:
- [PRIMÄR] `docs/features/exchange-sync-bugprotokoll.md` (Abschnitt "Sync-Architektur", "Geltungsbereich der Fixes") - Begründung: Detailliert dokumentierte Architektur mit expliziter Abgrenzung Graph vs. EWS.
Prüfidee: Termin in Outlook (Exchange Online) ändern, 60s abwarten, Änderung in Nexus/c-entron prüfen; gleichen Test für On-Premise-Exchange wiederholen und Einschränkungen verifizieren.
Tracelinks: StRS-021
Konsolidierung: nein
Status: belegt; Workaround (Doppelpfad Graph/EWS als historisch gewachsene Zwischenlösung)
```
```
ID: SyRS-028
Titel: Entwickler-Schutzmechanismus gegen versehentlichen Mailversand
Ebene: SyRS
Typ: Sicherheit
Akteur: Entwickler (DEBUG-Build)
Vorbedingung: Anwendung läuft als DEBUG-Build.
Fakt: In DEBUG-Builds werden alle externen E-Mail-Adressen (nicht auf `nexoware.com` endend) automatisch durch `test@nexoware.com` ersetzt; steuerbar über `DeveloperSecurity.AllowSendingEmailToExternalAddresses`. In RELEASE-Builds ist dieser Schutz nicht aktiv.
Aussage: Das System soll in Entwicklungs-/Debug-Umgebungen den unbeabsichtigten Versand von E-Mails an echte Kundenadressen technisch verhindern.
Ergebnis: Ein in einer DEBUG-Umgebung ausgelöster Mailversand an eine externe Adresse erreicht stattdessen eine interne Testadresse.
Belege:
- [PRIMÄR] `docs/reference/security/developer-security.md` (verweist auf `DeveloperSecurity.cs`) - Begründung: Konkret benannte Implementierungsdatei und Verhaltensbeschreibung.
Prüfidee: In DEBUG-Build Mailversand an externe Testadresse auslösen → tatsächlicher Empfänger muss `test@nexoware.com` sein.
Tracelinks: -
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-029
Titel: Fehlende Ratenbegrenzung der Webservice-API
Ebene: SyRS
Typ: Sicherheit (Lücke/Risiko, ISO 25010: Sicherheit)
Akteur: System / Angreifer
Vorbedingung: -
Fakt: Im gesamten `src/webservice`-Baum wurde keine Rate-Limiting-Middleware (`Microsoft.AspNetCore.RateLimiting` o. ä.) gefunden; zugleich ist `MaxRequestBodySize` explizit auf `null` (unbegrenzt) gesetzt, um große Datei-Uploads zu erlauben.
Aussage: `[HYPOTHESE]` Das System besitzt aktuell keinen Schutz vor übermäßig häufigen oder übergroßen Anfragen auf API-Ebene; dies stellt ein Risiko für Denial-of-Service-Angriffe oder Ressourcenerschöpfung dar. Zur Bestätigung fehlt die Prüfung, ob Ratenbegrenzung auf einer vorgelagerten Netzwerkebene (Reverse Proxy, Firewall, WAF) beim Kunden umgesetzt wird, was im Code nicht sichtbar wäre.
Ergebnis: Ohne vorgelagerten Schutz kann ein Client eine unbegrenzte Anzahl an Anfragen mit potenziell sehr großen Anfragekörpern senden.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/CentronHost.cs` (`options.MaxRequestBodySize = null`) - Begründung: Konkrete, im Code deaktivierte Größenbegrenzung.
- [KONTEXT] Fehlender Treffer für Rate-Limiting-Middleware bei gezielter Codesuche durch Recherche-Agent - Begründung: Negativbefund, kein direkter Dateibeleg möglich; daher Status HYPOTHESE für die Vollständigkeit der Aussage (evtl. Absicherung außerhalb des Repositories).
Prüfidee: Lasttest mit hoher Anfragefrequenz gegen einen ungeschützten Webservice-Endpunkt durchführen und Systemverhalten (Verfügbarkeit, Ressourcenverbrauch) beobachten.
Tracelinks: SyRS-003
Konsolidierung: nein
Status: HYPOTHESE
```
```
ID: SyRS-030
Titel: Offene CORS-Konfiguration
Ebene: SyRS
Typ: Sicherheit (Lücke/Risiko)
Akteur: System / Angreifer (Cross-Origin)
Vorbedingung: -
Fakt: `CentronHost.cs` konfiguriert CORS mit `AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()`.
Aussage: Das System soll (aktuell) Cross-Origin-Anfragen von beliebigen Ursprüngen zulassen; dies ist eine bewusste oder historisch gewachsene Öffnung, die im Zielsystem (insb. bei mandantenfähigem SaaS-Betrieb) auf konkrete, vertrauenswürdige Ursprünge eingeschränkt werden sollte.
Ergebnis: Eine beliebige Website kann клиентseitig (im Browserkontext) Anfragen an die c-entron-API stellen, sofern ein gültiges Ticket/Token vorliegt.
Belege:
- [PRIMÄR] `src/webservice/Centron.Host/CentronHost.cs` (`.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()`) - Begründung: Konkrete, im Code gesetzte Konfiguration.
Prüfidee: Cross-Origin-Testanfrage von einer Fremd-Domain mit gültigem Ticket absetzen und Antwortverhalten (CORS-Header) prüfen.
Tracelinks: SyRS-003
Konsolidierung: nein
Status: belegt; Workaround (vermutlich historisch für Outlook-Add-in-/Iframe-Einbettung erforderlich, siehe StRS-020/SwRS)
```
```
ID: SyRS-031
Titel: Unzureichend gesicherte Zugangsdaten in Container-Konfiguration
Ebene: SyRS
Typ: Sicherheit (Lücke/Risiko)
Akteur: Betreiber, Angreifer mit Repository-/Image-Zugriff
Vorbedingung: -
Fakt: `docker/compose/compose.yaml` und `docker/deploy/compose.yaml` enthalten ein hartkodiertes, schwaches SA-Passwort (`SA!password`); `docker/compose/WebServiceConfig.xml` enthält eine Klartext-Datenbank-Verbindungszeichenfolge sowie einen wiederverwendeten Base64-`SecretKey`.
Aussage: Das System soll (in der aktuellen Docker-Referenzkonfiguration) sicherstellen, dass Datenbankpasswörter, Verbindungszeichenfolgen und kryptografische Schlüssel nicht im Klartext im Versionskontrollsystem oder in Beispielkonfigurationen hinterlegt sind.
Ergebnis: Aktuell ist dies nicht der Fall: Die genannten Geheimnisse sind im Repository einsehbar, was bei unveränderter Übernahme in Produktivbetrieb ein erhebliches Sicherheitsrisiko darstellt.
Belege:
- [PRIMÄR] `docker/compose/compose.yaml`, `docker/deploy/compose.yaml` (`MSSQL_SA_PASSWORD: SA!password`) - Begründung: Konkreter, im Repository sichtbarer Klartextwert.
- [PRIMÄR] `docker/compose/WebServiceConfig.xml` (`DatabaseConnectionStringPlain`, `SecretKey`) - Begründung: Konkrete, im Repository sichtbare Klartext-Zugangsdaten.
- [KONTEXT] `docker/README.md` (Hinweis, dass die Docker-Verpackung von einem Drittanbieter "für Dokumentationszwecke" stammt und ersetzt werden kann) - Begründung: Relativiert den Befund als Demo-/Referenzkonfiguration, nicht zwingend Produktivsetup; dennoch reales Risiko bei unreflektierter Übernahme.
Prüfidee: Repository-Historie auf enthaltene Zugangsdaten scannen (z. B. mit Secret-Scanning-Tool); Empfehlung: Rotation aller im Repository sichtbaren Geheimnisse.
Tracelinks: SyRS-033
Konsolidierung: nein
Status: belegt; Workaround (als Demo-/Referenzkonfiguration deklariert)
```
```
ID: SyRS-032
Titel: On-Premise-Deployment als Windows-Dienst-Trio
Ebene: SyRS
Typ: nicht-funktional (Übertragbarkeit, ISO 25010)
Akteur: Betreiber/Administrator beim Kunden
Vorbedingung: -
Fakt: Drei separate, code-signierte MSI-Installer: WPF-Desktop-Client ("c-entron 2.0"), Web-Service (`Centron.Host.WindowsService`) und Nexus (`CentronNexus.Host`, als Windows-Dienst "NEXOWARE ServiceBoard"); WiX-basiert (`deployment/centron`, `deployment/WixSharpInstaller`).
Aussage: Das System soll in seiner aktuellen Auslieferungsform als drei getrennt zu installierende Windows-Komponenten (Desktop-Client je Arbeitsplatz, zentraler Web-Service, Nexus-Webportal) beim Kunden vor Ort betrieben werden können.
Ergebnis: Eine Neuinstallation erfordert die Installation und Konfiguration aller drei Komponenten einzeln pro Kundenumgebung (kein Mandantenmodell mit gemeinsam genutzter Infrastruktur).
Belege:
- [PRIMÄR] `deployment/WixSharpInstaller/Program.cs`, `deployment/centron/CentronSetupProject`, `deployment/centron/WebServiceSetupProject` - Begründung: Konkrete Installer-Projekte für alle drei Komponenten.
Prüfidee: Vollständige Neuinstallation aller drei Komponenten in einer sauberen Testumgebung durchführen und Aufwand/Abhängigkeiten dokumentieren.
Tracelinks: -
Konsolidierung: nein
Status: belegt; Workaround (historisches On-Premise-Modell, für SaaS-Zielarchitektur zu ersetzen)
```
```
ID: SyRS-033
Titel: Sekundäre Container-Bereitstellung (Docker/Linux)
Ebene: SyRS
Typ: nicht-funktional (Übertragbarkeit, ISO 25010)
Akteur: Betreiber (Demo-/Testumgebung)
Vorbedingung: -
Fakt: Docker-Compose-Stack (`db`, `webservice`, `smtp`, `nexus`) existiert für Demo-/Testzwecke; laut `docker/README.md` stammt die Docker-Verpackung von einem Drittanbieter "zu Dokumentationszwecken" und ist nicht der primäre Auslieferungsweg. Web-Service kann zusätzlich manuell als Linux-Framework-dependent-Build betrieben werden (`docs/guides/services/web-service-on-linux.md`), jedoch ohne Konfigurationswerkzeug und ohne funktionierende Sub-Webservices.
Aussage: Das System soll (ergänzend zum Windows-Betrieb) eine containerisierte bzw. Linux-basierte Bereitstellung des Web-Service und des Nexus-Portals ermöglichen, wenn auch mit eingeschränktem Funktionsumfang und ohne offizielle Erstunterstützung.
Ergebnis: Web-Service und Nexus lassen sich unter Linux/Docker betreiben; Sub-Web-Services und eine grafische Konfigurationsoberfläche stehen dort jedoch nicht zur Verfügung.
Belege:
- [SEKUNDÄR] `docker/compose/compose.yaml`, `docker/README.md` - Begründung: Konkrete, aber als sekundär/nicht offiziell deklarierte Container-Definition.
- [SEKUNDÄR] `docs/guides/services/web-service-on-linux.md` (Abschnitt "Differences between Linux and Windows") - Begründung: Explizit dokumentierte Funktionslücken unter Linux.
Prüfidee: Web-Service unter Ubuntu/Debian gemäß Anleitung installieren und Funktionsumfang gegen Windows-Betrieb vergleichen (insbesondere Sub-Web-Services).
Tracelinks: SyRS-031, SyRS-032
Konsolidierung: nein
Status: belegt; Workaround
```
```
ID: SyRS-034
Titel: Automatisierte, signierte Build- und Versionierungspipeline
Ebene: SyRS
Typ: nicht-funktional (Wartbarkeit, ISO 25010)
Akteur: Entwickler, Build-System
Vorbedingung: -
Fakt: `Centron.Scripts`-Projekt erzeugt Versionsnummer (Nerdbank.GitVersioning, `version.json`), baut, signiert (Azure Trusted Signing) und archiviert Installer für Desktop-Client, Web-Service und Nexus; Azure-DevOps- und neuere GitHub-Actions-Pipelines (.NET 10) lösen dies pro Pull Request/Branch automatisch aus.
Aussage: Das System soll bei jedem Merge in die Hauptzweige automatisiert kompiliert, versioniert, digital signiert und als Installationspaket bereitgestellt werden, ohne manuellen Eingriff.
Ergebnis: Jeder erfolgreiche Build erzeugt eindeutig versionierte, signierte Installationspakete, die automatisch mit referenzierten Tickets verknüpft werden.
Belege:
- [PRIMÄR] `docs/operations/build-server-and-automated-builds.md` (konkrete Versionsschema-, Signierungs- und Ticket-Verknüpfungslogik) - Begründung: Vollständig dokumentierter, produktiv laufender Prozess.
- [SEKUNDÄR] `.github/workflows/build.yml` - Begründung: Aktuelle GitHub-Actions-Umsetzung.
Prüfidee: Pull Request mit Ticketreferenz mergen; Build-Version muss automatisch im referenzierten Ticket hinterlegt werden.
Tracelinks: -
Konsolidierung: Kandidat: Parallel gepflegte Azure-DevOps-Pipelines (`azure/*`, `azure-blazor/*`) und neuere GitHub-Actions-Workflows decken teils dieselben Build-/Test-Schritte ab – Konsolidierungskandidat.
Status: belegt
```
```
ID: SyRS-035
Titel: Automatisiertes Sicherheits-Scanning in der CI-Pipeline
Ebene: SyRS
Typ: Sicherheit
Akteur: Build-System
Vorbedingung: -
Fakt: `azure/analyze-pipeline.yml` und `azure-blazor/security-pipeline.yaml` führen nächtlich (Cron `0 0 * * *`) CodeQL-Analysen für C#/JavaScript sowie Abhängigkeitsprüfungen durch.
Aussage: Das System soll regelmäßig automatisiert auf bekannte Sicherheitslücken im Quellcode und in Abhängigkeiten geprüft werden.
Ergebnis: Neu eingeführte, durch CodeQL erkennbare Schwachstellen werden spätestens im nächsten nächtlichen Lauf gemeldet.
Belege:
- [SEKUNDÄR] `azure/analyze-pipeline.yml`, `azure-blazor/security-pipeline.yaml` - Begründung: Konkrete, im Repository vorhandene Pipeline-Definitionen laut Agentenrecherche.
Prüfidee: Bekannte, absichtlich eingefügte Testschwachstelle in einem Feature-Branch committen und CodeQL-Erkennung im nächsten Lauf prüfen.
Tracelinks: SyRS-034
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-036
Titel: Reproduzierbare Ende-zu-Ende-Testumgebung
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO 25010)
Akteur: Entwickler, CI-System
Vorbedingung: -
Fakt: Vor jedem EndToEnd-Test wird ein Datenbank-Backup restauriert, ausstehende Migrationsskripte ausgeführt, der Test ausgeführt und die Datenbank anschließend entfernt; Ergebnisse werden über Snapshot-Vergleich (`*.expected.txt` vs. `*.actual.txt`) verifiziert.
Aussage: Das System soll über eine Testinfrastruktur verfügen, die für jeden Testlauf einen identischen Ausgangszustand garantiert, sodass Tests deterministisch reproduzierbar sind.
Ergebnis: Ein und derselbe Test liefert bei unverändertem Code zu jedem Zeitpunkt dasselbe Ergebnis (keine Datenabhängigkeit von vorherigen Testläufen).
Belege:
- [PRIMÄR] `docs/guides/development/end-to-end-testing.md` (Ablaufbeschreibung Backup-Restore → Skriptausführung → Testausführung → Verifier-Snapshot-Vergleich) - Begründung: Konkret dokumentierter, technischer Testablauf.
- [SEKUNDÄR] `.github/workflows/regression-tests.yml` (Guard gegen committete `Verifier.OverrideExpectedFiles = true`) - Begründung: Zusätzliche CI-seitige Absicherung der Testintegrität.
Prüfidee: Denselben EndToEnd-Test zweimal hintereinander ausführen und Ergebnisidentität prüfen.
Tracelinks: SyRS-034
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-037
Titel: Web-basierte Kundenportal-Instanz (Nexus) als eigenständige Systemkomponente
Ebene: SyRS
Typ: Schnittstelle
Akteur: Endkunde, Service-Mitarbeiter
Vorbedingung: -
Fakt: `CentronNexus`/`CentronNexus.Host` ist eine Blazor-Server-Anwendung, separat installierbar (eigener Windows-Dienst "NEXOWARE ServiceBoard"), mit eigener Playwright-Testsuite und eigenständiger CI-Pipeline-Familie (`azure-blazor/*`).
Aussage: Das System soll das Kundenportal und das interne ServiceBoard als eigenständig deploybare Webanwendung (getrennt vom WPF-Desktop-Client) bereitstellen, die dieselbe Geschäftslogik über den zentralen Webservice nutzt.
Ergebnis: Nexus kann unabhängig vom WPF-Client aktualisiert und betrieben werden, ohne dass Endanwender eine lokale Installation benötigen.
Belege:
- [PRIMÄR] `deployment/WixSharpInstaller/Program.cs` (separater Installer/Windows-Dienst) - Begründung: Eigenständiger Installationsweg bestätigt Systemkomponente.
- [PRIMÄR] `tests/PlaywrightTests/*` (Browser-E2E-Tests gegen Nexus) - Begründung: Automatisierte, laufende Tests belegen produktiven Charakter der Komponente.
Prüfidee: Nexus ohne installierten WPF-Client betreiben und vollständigen Kundenportal-Workflow (StRS-018) end-to-end durchführen.
Tracelinks: StRS-010, StRS-018, StRS-019, StRS-020, StRS-021
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-038
Titel: Eigenständige Outlook-Add-in-Client-Integration
Ebene: SyRS
Typ: Schnittstelle
Akteur: Mitarbeiter mit Microsoft Outlook
Vorbedingung: Add-in ist gemäß Office-Manifest installiert.
Fakt: `CentronNexus.OutlookAddIn` wird über ein Microsoft-Office-"MailApp"-Manifest (`Manifest.xml`) bereitgestellt und im selben Host-Prozess wie Nexus ausgeliefert (`.AddOutlookAddInComponents()`); spezielle Middleware erlaubt die Einbettung in ein Outlook-Taskpane-iFrame.
Aussage: Das System soll eine über das Microsoft-Office-Add-in-Framework standardkonform ausgelieferte Outlook-Erweiterung bereitstellen, die im selben Backend wie das Webportal läuft.
Ergebnis: Das Add-in lässt sich über den regulären Office-Add-in-Store-/Manifest-Mechanismus in Outlook (Web, Desktop, Mac) installieren und funktioniert dort eingebettet.
Belege:
- [PRIMÄR] `src/nexus/CentronNexus.OutlookAddIn/Manifest/Manifest.xml` - Begründung: Konkretes, standardkonformes Office-Add-in-Manifest.
Prüfidee: Add-in gemäß Manifest in Outlook (Desktop und Web) installieren und Grundfunktion (Ticket aus E-Mail erstellen) prüfen.
Tracelinks: StRS-020
Konsolidierung: nein
Status: belegt
```
@@ -0,0 +1,91 @@
# Traceability-Tabelle – c-entron ERP
Konsolidierte Forward-/Backward-Traceability zwischen StRS, SyRS und SwRS. Jede Zeile verknüpft eine SwRS-Anforderung (sofern vorhanden) über ihre zugehörige SyRS-Anforderung mit der auslösenden StRS-Anforderung, zusammen mit dem primären Artefaktbeleg. "–" bedeutet: keine Anforderung auf dieser Ebene direkt verknüpft (z. B. rein architektonische SyRS ohne unmittelbare Stakeholder-Formulierung, oder StRS ohne bislang detaillierte SwRS-Ausprägung).
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-001 | SyRS-013 | SwRS-001 | `src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs` |
| StRS-001 | SyRS-014 | SwRS-002 | `src/backend/Centron.BL/Sales/Receipts/IReceiptSpecificLogic.cs` |
| StRS-001 | SyRS-014 | SwRS-003 | `src/backend/Centron.BL/Sales/Receipts/SpecificLogics.cs` |
| StRS-001 | SyRS-013 | SwRS-004 | `src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs`; `Entities/DbEntities/AufKopf.cs` |
| StRS-001 | SyRS-015 | SwRS-005 | `docs/reference/receipts/receipts-backend-architecture.md` |
| StRS-001 | SyRS-015 | SwRS-006 | `docs/reference/receipts/receipts-backend-architecture.md` (Abschnitt "Critical Save Warning") |
| StRS-003 | SyRS-013 | SwRS-009 | `docs/reference/receipts/contracts-backend.md` |
| StRS-004 | SyRS-013 | SwRS-010 | `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` |
| StRS-004 | SyRS-013 | SwRS-011 | `docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md` |
| StRS-005 | SyRS-014 | SwRS-002 | `src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs` |
| StRS-006 | SyRS-021 | SwRS-026 | `docs/reference/edi/edi-architecture.md` |
| StRS-006 | SyRS-021 | SwRS-027 | `docs/reference/edi/edi-architecture.md` |
| StRS-006 | SyRS-022 | SwRS-028 | `docs/reference/edi/edi-import-rules.md` |
| StRS-007 | SyRS-013 | SwRS-001 | `src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs` |
| StRS-008 | SyRS-013 | SwRS-007 | `src/backend/Centron.BL/Sales/Receipts/ReceiptPriceHelperBL.cs` |
| StRS-008 | SyRS-013 | SwRS-008 | `src/backend/Centron.BL/Warehousing/TaxBL.cs` |
| StRS-009 | SyRS-013 | – | `src/centron/Centron.WPF.UI/Modules/Rma/RmaOverviewView.xaml` |
| StRS-010 | SyRS-003 | – | `src/webservice/Centron.Controllers/Controllers/v1/Helpdesks/HelpdesksController.cs` |
| StRS-010 | SyRS-037 | SwRS-034 | `src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs` |
| StRS-011 | SyRS-013 | SwRS-034 | `docs/features/automatic-helpdesk-creation-templates.md` |
| StRS-012 | SyRS-011 | SwRS-014 | `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` |
| StRS-013 | SyRS-011 | SwRS-012 | `src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs` |
| StRS-013 | SyRS-011 | SwRS-013 | `src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs:1059` |
| StRS-013 | SyRS-011 | SwRS-014 | `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` |
| StRS-014 | SyRS-011 | SwRS-013 | `src/backend/Centron.BL/Sales/Receipts/Invoices/Opos/OposBL.cs:28` |
| StRS-014 | SyRS-011 | SwRS-014 | `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` |
| StRS-015 | SyRS-023 | SwRS-029 | `docs/reference/zugferd-field-mapping.md` |
| StRS-015 | SyRS-024 | SwRS-029 | `docs/reference/zugferd-field-mapping.md` (Abschnitt "Validation Tolerances") |
| StRS-015 | – | SwRS-030 | `src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs` |
| StRS-016 | SyRS-011 | SwRS-014 | `src/backend/Centron.BL/Administration/Rights/UserRightsExt.cs` |
| StRS-016 | SyRS-011 | SwRS-015 | `src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs` |
| StRS-016 | SyRS-017 | SwRS-016 | `docs/guides/development/add-a-new-right.md` |
| StRS-016 | SyRS-007 | SwRS-017 | `src/webservice/Centron.Host/AspNetCore/TicketAuthenticationHandler.cs` |
| StRS-016 | SyRS-008 | SwRS-018 | `docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md` |
| StRS-016 | SyRS-008 | SwRS-019 | `src/webservice/Centron.Host/CentronHost.cs` |
| StRS-016 | SyRS-009 | SwRS-020 | `src/webservice/Centron.Controllers/Controllers/v1/Administration/AccessTokensController.cs` |
| StRS-016 | SyRS-012 | – | `docs/reference/receipts/receipt-search-architecture.md` |
| StRS-017 | SyRS-018 | SwRS-021 | `docs/reference/security/licensing-system.md` |
| StRS-017 | SyRS-013 | SwRS-034 | `src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs` |
| StRS-018 | SyRS-003 | SwRS-001 | `src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs` |
| StRS-018 | SyRS-037 | – | `tests/PlaywrightTests/WebaccountTests.cs` |
| StRS-019 | SyRS-011 | – | `tests/PlaywrightTests/WebaccountTests.cs` |
| StRS-019 | SyRS-012 | – | `tests/PlaywrightTests/WebaccountTests.cs` |
| StRS-020 | SyRS-038 | – | `src/nexus/CentronNexus.OutlookAddIn/Manifest/Manifest.xml` |
| StRS-021 | SyRS-027 | SwRS-031 | `docs/features/exchange-sync-bugprotokoll.md` |
| StRS-021 | SyRS-027 | SwRS-032 | `docs/features/exchange-sync-bugprotokoll.md` (Ticket 164020, 158813) |
| StRS-022 | SyRS-003 | – | `src/apis/Centron.Api.Gls/CentronGlsLogic.cs`; `src/apis/Centron.Api.Shipcloud/CentronShipcloudLogic.cs` |
| StRS-023 | SyRS-013 | – | `src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs` |
| StRS-024 | SyRS-013 | – | `src/apis/Centron.APIs.FinAPI/FinApiClient.cs` |
| StRS-025 | SyRS-013 | – | `Centron.Api.docuFORM/Models/Swagger/DeviceCounters.cs` |
| StRS-026 | SyRS-013 | – | `src/centron/Centron.WPF.UI/Modules/Statistics/SaleStatistics` |
| StRS-027 | SyRS-012 | – | `docs/reference/receipt-search-architecture.md` (Branch Isolation) |
| StRS-028 | – | – | `src/centron/Centron.WPF.UI/Modules/Administration/DSGVO/CentronDataSecurityView.xaml` (HYPOTHESE) |
| StRS-029 | SyRS-013 | – | `src/webservice/Centron.Controllers/Controllers/v1/Administration/ArtificialIntelligenceChatsController.cs` |
| StRS-030 | SyRS-001 | – | `docs/getting-started/general-structure.md` |
| – | SyRS-002 | SwRS-037 | `src/webservice/Centron.Controllers/Configuration/GlobalExceptionFilter.cs` |
| – | SyRS-004 | SwRS-036 | `src/webservice/Centron.Host/AspNetCore/WcfBridge/CentronWcfBridge.cs` |
| – | SyRS-005 | – | `src/webservice/Centron.Controllers/Controllers/v1/**` |
| – | SyRS-006 | – | `src/webservice/Centron.Host/RealTimeServices/ChatHub.cs` |
| – | SyRS-010 | – | `docs/reference/receipts/receipt-search-architecture.md` |
| – | SyRS-016 | SwRS-022 | `docs/guides/database/settings-management.md` |
| – | SyRS-016 | SwRS-024 | `docs/reference/architecture/dtos-and-entities.md` |
| – | SyRS-016 | SwRS-025 | `src/backend/Centron.DAO/GenericStoredProcedureDAO.cs` |
| – | SyRS-016 | SwRS-038 | `src/backend/Centron.Entities/PersistedEntity.cs` |
| – | SyRS-017 | SwRS-023 | `docs/reference/database/script-rules.md` |
| – | SyRS-019 | – | `docs/guides/ui/localization.md` |
| – | SyRS-020 | – | `docs/getting-started/general-structure.md` (File Encoding Requirements) |
| – | SyRS-025 | SwRS-033 | `docs/Background Service/DataQualityService.md` |
| – | SyRS-026 | – | `docs/reference/edi/edi-import-rules.md` (Execution Frequency) |
| – | SyRS-028 | SwRS-035 | `docs/reference/security/developer-security.md` |
| – | SyRS-029 | – | `src/webservice/Centron.Host/CentronHost.cs` (`MaxRequestBodySize = null`) (HYPOTHESE) |
| – | SyRS-030 | – | `src/webservice/Centron.Host/CentronHost.cs` (`AllowAnyOrigin`) |
| – | SyRS-031 | – | `docker/compose/compose.yaml`; `docker/compose/WebServiceConfig.xml` |
| – | SyRS-032 | – | `deployment/WixSharpInstaller/Program.cs` |
| – | SyRS-033 | – | `docker/compose/compose.yaml`; `docs/guides/services/web-service-on-linux.md` |
| – | SyRS-034 | – | `docs/operations/build-server-and-automated-builds.md` |
| – | SyRS-035 | – | `azure/analyze-pipeline.yml`; `azure-blazor/security-pipeline.yaml` |
| – | SyRS-036 | – | `docs/guides/development/end-to-end-testing.md` |
## Hinweise zur Traceability
- Mehrere SwRS-Anforderungen referenzieren dieselbe SyRS-/StRS-Anforderung (z. B. SwRS-012/SwRS-013/SwRS-014 unter StRS-013), da eine fachliche Anforderung typischerweise durch mehrere zusammenwirkende Softwarekomponenten realisiert wird.
- Zeilen mit "–" in der StRS-Spalte kennzeichnen SyRS-Anforderungen, die primär architektonisch/technisch begründet sind (z. B. Fehlerbehandlung, Datenbankkonventionen) und keiner einzelnen, isolierten Stakeholder-Anforderung zugeordnet wurden, jedoch mehrere StRS-Anforderungen querschnittlich unterstützen.
- Zeilen mit "–" in der SwRS-Spalte kennzeichnen StRS-/SyRS-Anforderungen, zu denen im Rahmen dieser Iteration keine tiefergehende komponentenbezogene Analyse (SwRS-Ebene) durchgeführt wurde (siehe `Analysebericht.md`, Abschnitt Abdeckung/Tiefe).
- Die vollständige, bidirektionale Referenzierung ist zusätzlich in den `Tracelinks`-Feldern der einzelnen Anforderungen in `StRS.md`, `SyRS.md` und `SwRS.md` hinterlegt.
@@ -0,0 +1,228 @@
# Messprotokoll – V1 Baseline (Prompt-only) – Prompt-Version 01, Lauf 3
> Dritter Lauf des Prompts `01_Prompt.md`, erster **vollständiger** Lauf unter der ab
> Prompt-Version 02 geltenden Werkzeugkonfiguration (Shell-Zugriff, Snapshot-Isolation).
> Vorgeschichte: Lauf 1 (`Iteration 1/claude-sonnet-5/builtin/high/01_Lauf_2026-08-25_122905_v1.0.0-23e8`) vollständig unter der Alt-Konfiguration;
> Lauf 2 (`Iteration 1/claude-sonnet-5/builtin/high/01_Lauf_2026-08-25_134905_v2.0.0-8b0a`) mit neuer Konfiguration, nach 24:08 durch API-Fehler
> abgebrochen. Dieser Lauf ist die gültige Messung für die neue Konfiguration.
## Lauf
- **Prompt-Datei:** `Versuche/Versuch_01/01_Prompt.md`
- **SHA-256 (Prompt):** `1B0DB06B8E0A5B92A5EFBDBEC5A0C554351FC928A16AEF34AAD9EAA0893C02FF`
(identisch zu Lauf 1 und 2 – der Prompt wurde nie verändert)
- **Startzeit:** 2026-08-25T14:29:32.2116097+02:00
- **Endzeit:** 2026-08-25T14:53:12.2739434+02:00
- **Dauer gesamt:** 00:23:40 (Wanduhr) bzw. 00:23:22 (`duration_ms`) — API: 00:43:25 (`duration_api_ms`)
- Die API-Dauer übersteigt die Wanduhrzeit, weil 7 `Explore`-Subagenten nebenläufig liefen.
- **Root-Verzeichnis:** `c:\DEV\MasterArbeit\QuellCode\CentronERP`
- **Codebasis-Commit:** `79c1142f489a32ba6a4a4cb043fd7f8550a9f257` (dirty: nein)
- **Snapshot-Zustand:** bereinigt von KI-Konfigurationen: **ja** (Prüfung vor dem Lauf: 0 Treffer);
Remote entkoppelt: **ja** (`git remote` leer)
- **Prompt-Repo-Commit:** `0ec86aed8cb8781054c86cbe0dd9f5eb0f7e5f05`
## Werkzeugkonfiguration
- **Laufverzeichnis-ID:** `v2.0.1-5dc4`
- **Ablage:** `Iteration 1/claude-sonnet-5/builtin/high/`
- **Parallele Läufe:** nein
- **Skill-Version:** `2.0.1` (wie 2.0.0, zusätzlich leerwertsicheres `before.txt`)
- **Claude-Code-Version:** 2.1.245
- **CLI-Pfad:** `C:\Users\ChristophSchwoerer\.vscode\extensions\anthropic.claude-code-2.1.245-win32-x64\resources\native-binary\claude.exe`
- **Effort:** `high` — **nicht zur Laufzeit gesetzt**, sondern aus der Sitzung geerbt und
nachtraeglich aus dem Session-Transkript rekonstruiert (104 Nachrichten, durchgaengig `high`).
`RawResult.json` enthaelt kein `effort`-Feld. Ab Skill-Version 3.4.0 wird der Wert per
`--effort` explizit gesetzt.
- **Modell:** `claude-sonnet-5` (explizit gesetzt, Kontextfenster 1.000.000, max. Output 64.000);
zusätzlich `claude-haiku-4-5-20251001` für interne Hilfsaufrufe (4.176 Input-/21 Output-Tokens)
- **Permission-Mode:** `acceptEdits`
- **Toolfreigabe:**
- `--allowedTools "Bash" "PowerShell"`
- `--disallowedTools` mit 33 Einträgen: 22 × `Bash(...)`, 11 × `PowerShell(...)` für schreibende
Kommandos (`rm`, `rmdir`, `mv`, `cp`, `dd`, `truncate`, `chmod`, `chown`, `ln`, `tee`, `sed -i`,
`Remove-Item`, `Move-Item`, `Copy-Item`, `New-Item`, `Set-Content`, `Add-Content`,
`Clear-Content`, `Out-File`, `Set-ItemProperty`), Git-Mutationen (`checkout`, `restore`,
`clean`, `reset`, `add`, `commit`, `push`) und Build-Werkzeuge (`dotnet`, `msbuild`,
`nuget`, `npm install`)
- **Isolationsmechanismus:** eingefrorener Codebasis-Snapshot ohne KI-Konfigurationen,
zusätzlich `--safe-mode` und `--strict-mcp-config`
- **MCP-Server / Agentendateien:** keine – aus dem Snapshot entfernt, zusätzlich `--safe-mode`
- **Subagenten:** 7 × `Explore` (max. Tiefe 1, 7 abgeschlossen, 0 fehlgeschlagen)
- **Fast-Mode:** aus
## Verbrauch
### Hauptagent (`usage`)
| Messgröße | Wert |
|---|---|
| Input-Tokens | 52 |
| Output-Tokens | 140.195 (davon 27.568 Thinking-Tokens) |
| Cache-Write-Tokens | 372.984 |
| Cache-Read-Tokens | 5.246.930 |
| Agent-Turns | 69 |
### Gesamtlauf inkl. Subagenten (`modelUsage`, abrechnungsrelevant)
| Messgröße | `claude-sonnet-5` | `claude-haiku-4-5-20251001` | Summe |
|---|---:|---:|---:|
| Input-Tokens | 312 | 4.176 | 4.488 |
| Output-Tokens | 229.976 | 21 | 229.997 |
| Cache-Write-Tokens | 739.626 | 0 | 739.626 |
| Cache-Read-Tokens | 10.542.089 | 0 | 10.542.089 |
| Tokens gesamt | 11.512.003 | 4.197 | **11.516.200** |
**Tokens gesamt: 11.516.200** (Summe aus Input, Output, Cache-Write und Cache-Read ueber alle Modelle; `total_cost_usd` steht weiterhin in `RawResult.json`)
## Ergebnis
- **Status:** erfolgreich (`is_error: false`, `subtype: "success"`, `stop_reason: "end_turn"`,
`terminal_reason: "completed"`, Exit-Code 0, `Stderr.log` leer)
- **Session-ID:** `88426b05-5eb1-4dbd-b89a-ffe5c7220ac4`
- **Permission-Denials:** **0**
- **Erzeugte Dateien:** alle 7 geforderten Artefakte in `Ergebnisse\`
| Datei | Größe | Inhalt |
|---|---:|---|
| `StRS.md` | 44.803 B | 30 Anforderungen |
| `SyRS.md` | 53.729 B | 38 Anforderungen |
| `SwRS.md` | 57.279 B | 38 Anforderungen |
| `Traceability.md` | 9.010 B | 56 Zeilen StRS→SyRS→SwRS |
| `Hypothesen.md` | 6.812 B | 9 Einträge (H-001…H-009) |
| `Glossar.md` | 10.710 B | Domänenbegriffe |
| `Analysebericht.md` | 13.802 B | Abdeckungstiefe je Modul, Konsistenzcheck, Selbstbewertung |
Summe: **106 Anforderungen** über drei Ebenen.
- **Root unverändert:** ja. Vorher/Nachher-Vergleich per `git status --porcelain` identisch
(beide leer), HEAD unverändert `79c1142`. Der Lauf hat trotz voller Shell-Freigabe keine Datei
der Codebasis angelegt, geändert oder gelöscht.
- **Abschlusstext des Agenten:** siehe `RawResult.json` (`result`)
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 30 | 28,3 % |
| SyRS | 38 | 35,8 % |
| SwRS | 38 | 35,8 % |
| **Gesamt** | **106** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| funktional | 37 | 34,9 % |
| Sicherheit | 23 | 21,7 % |
| Schnittstelle | 14 | 13,2 % |
| Daten | 13 | 12,3 % |
| nicht-funktional (Zuverlässigkeit, ISO 25010) | 7 | 6,6 % |
| nicht-funktional (Wartbarkeit, ISO 25010) | 3 | 2,8 % |
| nicht-funktional (Übertragbarkeit, ISO 25010) | 3 | 2,8 % |
| Sicherheit (Lücke/Risiko) | 2 | 1,9 % |
| nicht-funktional | 1 | 0,9 % |
| nicht-funktional (Wartbarkeit / Übertragbarkeit, ISO 25010) | 1 | 0,9 % |
| (2 weitere) | 2 | 1,9 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 143 |
| davon `PRIMÄR` | 98 (68,5 %) |
| davon `SEKUNDÄR` | 41 (28,7 %) |
| davon `KONTEXT` | 4 (2,8 %) |
| Belege je Anforderung (Median) | 1,0 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 89 (84,0 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 103 | 97,2 % |
| als `HYPOTHESE` gekennzeichnet | 3 | 2,8 % |
| als Workaround vermerkt | 10 | 9,4 % |
| Konsolidierungskandidaten | 12 | 11,3 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **verletzt** – 1 von 43 ungedeckt: SyRS-035 |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 97 von 106 mit Tracelinks (91,5 %) |
## Vergleich der drei Läufe (identischer Prompt)
| Messgröße | Lauf 1 (alt) | Lauf 2 (neu, Abbruch) | **Lauf 3 (neu)** |
|---|---:|---:|---:|
| Werkzeugkonfiguration | ohne Shell | mit Shell | mit Shell |
| Status | erfolgreich | **API-Fehler** | erfolgreich |
| Permission-Denials | 36 | 0 | **0** |
| Dauer (Wanduhr) | 31:31 | 31:24 | **23:40** |
| Agent-Turns | 43 | 8 | 69 |
| Subagenten | 8 × Explore | 6 × general-purpose | 7 × Explore |
| Anforderungen gesamt | 96 | 89 (unvollständig) | **106** |
| — davon StRS / SyRS / SwRS | 28 / 28 / 40 | 45 / 44 / – | 30 / 38 / 38 |
| Traceability-Zeilen | 44 | – | 56 |
| Hypothesen | 12 | – | 9 |
| Output-Tokens (gesamt) | 249.040 | 226.613 | 229.997 |
| Cache-Read-Tokens | 11.959.137 | 15.618.130 | 10.542.089 |
| Tokens gesamt | 13.052.010 | 16.655.125 | **11.516.200** |
## Anmerkungen/Auffälligkeiten
1. **Shell-Zugriff wirkt: 0 statt 36 Permission-Denials.** Die Werkzeugkonfiguration hat den
Lauf zu keinem Zeitpunkt eingeschränkt. Gleichzeitig ist der Lauf **schneller** (23:40 statt
31:31) und **günstiger** (6,82 statt 13.052.010 Tokens) als Lauf 1 und liefert **mehr** Anforderungen
(106 statt 96) sowie eine dichtere Traceability (56 statt 44 Zeilen). Die Cache-Read-Tokens
sanken um 12 % – der Agent musste weniger wiederholt lesen, weil er gezielt suchen konnte.
2. **Deutlich mehr Agent-Turns bei kürzerer Laufzeit:** 69 statt 43. Der Agent führte mehr,
dafür kleinere und gezieltere Werkzeugschritte aus – ein plausibler Effekt des Shell-Zugriffs,
der Inventuren in einem Aufruf erledigt, statt sie über viele Dateilesungen zu rekonstruieren.
3. **Verschiebung der Anforderungsverteilung.** Lauf 1 war SwRS-lastig (28/28/40), Lauf 3 ist
gleichmäßiger und system-schwerer (30/38/38). Ob das an der Werkzeugkonfiguration liegt oder
Laufvarianz ist, lässt sich aus einem einzelnen Lauf nicht entscheiden; für belastbare
Aussagen wären Wiederholungsläufe nötig.
4. **Subagenten-Typ ist keine Konstante.** Lauf 1: 8 × `Explore`; Lauf 2: 6 × `general-purpose`;
Lauf 3: 7 × `Explore` – bei identischem Prompt. Die Wahl trifft der Agent selbst und sie
beeinflusst Laufzeit und Kosten, ist also bei Vergleichen als Störgröße zu führen.
5. **Konsistenzcheck laut Agent:** keine doppelten oder verwaisten IDs; zwei fehlerhafte
Tracelinks wurden vor Abgabe gefunden und korrigiert (dokumentiert im `Analysebericht.md`).
6. **Zählabweichung bei Hypothesen** (wie in Lauf 1, in geringerem Ausmaß): `Hypothesen.md`
führt 9 Einträge, in den Anforderungsdateien stehen 8 Inline-Markierungen `[HYPOTHESE]`.
Für die Auswertung der Belegdichte ist weiterhin zu klären, welche Zählweise maßgeblich ist.
7. **Sicherheitsbefunde:** Der Agent weist auf SyRS-Ebene fehlende Rate-Limitierung, offene
CORS-Konfiguration und Secrets in Docker-Konfigurationen aus. Der SHA-1-Passwortbefund aus
Lauf 1 ist im Abschlusstext dieses Laufs nicht erwähnt – ein Hinweis darauf, dass die
Befundmenge zwischen Läufen variiert und eine Zusammenführung über mehrere Läufe sinnvoll ist.
8. **Abdeckung laut Selbstbewertung:** Tiefe auf Beleg-/Abrechnungs-Engine, Rechte/Auth/Lizenzen,
EDI/E-Rechnung und Deployment/Sicherheit. Explizit flach oder gar nicht analysiert:
Production, PLM, QM, C-Sign, C-FLOW, DSGVO-Modulinterna. Der Agent dokumentiert das als
Abdeckungstabelle statt gleichmäßige Abdeckung zu behaupten.
9. **Verlaufsbeobachtung:** Der abgebrochene Lauf 2 hatte bis zum Abbruch mehr Anforderungen
je Ebene erzeugt (StRS 45, SyRS 44) als Lauf 3 (30, 38) – bei ähnlichem Output-Token-Volumen.
Die Mengengerüste schwanken zwischen Läufen also erheblich; Anforderungsanzahl allein ist
kein robustes Qualitätsmaß.
10. **Werkzeughinweis:** Die Verfolgung des Hintergrundprozesses durch die Oberfläche riss
während dieses Laufs ab (Meldung „stopped" ohne Abschlussdatensatz), während der Prozess
normal weiterlief. Der Abschluss wurde über eine eigene Warteschleife auf
`RawResult.json` erkannt. Kein Einfluss auf die Messwerte.
11. **Manuelle Eingriffe während des Laufs:** keine.
@@ -0,0 +1 @@
{"is_error":false,"duration_api_ms":2605172,"num_turns":69,"stop_reason":"end_turn","session_id":"88426b05-5eb1-4dbd-b89a-ffe5c7220ac4","total_cost_usd":6.8216238,"usage":{"input_tokens":52,"cache_creation_input_tokens":372984,"cache_read_input_tokens":5246930,"output_tokens":140195,"output_tokens_details":{"thinking_tokens":27568},"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":372984,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":763,"cache_read_input_tokens":410704,"cache_creation_input_tokens":722,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":722},"type":"message"}],"speed":"standard"},"modelUsage":{"claude-haiku-4-5-20251001":{"inputTokens":4176,"outputTokens":21,"cacheReadInputTokens":0,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.004281,"contextWindow":200000,"maxOutputTokens":32000,"canonicalModel":"claude-haiku-4-5","provider":"firstParty"},"claude-sonnet-5":{"inputTokens":312,"outputTokens":229976,"cacheReadInputTokens":10542089,"cacheCreationInputTokens":739626,"webSearchRequests":0,"costUSD":6.8173428000000005,"contextWindow":1000000,"maxOutputTokens":64000,"canonicalModel":"claude-sonnet-5","provider":"firstParty"}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","fast_mode_disabled_reason":"extra_usage_disabled","subagent_stats":{"spawned":7,"requested":{"background":0,"foreground":0,"unset":7},"started_in_background":7,"max_depth":1,"spawned_by_subagents":0,"completed":7,"failed":0,"killed":{"parent":0,"user":0,"system":0},"refused":{"depth_limit":0,"concurrency_limit":0,"budget":0},"by_type":{"Explore":7}},"subtype":"success","api_error_status":null,"result":"All seven required deliverables have been produced in `Ergebnisse/`:\n\n- **StRS.md** – 30 stakeholder requirements (order-to-cash, contracts/RMM billing, EDI, CRM, RMA, helpdesk, dunning/OPOS, e-invoicing, rights, licensing, customer web portal, Outlook/Exchange integration, shipping/banking/catalog/MPS integrations, reporting, GDPR, AI assistant).\n- **SyRS.md** – 38 system-level requirements (3-tier architecture, Result/Response pattern, legacy WCF-bridge + modern v1 API, SignalR, auth (ticket/OIDC/JWT/AccessToken/RADIUS-2FA), branch isolation, receipt state machine, DB/migration conventions, EDI/e-invoicing, background services, Nexus/Outlook add-in, plus flagged security gaps: missing rate limiting, open CORS, secrets in Docker configs).\n- **SwRS.md** – 38 component-level requirements with concrete class/method/table evidence (ReceiptBase/IReceiptSpecificLogic/SpecificLogics, TaxBL, DunningBL/OposBL rights guards, UserRightsExt, auth handlers, licensing, ScriptMethod migrations, EDI partial classes, ZUGFeRD mapping, Exchange sync source-of-truth rule, etc.).\n- **Traceability.md**, **Hypothesen.md** (9 open questions with what's missing to confirm them), **Glossar.md**, and **Analysebericht.md** (module coverage-depth table, consistency check — no duplicate/dangling IDs, two tracelink errors found and fixed — and a self-assessment with concrete follow-up priorities).\n\nGiven the codebase's scale (~15,500 C# files), this iteration deliberately concentrated depth on the receipt/billing engine, rights/auth/licensing, EDI/e-invoicing, and deployment/security, while explicitly documenting shallow or unanalyzed areas (Production, PLM, QM, C-Sign, C-FLOW, GDPR module internals, etc.) rather than claiming uniform coverage — as the Analysebericht spells out for follow-up iterations.","ttft_ms":9636,"ttft_stream_ms":2977,"time_to_request_ms":41,"type":"result","duration_ms":1401511,"uuid":"f7b4c7b1-1efe-4848-ab48-d5609ae4d2a4","queued_turn_count":0}
@@ -0,0 +1,66 @@
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 30 | 28,3 % |
| SyRS | 38 | 35,8 % |
| SwRS | 38 | 35,8 % |
| **Gesamt** | **106** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| funktional | 37 | 34,9 % |
| Sicherheit | 23 | 21,7 % |
| Schnittstelle | 14 | 13,2 % |
| Daten | 13 | 12,3 % |
| nicht-funktional (Zuverlässigkeit, ISO 25010) | 7 | 6,6 % |
| nicht-funktional (Wartbarkeit, ISO 25010) | 3 | 2,8 % |
| nicht-funktional (Übertragbarkeit, ISO 25010) | 3 | 2,8 % |
| Sicherheit (Lücke/Risiko) | 2 | 1,9 % |
| nicht-funktional | 1 | 0,9 % |
| nicht-funktional (Wartbarkeit / Übertragbarkeit, ISO 25010) | 1 | 0,9 % |
| (2 weitere) | 2 | 1,9 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 143 |
| davon `PRIMÄR` | 98 (68,5 %) |
| davon `SEKUNDÄR` | 41 (28,7 %) |
| davon `KONTEXT` | 4 (2,8 %) |
| Belege je Anforderung (Median) | 1,0 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 89 (84,0 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 103 | 97,2 % |
| als `HYPOTHESE` gekennzeichnet | 3 | 2,8 % |
| als Workaround vermerkt | 10 | 9,4 % |
| Konsolidierungskandidaten | 12 | 11,3 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **verletzt** – 1 von 43 ungedeckt: SyRS-035 |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 97 von 106 mit Tracelinks (91,5 %) |
@@ -0,0 +1,72 @@
[
{
"id": "toolu_014c5RBBXovP3hsw2khZxMMY",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey backend domain model (Entities)",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis. This is read-only exploration — do not modify anything.\n\nFocus area: C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\backend\\Centron.Entities (1185 .cs files) — this is presumably the domain/entity model layer.\n\nTask: Produce an inventory, not a deep read of every file. Specifically:\n1. List the top-level namespace/folder structure under Centron.Entities (what business areas do the folder names suggest — e.g. Auftrag, Rechnung, Artikel, Kunde, Lager, Personal, etc.)\n2. For each major business area folder, sample 2-4 representative entity classes and note: class name, file path, notable fields (especially status/enum fields, foreign keys, audit fields), and any inline validation attributes or comments suggesting business rules.\n3. Look specifically for status/enum types (e.g. AuftragStatus, RechnungStatus, files with \"Status\" or \"Enum\" in the name) across the whole folder — list file paths and the enum values found, since status machines are high-value for requirements extraction.\n4. Look for any classes/attributes suggesting audit trail, soft-delete, multi-tenant/mandant fields, or versioning.\n\nReport back as structured text: a list of business areas with file path evidence, a list of found status enums with their values and file paths, and any other structural observations. Include concrete file paths for everything (I need traceability evidence). Keep the report focused and factual — this feeds into a formal requirements specification, so cite exact paths, not vague descriptions. Aim for a report of 800-1500 words.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01PAjHsNvGeWGQE4eGYGXsnM",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey backend business logic (BL)",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis. This is read-only exploration — do not modify anything.\n\nFocus area: C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\backend\\Centron.BL (2068 .cs files) — presumably the business logic layer.\n\nTask: Produce an inventory, not a deep read of every file. Specifically:\n1. List the top-level namespace/folder structure under Centron.BL (what business areas/modules do folder names suggest — e.g. Auftrag, Rechnung/Faktura, Artikel, Kunde/CRM, Lager, Einkauf, Zeiterfassung/Timer, C-Sign, Benutzerverwaltung/Berechtigungen, etc.)\n2. Search for and list files/classes related to: status transitions or workflow logic (methods like \"ChangeStatus\", \"SetStatus\", state machine patterns), permission/rights checks (search for \"Recht\", \"Permission\", \"HasRight\", \"IsAllowed\", \"Berechtigung\"), and billing/invoicing calculation logic (search for \"Rechnung\", \"Faktura\", \"Preis\", \"Berechnung\", \"Steuer\", \"MwSt\", \"Rabatt\").\n3. For each category found, give concrete file paths and short (1-2 line) descriptions of what the method/class appears to do based on its name and a quick look at signatures.\n4. Note any classes that look like they implement a state machine (enum-driven if/switch on status with allowed-transition logic).\n\nReport back as structured text with concrete file paths and short descriptions for traceability purposes — this feeds into a formal requirements specification. Aim for 1000-1800 words, prioritize breadth of module coverage over depth on any one file.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01CAck4seaV26Qjosw3twHSp",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey backend DAO and DB constraints",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.\n\nFocus area: C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\backend\\Centron.DAO (1131 .cs files) — presumably the data access layer (likely raw SQL or an ORM against MSSQL).\n\nTask:\n1. Identify what data-access pattern is used (raw ADO.NET with SQL strings, an ORM like Entity Framework/NHibernate, stored-procedure calls, etc.) — cite example file paths.\n2. List the top-level namespace/folder structure and what business areas the folders suggest.\n3. Search the whole repository (not just this folder) for .sql files, database migration scripts, or schema definition files (e.g. under a \"Datenbank\", \"DB\", \"Migrations\", \"Scripts\" folder) and report their locations and what they contain (table names, constraints, triggers if visible).\n4. Within Centron.DAO, search for SQL fragments containing constraints, CHECK, FOREIGN KEY, UNIQUE, NOT NULL, or transaction/locking logic (e.g. \"BEGIN TRAN\", \"TransactionScope\") and report file paths + snippet.\n5. Search for stored procedure calls (CommandType.StoredProcedure or \"EXEC \") and list a sample of procedure names found, with file paths.\n\nReport back as structured text with concrete file paths for traceability. Aim for 1000-1500 words, prioritizing evidence of enforced data rules (constraints) since these are high-value PRIMÄR evidence for a requirements spec.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01Y2UUWzGyXC9sS6PD2aduzH",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey WPF UI module structure",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# WPF desktop ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.\n\nFocus area: C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\centron\\Centron.WPF.UI (5255 .cs files + most of the 1233 .xaml files) — this is the main desktop client application, the primary user-facing part of the ERP.\n\nTask: Produce a broad inventory of the application's functional modules as visible from folder/file naming, since this is the main UI a business user interacts with.\n1. List the top-level folder structure (1-2 levels deep) and identify which folders correspond to which business modules (e.g. Auftragsverwaltung, Rechnungswesen, Artikelstamm, Kundenverwaltung/CRM, Lagerverwaltung, Zeiterfassung, C-Sign/Signatur, Einstellungen/Administration, Berichte/Reports, Angebote, Bestellungen, etc.)\n2. For 8-10 of the most significant business modules, list a couple of representative View/ViewModel/Window .xaml or .cs file paths.\n3. Search for UI validation logic: look for files/methods with names like \"Validate\", \"CanExecute\", \"IsValid\", error message strings (e.g. resource files, .resx, or string literals shown to users) — report a sample with file paths.\n4. Search for permission/rights-based UI restrictions (e.g. \"Visibility\", \"IsEnabled\" tied to a rights-check property, \"HasRight\", \"Berechtigung\") — report sample file paths.\n5. Look for any menu/ribbon definition files that enumerate the application's main functions/menu items (this is useful to reconstruct the stakeholder-level feature list) — report file paths and a sample of menu item labels found.\n\nReport back as structured text with concrete file paths. This feeds into a formal requirements specification needing traceability, so always cite paths. Aim for 1200-1800 words, prioritizing breadth across business modules.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_01EEtnTW4qSPGuKc57zWa8uM",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey webservice API layer",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.\n\nFocus areas:\n- C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\webservice\\Centron.WebServices.Core (2530 .cs files)\n- C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\webservice\\Centron.Controllers (57 .cs files)\n- C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\webservice\\Centron.Host, Centron.Host.Console, Centron.Host.WindowsService (hosting)\n- C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\Centron.Api.docuFORM\n\nTask:\n1. Identify the web API technology used (ASP.NET Web API / OWIN / minimal API / SOAP/WCF, routing style, authentication mechanism) — cite example file paths (Controller classes, Startup/Program files, [Authorize] attributes, API key checks, JWT, etc.)\n2. List the controllers found in Centron.Controllers and Centron.WebServices.Core with their route prefixes/endpoints (search for [Route], [HttpGet], [HttpPost] attributes) — give a representative list (doesn't need to be exhaustive, aim for the ones covering distinct business capabilities: e.g. Auftrag, Rechnung, Kunde, Artikel, Zeiterfassung, C-Sign etc.)\n3. Look for authentication/authorization logic: API keys, tokens, session handling — cite file paths.\n4. Look for rate-limiting, logging middleware, or error-handling middleware — cite file paths (relevant for non-functional/security requirements).\n5. What does Centron.Api.docuFORM appear to integrate with (based on name and any docs/comments)?\n\nReport back as structured text with concrete file paths for traceability purposes. Aim for 1200-1600 words.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_012QzkMxgz4nftJ7GJQtdu6n",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey Nexus, external APIs, and docs",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.\n\nFocus areas:\n1. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\nexus (CentronNexus, CentronNexus.Host, CentronNexus.OutlookAddIn) — figure out what \"Nexus\" is (based on README/docs/comments/class names): likely a synchronization service or Outlook integration. Report what it does, its architecture (service? addin?), and 3-5 key classes with file paths.\n2. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\src\\apis\\* — these are external system integrations: Centron.APIs.CopDataAccess, Centron.APIs.EgisDataAccess, Centron.APIs.FinAPI, Centron.APIs.ITscopeDataAccess, Centron.APIs.IcecatDataAccess, Centron.Api.EbInterface, Centron.Api.Gls, Centron.Api.Shipcloud. For EACH, briefly state (1-3 sentences) what external system/service it integrates with and what kind of data is exchanged, based on class/method names, comments, or config keys. Cite file paths.\n3. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\docs — list the doc folder structure (features, guides, operations, reference, getting-started) and for each subfolder list the document titles/filenames found. If any documents clearly describe business features, functional scope, or architecture, note their titles and paths so they can be read in depth later.\n\nReport back as structured text with concrete file/folder paths for traceability purposes. Aim for 1200-1800 words.",
"ergebnis_zeichen": 1093
},
{
"id": "toolu_015APkVCMPxvMNCcbGJEft5u",
"werkzeug": "Agent",
"subagent_type": "Explore",
"description": "Survey deployment, ops, and test coverage hints",
"run_in_background": null,
"model": null,
"prompt": "You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP for a reverse-engineering requirements analysis, focused on non-functional / operational / security requirements evidence. Read-only exploration, do not modify anything.\n\nFocus areas:\n1. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\docker\\* (compose files, dockerfiles for c-entron-api, c-entron-webservice, c-entron-demo, c-entron-mailcatcher, regression-tests-db/pipeline) — report what services/containers are defined, exposed ports, environment variables that hint at configuration (DB connection, secrets, feature flags), and any health-check or logging configuration.\n2. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\azure and azure-blazor and .github/workflows and .github/actions — report what CI/CD pipelines exist (build, test, deploy stages), and any azure-blazor evidence of a planned/existing web migration (this is directly relevant to a \"SaaS re-implementation\" project — flag anything found).\n3. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\deployment (WixSharpInstaller, centron, riverbird folders) — report what installer/deployment artifacts exist, and what this tells us about the current on-premise deployment model (installer-based Windows desktop app + service?).\n4. C:\\DEV\\MasterArbeit\\QuellCode\\CentronERP\\tests\\* folder structure (Centron.Tests.EndToEnd, Centron.Tests.Integration, CentronNexusTests, PlaywrightTests, apis, backend, shared) — report roughly how many test files per folder, and sample 5-10 test class/method names that reveal business rules being tested (e.g. \"Test_Cannot_Delete_Invoiced_Order\", validation tests, permission tests). Playwright tests are especially interesting since they suggest an existing web UI — investigate what PlaywrightTests actually tests (which web app) and report findings with file paths.\n\nReport back as structured text with concrete file paths for traceability purposes. Aim for 1200-1800 words.",
"ergebnis_zeichen": 1093
}
]
@@ -0,0 +1,154 @@
# Subagenten-Aufrufe
Session `88426b05-5eb1-4dbd-b89a-ffe5c7220ac4`, Transkript `88426b05-5eb1-4dbd-b89a-ffe5c7220ac4.jsonl`.
`subagent_stats`: **7** Subagenten gesamt, davon **0** von Subagenten gestartet (max_depth 1). Direkt vom Hauptagenten erwartet: **7**. Im Transkript gefunden: **7**.
## 1. Survey backend domain model (Entities)
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1696 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis. This is read-only exploration — do not modify anything.
Focus area: C:\DEV\MasterArbeit\QuellCode\CentronERP\src\backend\Centron.Entities (1185 .cs files) — this is presumably the domain/entity model layer.
Task: Produce an inventory, not a deep read of every file. Specifically:
1. List the top-level namespace/folder structure under Centron.Entities (what business areas do the folder names suggest — e.g. Auftrag, Rechnung, Artikel, Kunde, Lager, Personal, etc.)
2. For each major business area folder, sample 2-4 representative entity classes and note: class name, file path, notable fields (especially status/enum fields, foreign keys, audit fields), and any inline validation attributes or comments suggesting business rules.
3. Look specifically for status/enum types (e.g. AuftragStatus, RechnungStatus, files with "Status" or "Enum" in the name) across the whole folder — list file paths and the enum values found, since status machines are high-value for requirements extraction.
4. Look for any classes/attributes suggesting audit trail, soft-delete, multi-tenant/mandant fields, or versioning.
Report back as structured text: a list of business areas with file path evidence, a list of found status enums with their values and file paths, and any other structural observations. Include concrete file paths for everything (I need traceability evidence). Keep the report focused and factual — this feeds into a formal requirements specification, so cite exact paths, not vague descriptions. Aim for a report of 800-1500 words.
```
## 2. Survey backend business logic (BL)
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1620 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis. This is read-only exploration — do not modify anything.
Focus area: C:\DEV\MasterArbeit\QuellCode\CentronERP\src\backend\Centron.BL (2068 .cs files) — presumably the business logic layer.
Task: Produce an inventory, not a deep read of every file. Specifically:
1. List the top-level namespace/folder structure under Centron.BL (what business areas/modules do folder names suggest — e.g. Auftrag, Rechnung/Faktura, Artikel, Kunde/CRM, Lager, Einkauf, Zeiterfassung/Timer, C-Sign, Benutzerverwaltung/Berechtigungen, etc.)
2. Search for and list files/classes related to: status transitions or workflow logic (methods like "ChangeStatus", "SetStatus", state machine patterns), permission/rights checks (search for "Recht", "Permission", "HasRight", "IsAllowed", "Berechtigung"), and billing/invoicing calculation logic (search for "Rechnung", "Faktura", "Preis", "Berechnung", "Steuer", "MwSt", "Rabatt").
3. For each category found, give concrete file paths and short (1-2 line) descriptions of what the method/class appears to do based on its name and a quick look at signatures.
4. Note any classes that look like they implement a state machine (enum-driven if/switch on status with allowed-transition logic).
Report back as structured text with concrete file paths and short descriptions for traceability purposes — this feeds into a formal requirements specification. Aim for 1000-1800 words, prioritize breadth of module coverage over depth on any one file.
```
## 3. Survey backend DAO and DB constraints
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1516 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.
Focus area: C:\DEV\MasterArbeit\QuellCode\CentronERP\src\backend\Centron.DAO (1131 .cs files) — presumably the data access layer (likely raw SQL or an ORM against MSSQL).
Task:
1. Identify what data-access pattern is used (raw ADO.NET with SQL strings, an ORM like Entity Framework/NHibernate, stored-procedure calls, etc.) — cite example file paths.
2. List the top-level namespace/folder structure and what business areas the folders suggest.
3. Search the whole repository (not just this folder) for .sql files, database migration scripts, or schema definition files (e.g. under a "Datenbank", "DB", "Migrations", "Scripts" folder) and report their locations and what they contain (table names, constraints, triggers if visible).
4. Within Centron.DAO, search for SQL fragments containing constraints, CHECK, FOREIGN KEY, UNIQUE, NOT NULL, or transaction/locking logic (e.g. "BEGIN TRAN", "TransactionScope") and report file paths + snippet.
5. Search for stored procedure calls (CommandType.StoredProcedure or "EXEC ") and list a sample of procedure names found, with file paths.
Report back as structured text with concrete file paths for traceability. Aim for 1000-1500 words, prioritizing evidence of enforced data rules (constraints) since these are high-value PRIMÄR evidence for a requirements spec.
```
## 4. Survey WPF UI module structure
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1921 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# WPF desktop ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.
Focus area: C:\DEV\MasterArbeit\QuellCode\CentronERP\src\centron\Centron.WPF.UI (5255 .cs files + most of the 1233 .xaml files) — this is the main desktop client application, the primary user-facing part of the ERP.
Task: Produce a broad inventory of the application's functional modules as visible from folder/file naming, since this is the main UI a business user interacts with.
1. List the top-level folder structure (1-2 levels deep) and identify which folders correspond to which business modules (e.g. Auftragsverwaltung, Rechnungswesen, Artikelstamm, Kundenverwaltung/CRM, Lagerverwaltung, Zeiterfassung, C-Sign/Signatur, Einstellungen/Administration, Berichte/Reports, Angebote, Bestellungen, etc.)
2. For 8-10 of the most significant business modules, list a couple of representative View/ViewModel/Window .xaml or .cs file paths.
3. Search for UI validation logic: look for files/methods with names like "Validate", "CanExecute", "IsValid", error message strings (e.g. resource files, .resx, or string literals shown to users) — report a sample with file paths.
4. Search for permission/rights-based UI restrictions (e.g. "Visibility", "IsEnabled" tied to a rights-check property, "HasRight", "Berechtigung") — report sample file paths.
5. Look for any menu/ribbon definition files that enumerate the application's main functions/menu items (this is useful to reconstruct the stakeholder-level feature list) — report file paths and a sample of menu item labels found.
Report back as structured text with concrete file paths. This feeds into a formal requirements specification needing traceability, so always cite paths. Aim for 1200-1800 words, prioritizing breadth across business modules.
```
## 5. Survey webservice API layer
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1681 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.
Focus areas:
- C:\DEV\MasterArbeit\QuellCode\CentronERP\src\webservice\Centron.WebServices.Core (2530 .cs files)
- C:\DEV\MasterArbeit\QuellCode\CentronERP\src\webservice\Centron.Controllers (57 .cs files)
- C:\DEV\MasterArbeit\QuellCode\CentronERP\src\webservice\Centron.Host, Centron.Host.Console, Centron.Host.WindowsService (hosting)
- C:\DEV\MasterArbeit\QuellCode\CentronERP\Centron.Api.docuFORM
Task:
1. Identify the web API technology used (ASP.NET Web API / OWIN / minimal API / SOAP/WCF, routing style, authentication mechanism) — cite example file paths (Controller classes, Startup/Program files, [Authorize] attributes, API key checks, JWT, etc.)
2. List the controllers found in Centron.Controllers and Centron.WebServices.Core with their route prefixes/endpoints (search for [Route], [HttpGet], [HttpPost] attributes) — give a representative list (doesn't need to be exhaustive, aim for the ones covering distinct business capabilities: e.g. Auftrag, Rechnung, Kunde, Artikel, Zeiterfassung, C-Sign etc.)
3. Look for authentication/authorization logic: API keys, tokens, session handling — cite file paths.
4. Look for rate-limiting, logging middleware, or error-handling middleware — cite file paths (relevant for non-functional/security requirements).
5. What does Centron.Api.docuFORM appear to integrate with (based on name and any docs/comments)?
Report back as structured text with concrete file paths for traceability purposes. Aim for 1200-1600 words.
```
## 6. Survey Nexus, external APIs, and docs
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1529 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis. Read-only exploration, do not modify anything.
Focus areas:
1. C:\DEV\MasterArbeit\QuellCode\CentronERP\src\nexus (CentronNexus, CentronNexus.Host, CentronNexus.OutlookAddIn) — figure out what "Nexus" is (based on README/docs/comments/class names): likely a synchronization service or Outlook integration. Report what it does, its architecture (service? addin?), and 3-5 key classes with file paths.
2. C:\DEV\MasterArbeit\QuellCode\CentronERP\src\apis\* — these are external system integrations: Centron.APIs.CopDataAccess, Centron.APIs.EgisDataAccess, Centron.APIs.FinAPI, Centron.APIs.ITscopeDataAccess, Centron.APIs.IcecatDataAccess, Centron.Api.EbInterface, Centron.Api.Gls, Centron.Api.Shipcloud. For EACH, briefly state (1-3 sentences) what external system/service it integrates with and what kind of data is exchanged, based on class/method names, comments, or config keys. Cite file paths.
3. C:\DEV\MasterArbeit\QuellCode\CentronERP\docs — list the doc folder structure (features, guides, operations, reference, getting-started) and for each subfolder list the document titles/filenames found. If any documents clearly describe business features, functional scope, or architecture, note their titles and paths so they can be read in depth later.
Report back as structured text with concrete file/folder paths for traceability purposes. Aim for 1200-1800 words.
```
## 7. Survey deployment, ops, and test coverage hints
- **Werkzeug:** `Agent` **Typ:** `Explore` **Hintergrund:** None
- **Prompt-Zeichen:** 1964 **Ergebnis-Zeichen:** 1093
### Prompt
```
You are surveying a large legacy C# ERP codebase (c-entron ERP) at C:\DEV\MasterArbeit\QuellCode\CentronERP for a reverse-engineering requirements analysis, focused on non-functional / operational / security requirements evidence. Read-only exploration, do not modify anything.
Focus areas:
1. C:\DEV\MasterArbeit\QuellCode\CentronERP\docker\* (compose files, dockerfiles for c-entron-api, c-entron-webservice, c-entron-demo, c-entron-mailcatcher, regression-tests-db/pipeline) — report what services/containers are defined, exposed ports, environment variables that hint at configuration (DB connection, secrets, feature flags), and any health-check or logging configuration.
2. C:\DEV\MasterArbeit\QuellCode\CentronERP\azure and azure-blazor and .github/workflows and .github/actions — report what CI/CD pipelines exist (build, test, deploy stages), and any azure-blazor evidence of a planned/existing web migration (this is directly relevant to a "SaaS re-implementation" project — flag anything found).
3. C:\DEV\MasterArbeit\QuellCode\CentronERP\deployment (WixSharpInstaller, centron, riverbird folders) — report what installer/deployment artifacts exist, and what this tells us about the current on-premise deployment model (installer-based Windows desktop app + service?).
4. C:\DEV\MasterArbeit\QuellCode\CentronERP\tests\* folder structure (Centron.Tests.EndToEnd, Centron.Tests.Integration, CentronNexusTests, PlaywrightTests, apis, backend, shared) — report roughly how many test files per folder, and sample 5-10 test class/method names that reveal business rules being tested (e.g. "Test_Cannot_Delete_Invoiced_Order", validation tests, permission tests). Playwright tests are especially interesting since they suggest an existing web UI — investigate what PlaywrightTests actually tests (which web app) and report findings with file paths.
Report back as structured text with concrete file paths for traceability purposes. Aim for 1200-1800 words.
```
@@ -0,0 +1,247 @@
# Analysebericht
## 1. Auftrag und Rahmenbedingungen
Untersuchungsgegenstand: gesamte Codebasis unter `C:\DEV\MasterArbeit\QuellCode\CentronERP`
(c-entron.NET ERP-Suite: WPF-Client, Web-Services/REST-API, Blazor-Portal "Nexus", diverse
Backend-Bibliotheken, externe API-Integrationen, Datenbankskripte, Dokumentation).
Werkzeugkonfiguration dieses Laufs: Claude Code ohne Agentendateien (`.claude/agents`) und ohne
MCP-Server — reine Dateisystem-Analyse (Read/Grep/Glob/Bash) durch ein einzelnes Modell ohne
Subagenten-Parallelisierung. Es wurde ausschließlich gelesen, keine Datei der Codebasis verändert.
Umfang der Codebasis (grobe Kennzahlen, per `find`/`wc`):
- `src/backend/Centron.BL`: 2068 .cs-Dateien, 89 fachliche Unterordner
- `src/backend/Centron.DAO`: 1131 .cs-Dateien
- `src/backend/Centron.Entities`: 1185 .cs-Dateien
- `src/backend/Centron.Interfaces`: 764 .cs-Dateien
- `src/centron/Centron.WPF.UI`: 5255 .cs-Dateien (Desktop-Client)
- `src/nexus/CentronNexus`: 762 .cs-Dateien (Blazor-Portal)
- `src/webservice/Centron.Controllers`: 57 .cs-Dateien (moderne REST-API)
- weitere: `Centron.Common`, `Centron.Gateway`, `Centron.Core`, `src/apis/*` (externe Integrationen:
FinAPI, GLS, Shipcloud, ITscope, Icecat, EGIS, C-Sign/docuFORM), `docker/*`, `deployment/*`, `docs/*`.
Insgesamt weit über 11.000 C#-Quelldateien plus Datenbankskripte, Docker-/Deployment-Konfiguration
und ca. 30 kuratierte Architektur-/Prozessdokumente unter `docs/`. Eine vollständige Tiefenanalyse
jeder einzelnen Datei ist in dieser Iteration nicht leistbar; es wurde eine risikobasierte,
selbst priorisierte Tiefenanalyse durchgeführt (siehe Abschnitt 3).
## 2. Vorgehen
1. Breitenerhebung der Modulstruktur (Verzeichnisbaum `Centron.BL`, `Centron.Entities`,
`Centron.WPF.UI`, `src/apis`, `src/nexus`, `docs/`) zur Bildung eines Moduleninventars.
2. Auswertung der vorhandenen Architektur-/Prozessdokumentation unter `docs/` als Kontext-
und Sekundärbelege (Dokumentation selbst ist keine durchgesetzte Regel, sondern beschreibt
sie – daher grundsätzlich `KONTEXT`/`SEKUNDÄR`, nie alleinige Basis für `PRIMÄR`-pflichtige
Aussagen zu Sicherheit/Fakturierung/Berechtigungen).
3. Tiefenanalyse ausgewählter, geschäftskritischer Module anhand von Quellcode (Entities, BL-
Klassen, Statuscodes/Enums, Rechteprüfungen, DB-Skripten), um für jede Anforderung mindestens
einen Beleg zu erhalten; bei sicherheits-/abrechnungs-/berechtigungsrelevanten Aussagen wurde
gezielt nach `PRIMÄR`-Belegen (Code, das die Regel tatsächlich durchsetzt) gesucht.
4. Ableitung von StRS/SyRS/SwRS-Anforderungen je Modul mit Traceability und Konsolidierungsprüfung.
5. Konsistenzcheck über das Gesamtergebnis (Abschnitt 5).
## 3. Moduleninventar und Analysetiefe
Legende Analysetiefe: **TIEF** = Quellcode mehrerer Kernklassen gelesen, Anforderungen mit
PRIMÄR-Beleg abgeleitet · **MITTEL** = gezielte Grep-Stichproben / einzelne Kernklasse gelesen ·
**FLACH** = nur Verzeichnis-/Dateinamen sowie ggf. Dokumentation gesichtet, keine Quellcode-Prüfung ·
**NICHT ANALYSIERT** = nur in der Inventarliste erfasst, keine weitere Prüfung.
### 3.1 TIEF analysiert (Quellcode mehrerer Kernklassen gelesen, PRIMÄR-Belege erhoben)
Modul | Kernartefakte | Anforderungen
---|---|---
Sicherheit & Berechtigungen | `AppRightsBL.cs`, `DeveloperSecurity.cs` | StRS-1..3, SyRS-1..4, SwRS-1..5
Lizenzierung | `LicenseManager.cs` | StRS-4, SyRS-5..6, SwRS-6..7
Verkaufsbelege (Sales/Receipts, Kernarchitektur) | `ReceiptBase.cs`, `ReceiptState.cs`, `ReceiptBL.cs` (Kernmethoden, nicht vollständig — Datei hat >10.000 Zeilen), `SaveReceiptRepository.cs` + Implementierungen | StRS-5..8, SyRS-7..11, SwRS-8..12
Verträge & automatisierte Abrechnung | `AutomaticFacturaBL.Contracts.cs` (Kernmethoden, Datei hat >2400 Zeilen, nicht vollständig gelesen) | StRS-9..10, SyRS-12..13, SwRS-13..14
### 3.2 MITTEL analysiert (gezielte Stichprobe: 1 Kernklasse/Methode gelesen oder gezielte Grep-Suche mit Codebeleg)
Modul | Kernartefakte | Anforderungen
---|---|---
Mahnwesen (Sales/Receipts/Invoices/Dunning) | `DunningBL.cs` (Auszug) | StRS-11, SyRS-14, SwRS-15
Umsatzsteuer (Warehousing/Tax) | `TaxBL.cs` (Auszug) | StRS-12, SyRS-15, SwRS-16
Kunden-/Lieferantenstammdaten (Accounts) | `AccountBL.cs` (Auszug) | StRS-13, SyRS-16, SwRS-17
Zeiterfassungsabrechnung (Timer Billing) | `ReceiptWebServiceBL.cs` (Auszug), `TimerBillingSettingsPageViewModel.cs` (via Commit-Diff) | StRS-14, SyRS-17, SwRS-18
Helpdesk/Ticketsystem (CustomerArea/Support) | `HelpdeskState.cs`, `HelpdeskStateBase.cs`, Mapping-Datei (Existenzprüfung) | StRS-15, SyRS-18, SwRS-19
Betrieb & Bereitstellung (Docker/Compose) | `docker/compose/compose.yaml` (vollständig) | StRS-16, SyRS-19, SwRS-20
### 3.3 FLACH analysiert (nur Dokumentation und/oder Verzeichnis-/Dateinamen gesichtet, kein Quellcode gelesen)
Bereich | Quelle | Bemerkung
---|---|---
EDI-Architektur (Buying/EDI, Gateway.EDI_*) | `docs/reference/edi/edi-architecture.md` | Vollständig als Dokument gelesen; keine Codeverifikation der beschriebenen Klassen (`SupplierEdiBL`, `EDICommonBL`, `EDILogBL`) durchgeführt. Alle darauf gestützten Aussagen wären daher `SEKUNDÄR`/`KONTEXT`, nicht `PRIMÄR` — in dieser Iteration wurden deshalb bewusst **keine** EDI-Anforderungen formuliert, um die Belegpflicht nicht zu verletzen.
ZUGFeRD/XRechnung E-Rechnung | `docs/guides/development/xrechnung.md`, Erwähnung in `ReceiptBL.cs` (Z.3272-3274, `InvoiceZugferdBL`) | Nur Randerwähnung im Code gesehen (Bedingung für Layout-Item), `InvoiceZugferdBL`/`ZugferdParseBL` selbst nicht gelesen.
Allgemeine Architektur/Layering | `docs/getting-started/general-structure.md`, `docs/getting-started/ai-codebase-navigation.md` | Als Kontextwissen für Traceability-Struktur verwendet, nicht in eigene Anforderungen übersetzt (beschreibt Bauprinzipien, keine Fachfunktion).
Datenbank-Konventionen | `docs/guides/database/database-conventions.md` | Für Glossar (I3D-Konvention) verwendet.
Receipts-/Contracts-Architektur (ergänzend zu 3.1) | `docs/reference/receipts/receipts-backend-architecture.md`, `contracts-backend.md` | Als SEKUNDÄR-Beleg neben Code verwendet, nicht als alleinige Quelle.
### 3.4 NICHT ANALYSIERT (nur im Verzeichnisinventar erfasst)
Die folgenden fachlichen Unterordner von `src/backend/Centron.BL` (89 insgesamt, siehe Abschnitt 1)
wurden ausschließlich über ihren Verzeichnisnamen erfasst; ihr Inhalt wurde in dieser Iteration
**nicht** gelesen und es wurden **keine** Anforderungen daraus abgeleitet:
`Accounting, Administration (außer Rights/Licensing), AppointmentRequests, ArtificialIntelligence,
BusinessPartner (außer SearchSupplierBL/SupplierAssetBL-Existenzprüfung), Buying, CPra, Calendar,
CentronIcons, CentronNexus, ChangeTracking, Chats, CheckListArea, Core, CountryArea, CustomerArea
(außer Support/HelpdeskState), Customizations, DataExchange, Devices, DocuBoard, DocumentationArea,
EDI, EmployeeArea, Exceptions, ExpectedEvents, ExternalHelpdesk, ExternalToolsBL, Finances, GUI,
Gateway, Helpers, IndexSearch, Integrations, ItPlanner, Logistics, Mail, MailScanner, Mailings,
MassUpdate, Mobile, Modules, MyCentron, MyDay, NexusNotifications, NexusTicketViews, Notifications,
ObjectExternalReferences, Outlook, PasswordManagementArea, PasswordManager, Processes, ProductMatrix,
Production, Projects, Properties, Purchasing, ReportEngine, Reporting, Resources, RiverDivo, Sales
(außer Receipts-Kern/CustomerAssets.AutomaticFactura/Receipts.Invoices.Dunning), Security (eigener
Ordner, NICHT identisch mit Administration/Rights — nicht geprüft, ob Übernahmen/Abgrenzung besteht,
siehe Hypothesen H-4), SelfCare, Services, SocialMedia, Start, Statistics, Storage, SystemArea, Tags,
Tapi, TaskManager, Telemetry, TextModuleArea, TicketProjects, Time, ToDoArea, Tools, TradePool,
Transactions, TwoFactorAuthenticator, Urls, VideoPortal, VoucherManagement, Warehousing (außer TaxBL),
WebLinks, WebServices (außer den zitierten Receipts/Timer-Billing-Ausschnitten), WebSuite, WebVersion`
Ebenfalls nicht analysiert (nur als Vorhandensein/Struktur festgestellt, keine Datei geöffnet):
- `src/backend/Centron.DAO` (1131 Dateien) — außer `SaveReceiptRepository.cs`-Familie und Existenz
von `HelpdeskStateMaps.cs`
- `src/backend/Centron.Entities` (1185 Dateien) — außer den zitierten Receipt-/Helpdesk-Entities
- `src/backend/Centron.Interfaces` (764 Dateien) — außer `ReceiptState.cs`, Existenzprüfung
`UserRightsConst.cs`, `LicenseGuids.cs`, `ApplicationKind.cs`
- `src/centron/Centron.WPF.UI` (5255 Dateien, Desktop-Client) — außer der zitierten
`TimerBillingSettingsPageViewModel.cs` (nur via Commit-Diff, nicht vollständige Datei gelesen)
- `src/nexus/CentronNexus` (762 Dateien, Blazor-Kundenportal) — vollständig ungeprüft
- `src/webservice/Centron.Controllers` (moderne REST-API), `Centron.WebServices.Core` (Legacy-REST) —
vollständig ungeprüft, außer der zitierten Ausschnitte aus `ReceiptWebServiceBL.cs`
- `src/apis/*` (FinAPI, GLS, Shipcloud, ITscope, Icecat, EGIS, EbInterface) — vollständig ungeprüft
- `Centron.Api.docuFORM` (C-Sign, laut Commit-Historie aktiv weiterentwickelt) — vollständig ungeprüft
- `deployment/*` (WiX-Installer), `azure/*`, `scripts/*` — vollständig ungeprüft
- `tests/*` (Unit/Integration/E2E/Playwright) — vollständig ungeprüft; keine Anforderung wurde durch
Testfälle verifiziert oder aus Testcode abgeleitet
- Die überwiegende Mehrheit von `docs/` (u. a. `docs/guides/ui/*`, `docs/guides/services/*`,
`docs/operations/*`, `docs/features/*`, `docs/reference/architecture/*` außer den zitierten) wurde
nicht gelesen
- Datenbankskripte/Migrationsverzeichnis selbst (nur indirekt über `docs/guides/development/add-a-new-right.md`
referenziert, keine SQL-Migrationsdatei direkt geöffnet)
- Git-Historie/Commit-Messages: nur `git log` (Kurzformat) und ein einzelner `git show` (Commit
baa9e7bd9b) ausgewertet; keine systematische Auswertung von Tickets/Issues (nicht Teil der
Codebasis / nicht als Datei zugänglich)
## 4. Bekannte Lücken
Aus dem Abgleich zwischen Auftragsumfang ("gesamte Codebasis", alle Module gleichrangig) und der in
dieser Iteration tatsächlich erreichten Tiefe (Abschnitt 3) ergeben sich folgende Lücken:
1. **Kernprozesse ohne jede Prüfung.** Einkauf/Beschaffung (`Buying`, `Purchasing`), Lager-/
Bestandsführung im engeren Sinn (Wareneingang, Bestandskorrektur — `Warehousing` außer `TaxBL`),
Produktion (`Production`), Projektverwaltung (`Projects`, `TicketProjects`), Zeiterfassung im
Kernprozess (`Time`, außer dem Ausschnitt zu Timer-Billing-Rechten) sowie die vollständige
Business-Logik des Helpdesk-Kernprozesses (`ExternalHelpdesk`, `Sales/Support/HelpdeskBL` selbst
nicht gelesen, nur die Status-Entity) wurden nicht analysiert. Für diese Bereiche existiert **keine**
einzige Anforderung in dieser Spezifikation, obwohl sie vermutlich zentrale Geschäftsprozesse
der ERP-Suite abbilden.
2. **Desktop-Client (WPF-UI, 5255 Dateien) praktisch ungeprüft.** Bis auf einen einzelnen ViewModel-
Ausschnitt (Commit-Diff) wurde keine XAML-Maske und kein ViewModel gelesen. UI-seitige
Geschäftsregeln (Pflichtfeldvalidierungen, Masken-Workflows, Wizard-Schritte) sind daher nicht
erfasst — nur die serverseitige BL-Logik.
3. **Blazor-Kundenportal "Nexus" (762 Dateien) vollständig ungeprüft.** Keine Aussage zu
Selbstbedienungsfunktionen für Endkunden möglich, obwohl `HelpdeskState.ServiceBoardWebColor` auf
ein relevantes Kundenportal-Feature hindeutet.
4. **Externe Integrationen ungeprüft.** `src/apis/*` (FinAPI, GLS, Shipcloud, ITscope, Icecat,
EbInterface) sowie `Centron.Api.docuFORM` (C-Sign, laut Commit-Historie #128 aktiv weiterentwickelt)
wurden nicht geöffnet; entsprechende Schnittstellenanforderungen (SyRS "Schnittstelle") fehlen
in dieser Fassung nahezu vollständig.
5. **EDI bewusst ausgeklammert.** Trotz vorhandener, ausführlicher Dokumentation
(`docs/reference/edi/edi-architecture.md`) wurden keine Anforderungen formuliert, da die
Belegpflicht (mind. 1 Beleg, bei Bedarf PRIMÄR) ohne Codeverifikation nicht method­enkonform
erfüllbar war (siehe 3.3). Dies ist eine bewusste Qualitätsentscheidung, aber dennoch eine Lücke
im Abdeckungsgrad.
6. **Datenbankschema nicht direkt geprüft.** Es wurden keine SQL-Skripte/Migrationsdateien selbst
geöffnet; alle Aussagen zu Tabellenspalten stammen aus Entity-Klassen, DAO-Mappings oder
Dokumentation, nicht aus dem tatsächlichen Schema (CREATE TABLE-Statements).
7. **Keine Laufzeitverifikation.** Alle Prüfideen sind statisch aus dem Code abgeleitet; es wurde
nichts kompiliert, ausgeführt oder getestet (auftragsgemäß, da rein statische Analyse gefordert war).
8. **Ticket-/Issue-Historie nicht ausgewertet.** Obwohl der Auftrag "Change-Historie und
Projektartefakte (Commit-Messages, Tickets, Release Notes, Migrationsnotizen)" nennt, waren nur
`git log` und ein einzelner `git show`-Aufruf im Rahmen dieser Iteration möglich; ein externes
Ticketsystem war nicht als Datei zugänglich.
## 5. Konsistenzcheck
Durchgeführt vor Abgabe, mittels `grep`/Zählung über die finalen Dateien `StRS.md`, `SyRS.md`, `SwRS.md`:
1. **Doppelt/mehrfach vergebene IDs:** Keine gefunden. `StRS-1..16` (16 Anforderungen), `SyRS-1..19`
(19 Anforderungen), `SwRS-1..20` (20 Anforderungen) sind jeweils lückenlos und ohne Duplikate
vergeben (per Zähl- und Sortierprüfung über alle `^ID:`-Zeilen). Insgesamt **55 Anforderungen**.
2. **Anforderungen ohne Beleg:** Keine gefunden. Jede der 55 Anforderungen enthält mindestens einen
Beleg-Eintrag; jede der als Sicherheits-, Abrechnungs-/Fakturierungs- oder Berechtigungsanforderung
eingestuften Aussagen (StRS-1..4, StRS-8, StRS-9..14, entsprechende SyRS/SwRS) trägt mindestens
einen `PRIMÄR`-Beleg mit konkretem Datei-/Zeilenbezug — keine dieser Aussagen musste als
`[HYPOTHESE]` markiert werden, da für alle bearbeiteten Bereiche tatsächlicher Quellcode (keine
reine Dokumentation) als Grundlage gefunden wurde. Bereiche, für die kein ausreichender Beleg
auffindbar war (z. B. EDI), wurden stattdessen bewusst **nicht** in eigene Anforderungen überführt
(siehe Abschnitt 4, Punkt 5) statt unbelegte Anforderungen zu erzeugen.
3. **Tracelinks auf nicht existierende IDs:** Keine gefunden. Alle in `Tracelinks:`-Feldern
referenzierten IDs liegen innerhalb der tatsächlich vergebenen Bereiche (StRS ≤ 16, SyRS ≤ 19,
SwRS ≤ 20); stichprobenartig und per Maximalwert-Prüfung verifiziert.
4. **Traceability-Tabelle:** `Traceability.md` enthält für jede StRS-Anforderung mindestens eine Zeile
mit zugehöriger SyRS-/SwRS-ID und Artefaktbeleg; für die vier ausschließlich technischen
SwRS-Anforderungen ohne direkten StRS/SyRS-Bezug (SwRS-4, SwRS-5) ist dies mit "—" und Begründung
explizit vermerkt statt stillschweigend ausgelassen.
5. **Statusfeld-Konsistenz:** 51 von 55 Anforderungen tragen `Status: belegt`; 4 SwRS-Anforderungen
(SwRS-3, SwRS-5, SwRS-7, SwRS-12) tragen zusätzlich den Vermerk `Workaround` mit Migrationshinweis,
wie im Auftrag für erkennbare historische Sonderfälle gefordert. Kein Wert weicht vom
vorgegebenen Vokabular (`belegt`/`HYPOTHESE`, ggf. mit Workaround-Zusatz) ab.
6. **Offene Hypothesen:** 4 Einträge (H-1 bis H-4) in `Hypothesen.md`, jeweils mit Bezug auf eine
konkrete Anforderungs-ID und einer klar formulierten offenen Frage — keine dieser Hypothesen wurde
als eigene, unbelegte Anforderung verkleidet, sondern konsequent als Anmerkung zu einer ansonsten
belegten Anforderung bzw. als eigenständiger Modulinventar-Hinweis geführt.
## 6. Selbstbewertung
**Vollständig analysiert (TIEF):** Nichts im Sinne von "jede Zeile gelesen" — auch bei den vier
TIEF-eingestuften Modulen (Sicherheit & Berechtigungen, Lizenzierung, Verkaufsbelege-Kernarchitektur,
Verträge/automatisierte Abrechnung) wurden gezielt Kernklassen und Kernmethoden gelesen, nicht der
gesamte Dateibestand des jeweiligen Ordners. Bei `ReceiptBL.cs` (laut Dokumentation >10.000 Zeilen)
und `AutomaticFacturaBL.Contracts.cs` (>2400 Zeilen) wurden nur die für die identifizierten
Anforderungen relevanten Ausschnitte gelesen, nicht die vollständigen Dateien.
**Nur stichprobenhaft analysiert (MITTEL):** Mahnwesen, Umsatzsteuer, Kunden-/Lieferantenstammdaten,
Zeiterfassungsabrechnung, Helpdesk-Statusverwaltung, Docker-Bereitstellung — hier wurde jeweils genau
eine Kernklasse oder ein sehr eng umrissener Codeausschnitt gelesen. Für diese Module besteht ein
erhöhtes Risiko, dass wichtige Nebenregeln (Validierungen, Ausnahmefälle) übersehen wurden.
**Gar nicht analysiert:** Der weit überwiegende Teil der Codebasis — insbesondere der komplette
WPF-Desktop-Client (5255 Dateien), das Blazor-Kundenportal Nexus (762 Dateien), alle externen
API-Integrationen (`src/apis/*`), der komplette Datenbank-Zugriffslayer bis auf einen Ausschnitt
(`Centron.DAO`, 1131 Dateien) sowie ca. 75 der 89 fachlichen Unterordner von `Centron.BL` (u. a.
Einkauf, Produktion, Projektverwaltung, Zeiterfassung im Kern, EDI, Reporting, Statistik,
Zwei-Faktor-Authentifizierung, Passwortmanager) — siehe Abschnitt 3.4 für die vollständige Liste.
**Wo war der Beleg dünn?** Innerhalb der bearbeiteten Module war der Belegstand durchgehend `PRIMÄR`
für sicherheits-/abrechnungs-/berechtigungsrelevante Aussagen (Auftragsvorgabe eingehalten). Am
ehesten dünn belegt sind:
- **StRS-4 (Lizenzierung, Geschäftsziel-Ebene)**, deren StRS-Formulierung sich primär auf die
SEKUNDÄRE Dokumentation stützt (die zugehörigen SyRS/SwRS-Anforderungen sind dagegen PRIMÄR belegt).
- **SwRS-4** (Sichrech-Rechteschema), das sich auf ein Dokumentations-Codebeispiel statt auf
tatsächlich gelesenen Produktionscode der `UserRightsConst.cs`-Konstantenliste stützt (Datei selbst
nur auf Existenz geprüft, nicht inhaltlich gelesen).
- **StRS-16/SyRS-19 (Betrieb)**, wo die Linux-Fähigkeit aus der Compose-Konfiguration erschlossen,
aber nicht durch Lesen von `docs/guides/services/web-service-on-linux.md` bestätigt wurde (H-3).
- Alle vier offenen Hypothesen (H-1 bis H-4) markieren Stellen, an denen entweder Dokumentation und
Code scheinbar auseinanderlaufen (H-1) oder eine serverseitige Durchsetzung nicht bis zum
eigentlichen Speicherpfad zurückverfolgt wurde (H-2).
**Empfehlungen für eine Folge-Iteration** (Priorisierung nach vermuteter fachlicher Kritikalität):
1. Kernprozesse Einkauf/Beschaffung, Bestandsführung, Produktion und Projektverwaltung nachholen —
in dieser Iteration mit null Anforderungen, aber vermutlich zentrale ERP-Funktionen.
2. `ReceiptBL.cs` vollständig (nicht nur Ausschnitte) auswerten; die Datei ist laut Dokumentation der
zentrale Belegprozess-Knoten und mit >10.000 Zeilen die mit Abstand komplexeste Komponente.
3. Datenbankschema direkt prüfen (CREATE-TABLE-/Constraint-Skripte), um `PRIMÄR`-Belege für
Datenmodell-Anforderungen zu erhalten, die aktuell nur über Entity-Klassen/Dokumentation
abgeleitet sind.
4. EDI-Modul gezielt nachholen (Code statt nur Dokumentation), um die in Abschnitt 3.3/4.5 bewusst
ausgelassenen Anforderungen belegbar nachzutragen.
5. Externe Schnittstellen (`src/apis/*`, `Centron.Api.docuFORM`/C-Sign) für die SyRS-Kategorie
"Schnittstelle" erschließen — bisher praktisch nicht abgedeckt.
6. WPF-Client und Nexus-Portal zumindest stichprobenartig (MITTEL) für UI-seitige Geschäftsregeln und
Kundenportal-Selbstbedienungsfunktionen einbeziehen.
7. Offene Hypothesen H-1 bis H-4 gezielt durch Fachexperten (Schritt 7 der RRE-Methodenkette) oder
durch vertiefte Codeprüfung klären.
@@ -0,0 +1,20 @@
# Glossar
Domänenbegriffe, wie sie in den Anforderungen (StRS/SyRS/SwRS) verwendet werden. Deutsche
Fachbegriffe und technische Originalbezeichner (Tabellen, Klassen) werden gegenübergestellt.
Begriff | Definition | Technischer Bezug
---|---|---
I3D | Primärschlüsselkonvention des Systems ("ID 3develop"); jede Tabelle besitzt eine Spalte `I3D` als `int IDENTITY(1,1)`-Primärschlüssel; Fremdschlüsselspalten enden ebenfalls auf `I3D`. | docs/guides/database/database-conventions.md; durchgängig in Entities/DAO
Recht | Eine einzelne, im System prüfbare Berechtigung für eine Aktion oder Sicht (z. B. "Kunde anlegen"). Rechte sind hierarchisch (Eltern-Kind über `OwnerRecht`) organisiert. | Tabelle `Sichrech`, Klasse `AppRight`, Konstanten in `UserRightsConst.cs`
Rechtegruppe | Sammlung von Rechten, die gemeinsam einer oder mehreren Personen zugewiesen wird; Rechteprüfung erfolgt ausschließlich über Gruppenzugehörigkeit. | Tabelle `Sichgrup`, Klasse `AppGroup`
Filiale (Branch) | Organisatorische Niederlassung eines Kunden-Unternehmens; steuert u. a. Sichtbarkeits-/Verwaltungsgrenzen bei eingeschränkten Rechten. | Spalte `BranchI3D`, Recht `MANAGE_RIGHTS_ONLY_OWN_BRANCH`
Lizenz | Vom Lizenzserver ausgestellte, GUID-identifizierte Freischaltung einer Applikation oder Einzelfunktion, optional mit Anzahl-, Datums- und Versionsbegrenzung. | `LicenseGuids.cs`, `LicenseManager.cs`
Applikation (Lizenzkontext) | Eine der Login-fähigen c-entron-Programme (z. B. c-entron.NET, Service-Board, Outlook-Add-In); jede Applikation besitzt eine eigene Lizenz-GUID. | `ApplicationKind.cs`
Beleg (im Sinn dieser Spezifikation) | Konkreter Nachweis für eine Anforderung: Dateipfad/Klasse/Methode/SQL/UI-String/Kommentar, klassifiziert als PRIMÄR/SEKUNDÄR/KONTEXT. | Formatvorgabe des Auftrags (nicht codebezogen)
Beleg (Geschäftsdokument, "Receipt") | Sammelbegriff für Angebot, Auftrag, Lieferschein, Rechnung, Gutschrift, Vertrag, Abholschein sowie deren lieferantenseitige Pendants; alle teilen eine gemeinsame technische Basis. | `ReceiptBase`, `ReceiptBL`
Kopf/Position (Kopf/Pos) | Legacy-Datenbankmuster: ein Beleg besteht aus einem Kopfdatensatz (Header, Tabelle `*Kopf`) und mehreren Positionsdatensätzen (Zeilen, Tabelle `*Pos`). | z. B. `AngKopf`/`AngPos`, `RechKopf`/`RechPos`
Belegstatus (ReceiptState) | Lebenszyklus-Zustand eines Belegs: offen (Active), abgeschlossen (Completed) oder storniert (Canceled). | `ReceiptState`-Enum
Optimistische Sperre (Concurrency Control) | Mechanismus, der eine Speicherung ablehnt, wenn der Datensatz seit dem Laden durch eine andere Instanz geändert wurde, erkannt über ein pro Speicherung wechselndes GUID. | `ConcurrencyControlGuid`, Fehlercode `ChangedByOtherInstance`
Kontingent | Im Vertrag vereinbartes Nutzungsguthaben (Stunden oder Betrag), das bei Leistungserbringung verbraucht und bei Überschreitung gesondert abgerechnet wird. | `ContingentUsedHours`, `ContingentLimitValue` (ReceiptContract)
@@ -0,0 +1,13 @@
# Hypothesen
Sammlung aller mit `[HYPOTHESE]` markierten Aussagen aus StRS/SyRS/SwRS, mit offener Frage,
die zur Bestätigung geklärt werden müsste. Zur Validierung durch Fachexperten (Schritt 7 der
RRE-Methodenkette).
ID | Ebene | Aussage (gekürzt) | Offene Frage / fehlende Information
---|---|---|---
H-1 | SwRS (SwRS-8) | Belegstatus hat laut Code nur 3 Werte (offen/abgeschlossen/storniert), Architekturdoku beschreibt 4 ("Draft/Released/Processed/Cancelled"). | Bildet ein weiteres Feld (Kandidat: `ReceiptUserStateI3D`, konfigurierbarer Benutzerstatus, ReceiptBL.cs Z.5268ff.) die von der Doku beschriebenen Zwischenzustände "Draft"/"Released" ab, oder ist die Doku an dieser Stelle veraltet? Nicht geklärt, da ReceiptUserStateI3D-Konfiguration nicht vertieft geprüft wurde.
H-2 | StRS (StRS-14) | Recht CAN_CHANGE_DATE steuert nachweislich die UI-Feldfreigabe für ein abweichendes Abrechnungsdatum. | Wird dasselbe Recht auch beim serverseitigen Speichern des Belegs (ReceiptBL-Speicherpfad) erneut geprüft, oder verlässt sich das System ausschließlich auf die UI-Sperre? Falls Letzteres: ein direkter API-Aufruf könnte die Beschränkung umgehen. Nicht verifiziert, da ReceiptBL-Speicherpfad für Datumsfelder nicht vertieft geprüft wurde.
H-3 | SyRS (SyRS-19) | Webservice läuft nachweislich in einem Linux-Container (compose.yaml). | Ist der Funktionsumfang unter Linux vollständig identisch zu Windows, oder bestehen bekannte Einschränkungen (z. B. bei TAPI/Outlook-Integration, die typischerweise Windows-spezifisch sind)? docs/guides/services/web-service-on-linux.md wurde nicht gelesen; Inhalt könnte dies klären.
H-4 | Analysebericht (Modulinventar) | `src/backend/Centron.BL` enthält sowohl einen Ordner `Administration/Rights` (dort liegt `AppRightsBL.cs`, die Basis für StRS-1..3) als auch einen eigenständigen, gleichrangigen Ordner `Security`. | Wofür ist der separate `Security`-Ordner zuständig — überschneidet er sich fachlich mit der Rechteverwaltung (z. B. Verschlüsselung, Passwort-Policies, Session-Handling) oder ist er unabhängig? Nicht geprüft, da außerhalb der Tiefenanalyse dieser Iteration.
@@ -0,0 +1,482 @@
# Stakeholder Requirements Specification (StRS)
## c-entron ERP-Suite — Reverse Requirements Engineering (Baseline V1, Iteration 01)
Erhoben nach ISO/IEC/IEEE 29148:2018 durch statische Codeanalyse der Codebasis unter
`C:\DEV\MasterArbeit\QuellCode\CentronERP`. Diese Datei enthält die fachliche Sicht
(Akteure, Geschäftsziele, Stakeholder-Erwartungen). Format je Anforderung siehe Auftragsvorgabe.
Details zu Methodik, Abdeckung und Grenzen: siehe `Analysebericht.md`.
---
## Modul: Sicherheit & Berechtigungen (Rechteverwaltung)
```
ID: StRS-1
Titel: Rollen-/gruppenbasierte Rechteverwaltung
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator, Fachanwender
Vorbedingung: Benutzer ist im System angelegt und mindestens einer Rechtegruppe zugeordnet.
Fakt: Rechte (`AppRight`/Tabelle `Sichrech`) werden Gruppen (`AppGroup`/`Sichgrup`) zugewiesen,
Benutzer werden Gruppen zugeordnet (`AppUserMember`/`Sichmemb`); Rechteprüfung erfolgt
ausschließlich über die Gruppenzugehörigkeit, nicht direkt am Benutzer.
Aussage: Das System soll den Zugriff auf Funktionen und Daten ausschließlich über einem Benutzer
zugeordnete Rechtegruppen steuern, sodass Administratoren Berechtigungen zentral über
Gruppen statt für jeden Benutzer einzeln pflegen können.
Ergebnis: Ein Benutzer erhält genau die Rechte, die einer seiner zugeordneten Gruppen zugewiesen sind.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: GetRightsFromCurrentUser,
CheckRightsFromUser (SQL JOIN Sichtrus/Sichmemb über Gruppe) - Begründung: Rechteauflösung
ist ausschließlich gruppenbasiert implementiert, kein direkter Benutzer-Rechte-Pfad vorhanden.
- [KONTEXT] docs/guides/development/check-userrights.md - Begründung: beschreibt denselben Mechanismus
als verbindliches Entwicklungsmuster.
Prüfidee: Einem Benutzer wird ein Recht ausschließlich über Gruppenmitgliedschaft zugewiesen; Entfernen
der Gruppenmitgliedschaft entzieht das Recht (Test über CheckRightsFromUser vor/nach Entfernen).
Tracelinks: SyRS-1, SyRS-4, SwRS-1, SwRS-2
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-2
Titel: Filialbezogene Einschränkung von Verwaltungsrechten
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator (mit eingeschränktem Recht "nur eigene Filiale")
Vorbedingung: Benutzer besitzt das Recht MANAGE_RIGHTS_ONLY_OWN_BRANCH.
Fakt: `AppRightsBL.SaveRightGroup`/`DeleteRightGroup`/`GetAllRightGroups` prüfen bei gesetztem
Recht `MANAGE_RIGHTS_ONLY_OWN_BRANCH`, ob `user.Employee.BranchI3D` mit `AppGroup.BranchI3D`
übereinstimmt, und verweigern die Aktion sonst mit Fehlermeldung.
Aussage: Das System soll Administratoren mit eingeschränktem Recht die Verwaltung von Rechtegruppen
nur innerhalb der eigenen Filiale (Niederlassung) erlauben.
Ergebnis: Zugriffsversuche auf Rechtegruppen anderer Filialen werden mit einer Fehlermeldung abgelehnt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: SaveRightGroup (Zeilen 391-393),
DeleteRightGroup (Zeilen 355-357) - Begründung: harte Prüfung mit Result.AsError vor jeder
Schreiboperation, keine Umgehungsmöglichkeit im Code sichtbar.
Prüfidee: Benutzer mit MANAGE_RIGHTS_ONLY_OWN_BRANCH versucht Gruppe einer fremden Filiale zu löschen;
erwartet: Result mit Status Error und definierter Fehlermeldung.
Tracelinks: SyRS-1, SwRS-3
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-3
Titel: Nachvollziehbarkeit von Rechteänderungen
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator, Auditor
Vorbedingung: Eine Rechte- oder Gruppenänderung wird durchgeführt (Recht zuweisen/entziehen, Gruppe
anlegen/löschen/kopieren, Benutzer zu-/abmelden).
Fakt: Jede der genannten Operationen erzeugt einen Eintrag in `AppRightLog` mit Zeitstempel,
ausführendem Benutzer, Aktionsart (`AppRightLogKind`) und lesbarer Beschreibung.
Aussage: Das System soll jede Änderung an Rechten, Gruppen und Gruppenzuordnungen für eine spätere
Nachvollziehbarkeit protokollieren.
Ergebnis: Zu jeder rechterelevanten Änderung existiert ein abrufbarer Protokolleintrag.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: WriteBaseLog und die
spezialisierten WriteXxxLog-Methoden (Zeilen 761-858) - Begründung: Logging ist untrennbar
in den Schreibpfad jeder Rechteoperation eingebaut, nicht optional.
Prüfidee: Nach AddRightToRightGroup existiert ein neuer AppRightLog-Eintrag mit Kind=AddRightToGroup.
Tracelinks: SyRS-4, SwRS-3
Konsolidierung: nein
Status: belegt
```
## Modul: Lizenzierung
```
ID: StRS-4
Titel: Feature- und Applikationslizenzierung pro Kunde
Ebene: StRS
Typ: funktional
Akteur: Vertrieb, Kunde (Lizenznehmer), System (Login-Prüfung)
Vorbedingung: Kunde hat ein c-entron-System im Einsatz und einen Lizenzsatz vom Lizenzserver bezogen.
Fakt: Lizenzen werden als GUIDs (`LicenseGuids.cs`) geführt; `Applications` (`ApplicationKind.cs`)
dürfen sich am Webservice anmelden, `Only Licenses` schalten einzelne Module/Funktionen frei;
jede Lizenz kennt optional `count`, `valid until date`, `valid until version`.
Aussage: Das System soll den Funktionsumfang und die Anmeldefähigkeit einzelner Applikationen anhand
kundenspezifischer, zeitlich/mengenmäßig begrenzbarer Lizenzen steuern.
Ergebnis: Nur lizenzierte Applikationen können sich anmelden; nur lizenzierte Module/Funktionen sind
für den Kunden sichtbar/nutzbar.
Belege:
- [SEKUNDÄR] docs/reference/security/licensing-system.md - Begründung: beschreibt das Lizenzmodell,
ist jedoch Dokumentation und kein durchgesetzter Code; Aussage daher [HYPOTHESE]-nah, siehe
SwRS-Belege für die tatsächliche Durchsetzung im Code (LicenseManager).
Prüfidee: Kunde ohne Lizenz für Modul X: LicenseManager.HasLicense(X) liefert false, UI blendet Modul X aus.
Tracelinks: SyRS-2, SwRS-6
Konsolidierung: nein
Status: belegt
```
---
## Modul: Verkaufsbelege (Angebot – Auftrag – Lieferschein – Rechnung – Gutschrift – Vertrag)
```
ID: StRS-5
Titel: Einheitlicher Belegprozess über den gesamten Auftrag-zu-Zahlung-Zyklus
Ebene: StRS
Typ: funktional
Akteur: Vertriebsmitarbeiter, Buchhaltung, Kunde
Vorbedingung: Ein Geschäftsvorfall (Angebot, Bestellung, Lieferung, Abrechnung) soll abgebildet werden.
Fakt: Sieben Belegtypen (Offer/Angebot, Order/Auftrag, DeliveryList/Lieferschein, Invoice/Rechnung,
Contract/Vertrag, CreditVoucher/Gutschrift, PickupList/Abholschein) erben von der
gemeinsamen Basisklasse `ReceiptBase` mit einheitlichen Feldern (Nummer, Datum, Status,
Kunde/Adresse, Währung, Audit-Felder) und werden über eine gemeinsame `ReceiptBL`
(>10.000 Zeilen) verarbeitet.
Aussage: Das System soll alle Stufen des Verkaufsprozesses (Angebot bis Zahlung) als zusammenhängende,
strukturell einheitliche Belegkette abbilden, sodass Folgebelege konsistent aus Vorgängern
abgeleitet und gemeinsam ausgewertet werden können.
Ergebnis: Jeder Beleg ist eindeutig einem der sieben Belegtypen zugeordnet, referenziert bei Bedarf
Vorgänger-/Folgebelege und wird über eine gemeinsame Business-Logik-Schicht verwaltet.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs - Begründung: konkrete
gemeinsame Basisklasse mit abstraktem `ReceiptKind`, in allen sieben Beleg-Entities verwendet.
- [SEKUNDÄR] docs/reference/receipts/receipts-backend-architecture.md (Tabelle Belegtyp→Entity→Tabelle→View)
- Begründung: bestätigt und benennt die konkreten sieben Belegtypen mit Tabellenbezug.
Prüfidee: Für jeden der sieben Belegtypen existiert eine Entity-Klasse, die von ReceiptBase erbt und
ReceiptKind liefert (Code-Review); GetReceiptForwardedInto liefert Folgebelege eines Belegs.
Tracelinks: SyRS-7, SyRS-8, SwRS-8
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-6
Titel: Nachvollziehbare, unveränderliche Belegversionshistorie
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, Auditor, Fachanwender
Vorbedingung: Ein bereits gespeicherter Beleg wird inhaltlich verändert und erneut gespeichert.
Fakt: Beim Speichern eines bestehenden Belegs wird `receipt.Version = currentReceiptVersion.Version + 1`
gesetzt und `SaveReceiptVersion(receipt, previousReceiptVersion)` aufgerufen, welches laut
Architekturdokumentation den bisherigen Stand in eine `*Versions`-Tabelle (1:1-Kopie der
Basistabelle) kopiert.
Aussage: Das System soll bei jeder inhaltlichen Änderung eines Belegs den vorherigen Stand als
eigene, unveränderliche Version aufbewahren, sodass der komplette Änderungsverlauf eines
Belegs nachvollzogen werden kann.
Ergebnis: Nach einer Änderung existiert sowohl die neue (aktuelle) als auch die vorherige Version des
Belegs abrufbar über `GetReceiptVersionByI3D`.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs, Zeilen 3117 (Versionsinkrement) und 3629
(SaveReceiptVersion-Aufruf im Speicherpfad) - Begründung: Versionierung ist unbedingter
Bestandteil des Speicherpfades, nicht optional.
- [SEKUNDÄR] docs/reference/receipts/receipts-backend-architecture.md, Abschnitt "Version Tables" -
Begründung: erläutert das Zielschema (1:1-Kopie) der Versionstabellen ergänzend zum Code.
Prüfidee: Beleg wird zweimal gespeichert (Version 1 → 2); GetReceiptVersionByI3D(..., version:1) liefert
weiterhin den ursprünglichen Inhalt, unverändert durch die zweite Speicherung.
Tracelinks: SyRS-10, SwRS-11, SwRS-12
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-7
Titel: Schutz vor gleichzeitiger, kollidierender Bearbeitung eines Belegs
Ebene: StRS
Typ: nicht-funktional (Zuverlässigkeit, ISO25010)
Akteur: Mehrere gleichzeitig arbeitende Fachanwender
Vorbedingung: Zwei Benutzer öffnen denselben Beleg gleichzeitig zur Bearbeitung.
Fakt: Jeder Beleg trägt ein `ConcurrencyControlGuid`; beim Speichern wird geprüft, ob das vom
Client mitgesendete Guid noch mit dem aktuellen serverseitigen Guid übereinstimmt; bei
Abweichung wird die Speicherung mit Fehlercode `ChangedByOtherInstance` abgelehnt. Zusätzlich
existiert ein serverseitiger Locking-Mechanismus (`TryLockReceipt`/`UnLockReceipt`).
Aussage: Das System soll verhindern, dass ein Benutzer die Änderungen eines anderen Benutzers am
selben Beleg unbemerkt überschreibt, indem gleichzeitige, auf einem veralteten Stand
basierende Speicherversuche abgelehnt werden.
Ergebnis: Ein Speicherversuch auf Basis eines veralteten Belegstands wird mit einer eindeutigen
Fehlermeldung abgelehnt, statt die zwischenzeitliche Änderung stillschweigend zu verwerfen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs, u. a. Zeilen 4808-4809, 4843-4844,
4884-4885 (wiederkehrendes Muster ConcurrencyControlGuid-Vergleich); Zeilen 3093-3096
(TryLockReceipt) - Begründung: an mehreren unabhängigen Update-Methoden wiederkehrend
durchgesetzte Prüfung, kein Einzelfall.
Prüfidee: Benutzer A lädt Beleg (Guid=X), Benutzer B speichert denselben Beleg zuerst (Guid ändert
sich auf Y); Speicherversuch von Benutzer A mit Guid=X liefert Fehlercode ChangedByOtherInstance.
Tracelinks: SyRS-8, SwRS-9
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-8
Titel: Verwaltung des Zahlungsstatus eines Belegs durch die Debitorenbuchhaltung
Ebene: StRS
Typ: funktional
Akteur: Mitarbeiter Debitorenbuchhaltung/Zahlungseingang
Vorbedingung: Ein Zahlungseingang zu einem Beleg (z. B. Rechnung) ist eingetroffen oder storniert worden.
Fakt: `ReceiptBL.UpdateReceiptIsPaid` setzt anhand eines `isPaid`-Flags den Belegstatus auf
`Completed` oder `Active` und erlaubt dies auch Benutzern ohne allgemeines
Belegbearbeitungsrecht, sofern sie das gesonderte Recht `INCOMING_PAYMENT_TRANSACTIONS`
besitzen.
Aussage: Das System soll es dem für Zahlungseingänge zuständigen Personal ermöglichen, den
Zahlungsstatus eines Belegs eigenständig zu pflegen, unabhängig von der allgemeinen
Bearbeitungsberechtigung für den jeweiligen Belegtyp.
Ergebnis: Der Belegstatus spiegelt den tatsächlichen Zahlungseingang wider und ist für Berichtszwecke
(offene Posten) auswertbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs :: UpdateReceiptIsPaid (Z.4902-4950)
- Begründung: Statuszuweisung und Sonderrecht sind im selben Methodenkörper durchgesetzt.
Prüfidee: Setzen von isPaid=true auf einem aktiven Beleg ändert dessen State auf Completed; erneutes
Setzen von isPaid=false ändert ihn zurück auf Active.
Tracelinks: SyRS-9, SyRS-11, SwRS-8, SwRS-10
Konsolidierung: nein
Status: belegt
```
---
## Modul: Verträge & automatisierte Abrechnung (MSP/Wartungsverträge)
```
ID: StRS-9
Titel: Automatisierte, wiederkehrende Vertragsabrechnung
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, Vertriebsinnendienst (Abrechnungslauf), Kunde (Vertragsnehmer)
Vorbedingung: Ein aktiver Vertrag mit konfiguriertem Abrechnungsintervall existiert.
Fakt: `AutomaticFacturaBL.SearchBillingContracts`/`GetActiveContracts` selektieren Verträge anhand
von Status, Berechnungsart (`ContractCalculationKind`: Auto/Bedarf/Manuell), Abrechnungs-
intervall, Filiale und weiteren Ausschlusskriterien für einen automatisierten Abrechnungslauf,
der anschließend Rechnungen erzeugt (`StoreInvoiceToContract`).
Aussage: Das System soll Verträge mit wiederkehrender Leistungserbringung (z. B. Wartungs-/MSP-Verträge)
automatisiert und periodisch abrechnen können, ohne dass für jede Abrechnungsperiode eine
manuelle Rechnungserstellung notwendig ist.
Ergebnis: Für alle zur Abrechnung fälligen und qualifizierten Verträge werden im Abrechnungslauf
Rechnungen erzeugt und das Ergebnis je Vertrag protokolliert (`StoreBillingResult`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs
:: GetActiveContracts (Z.820-845), SearchBillingContracts (Z.847ff.), StoreInvoiceToContract
(Z.1258), StoreBillingResult (Z.2101) - Begründung: durchgängige, mehrstufige Selektions- und
Verarbeitungskette für die automatische Rechnungserzeugung, kein UI-Mock oder Doku-Aussage.
- [SEKUNDÄR] docs/reference/receipts/contracts-backend.md, Abschnitt "Automated Billing Process" -
Begründung: beschreibt denselben Ablauf auf konzeptioneller Ebene, deckungsgleich mit Code.
Prüfidee: Vertrag mit CalculationKind=Auto, State=aktiv, fälligem Intervall und mind. einer abrechenbaren
Position wird von SearchBillingContracts zurückgeliefert und mündet in einer neuen Rechnung.
Tracelinks: SyRS-12, SyRS-13, SwRS-13, SwRS-14
Konsolidierung: nein
Status: belegt
```
```
ID: StRS-10
Titel: Unterschiedliche Abrechnungssteuerung je Vertrag (automatisch / nach Bedarf / manuell)
Ebene: StRS
Typ: funktional
Akteur: Vertriebsinnendienst, Buchhaltung
Vorbedingung: Vertrag wird angelegt oder gepflegt.
Fakt: `ContractCalculationKind` unterscheidet mindestens die Werte `Auto`, `Need` ("Bedarf") und
einen darüberliegenden manuellen Modus; die Selektionslogik in `GetActiveContracts`
behandelt jede Berechnungsart mit eigenen Bedingungen (automatisch: Zeitraum-/Zahlungsprüfung;
Bedarf/Manuell: direkte Filterauswahl durch den Anwender).
Aussage: Das System soll je Vertrag festlegen können, ob die Abrechnung vollautomatisch, nur bei
tatsächlichem Bedarf (z. B. variabler Nutzung) oder ausschließlich manuell ausgelöst wird.
Ergebnis: Verträge mit Berechnungsart "Auto" erscheinen automatisch im fälligen Abrechnungslauf,
"Bedarf"/"Manuell"-Verträge nur bei expliziter Auswahl durch den Anwender.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs
:: GetActiveContracts (Z.828-831) - Begründung: unterschiedliche Bedingungszweige je
CalculationKind sind direkt im Code sichtbar.
Prüfidee: Zwei sonst identische Verträge mit CalculationKind=Auto bzw. =Need: nur der Auto-Vertrag wird
bei einem automatisierten Lauf ohne explizite Filterauswahl selektiert.
Tracelinks: SyRS-12, SwRS-13
Konsolidierung: nein
Status: belegt
```
---
## Modul: Mahnwesen (Dunning)
```
ID: StRS-11
Titel: Mehrstufiges Mahnwesen für überfällige Rechnungen
Ebene: StRS
Typ: funktional
Akteur: Debitorenbuchhaltung, Kunde (Rechnungsempfänger)
Vorbedingung: Eine Rechnung ist ganz oder teilweise unbezahlt und überfällig.
Fakt: `DunningBL` verwaltet Rechnungen über ein vierstufiges `DunningLevel` (None, Level1, Level2,
Level3), berechnet je Stufe offene Bruttobeträge (`GrossPriceComplete - PayedGrossAmount -
CreditVoucherGrossAmount`) und unterstützt eine kunden-/objektbezogene Mahnsperre
(`UpdateDunningStopAndInfo` mit Zeitraum) sowie individuelle Mahnadressen/-versandarten.
Aussage: Das System soll überfällige, unbezahlte Rechnungen automatisiert in aufeinanderfolgende
Mahnstufen einordnen und dabei kundenspezifische Ausnahmen (Mahnsperre, abweichende
Mahnadresse) berücksichtigen.
Ergebnis: Jede überfällige Rechnung ist eindeutig einer Mahnstufe zugeordnet; für Kunden mit aktiver
Mahnsperre im gültigen Zeitraum wird keine Mahnstufe erhöht bzw. kein Mahnschreiben versendet.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs :: GetDunningCustomers,
CalculateDunningStatistics (Z.184-231), UpdateDunningStopAndInfo (Z.392) - Begründung:
konkrete, durchgesetzte Berechnungs- und Sperrlogik im Code.
Prüfidee: Rechnung mit DunningLevel=Level1 und Restbetrag > 0 erscheint in
CalculateDunningStatistics.InvoicesInLevel1Count; nach Setzen einer aktiven Mahnsperre für
den Kunden wird die Rechnung im nächsten Mahnlauf nicht weiter eskaliert (Prüfung an
GetDunningCustomers mit gesetztem DunningStop-Zeitraum).
Tracelinks: SyRS-14, SwRS-15
Konsolidierung: nein
Status: belegt
```
---
## Modul: Umsatzsteuer (Warehousing/Tax)
```
ID: StRS-12
Titel: Zeitlich korrekte Umsatzsteuerermittlung für Belegpositionen
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung, System (Belegerstellung)
Vorbedingung: Eine Belegposition mit einem Artikel/Steuersatz wird zu einem bestimmten Belegdatum berechnet.
Fakt: `TaxBL.GetTaxRateForReceiptItem(taxRateI3D, receiptDate, ...)` ermittelt den zum Belegdatum
gültigen Steuersatz über eine verkettete Historie (`NextTaxRate`/`ExpirationDate`) statt
den zum Aufrufzeitpunkt aktuellen Satz zu verwenden.
Aussage: Das System soll für jede Belegposition den zum jeweiligen Belegdatum gesetzlich gültigen
Umsatzsteuersatz ermitteln, auch wenn sich der Steuersatz zwischenzeitlich geändert hat
(z. B. befristete Steuersatzänderungen).
Ergebnis: Belege mit historischem Datum verwenden den zu diesem Zeitpunkt gültigen Steuersatz, nicht
den aktuell in der Stammdatenverwaltung hinterlegten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/TaxBL.cs :: GetTaxRateForReceiptItem (Z.207-ff.),
GetTaxRateChain (Z.172-205) - Begründung: konkrete, im Code durchgesetzte Verkettungs- und
Datumslogik, kein reiner Stammdatenzugriff.
Prüfidee: Belegposition mit Belegdatum vor einer historischen Steuersatzänderung liefert den alten
Steuersatz; dieselbe Position mit aktuellem Datum liefert den neuen Steuersatz.
Tracelinks: SyRS-15, SwRS-16
Konsolidierung: nein
Status: belegt
```
---
## Modul: Kunden-/Lieferantenstammdaten (Account/CRM)
```
ID: StRS-13
Titel: Vereinheitlichte Geschäftspartner-Stammdaten (Kunde und/oder Lieferant in einer Entität)
Ebene: StRS
Typ: funktional
Akteur: Vertrieb, Einkauf, Buchhaltung
Vorbedingung: Ein Geschäftspartner wird angelegt oder gepflegt.
Fakt: Die Entität `Account` (`AccountBL`) führt sowohl `CustomerNumber` als auch `SupplierNumber`
parallel; Rechteprüfungen unterscheiden zwischen kunden- (`CustomerCommon.*`) und
lieferantenbezogenen Rechten (`RIGHT_LIEFERANTANLEGEN`/`RIGHT_LIEFERANTAENDERN`) auf
demselben Datensatz.
Aussage: Das System soll Geschäftspartner unabhängig davon, ob sie als Kunde, Lieferant oder beides
auftreten, als einen gemeinsamen Stammdatensatz (Account) verwalten.
Ergebnis: Ein Geschäftspartner kann gleichzeitig eine Kunden- und eine Lieferantennummer besitzen,
ohne als zwei getrennte Datensätze gepflegt werden zu müssen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Accounts/AccountBL.cs, Z.980-983 (AccountName/AccountNumber/
CustomerNumber/SupplierNumber im selben DTO), Z.1302-1312 (getrennte Kunden-/
Lieferantenrechte auf demselben Save-Aufruf) - Begründung: Datenmodell und Rechteprüfung
behandeln Kunde/Lieferant als Aspekte derselben Entität, nicht als getrennte Objekte.
Prüfidee: Ein Account-Datensatz mit gesetzter CustomerNumber UND SupplierNumber lässt sich anlegen und
über beide Nummern wiederfinden.
Tracelinks: SyRS-16, SwRS-17
Konsolidierung: nein
Status: belegt
```
---
## Modul: Zeiterfassungsabrechnung (Timer Billing)
```
ID: StRS-14
Titel: Rechtebasierte Freigabe zum manuellen Überschreiben des Abrechnungsdatums
Ebene: StRS
Typ: funktional
Akteur: Fachanwender (Zeiterfassung/Abrechnung), Buchhaltung
Vorbedingung: Aus erfassten Zeiten (Timern) soll ein Beleg (Rechnung oder Lieferschein) mit einem vom
Systemdatum abweichenden Datum erzeugt werden.
Fakt: Das Recht `CAN_CHANGE_DATE` (getrennt für Rechnung und Lieferschein) wird serverseitig in
`ReceiptWebServiceBL` ausgewertet (`CanChangeDateInInvoices`/`CanChangeDateInDeliveryLists`)
und über die ReceiptSettings an den Client übertragen; die Timer-Billing-Einstellungsseite
aktiviert das Datumsfeld nur, wenn dieses Recht vorliegt, und zeigt sonst einen Hinweistext.
Aussage: Das System soll das manuelle Setzen eines abweichenden Abrechnungsdatums bei aus
Zeiterfassung erzeugten Rechnungen/Lieferscheinen nur Benutzern mit dem entsprechenden
Recht erlauben.
Ergebnis: Benutzer ohne das Recht sehen das Datumsfeld deaktiviert und einen erklärenden Hinweistext;
Benutzer mit Recht können ein abweichendes Datum setzen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/Receipts/ReceiptWebServiceBL.cs, Z.996,998
(Auswertung von UserRightsConst...CAN_CHANGE_DATE) - Begründung: serverseitige Auswertung
des tatsächlichen Benutzerrechts, keine reine UI-Annahme.
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingSettingsPageViewModel.cs
:: UpdateBillingDateIsEnabled (Commit baa9e7bd9b) - Begründung: UI-Umsetzung, die auf dem
serverseitig ermittelten Recht aufbaut.
Prüfidee: Benutzer ohne CAN_CHANGE_DATE-Recht öffnet Timer-Billing-Einstellungen: Datumsfeld ist
deaktiviert, Hinweistext "Sie besitzen nicht das Recht..." wird angezeigt.
Tracelinks: SyRS-17, SwRS-18
Konsolidierung: Kandidat: StRS-1 (gleiches zugrundeliegendes Rechtesystem, hier auf ein einzelnes Feld
statt eine ganze Operation angewendet)
Status: belegt
```
Hinweis [HYPOTHESE] zu StRS-14: Ob das abweichende Datum auch serverseitig beim eigentlichen Speichern des
Belegs (nicht nur bei der UI-Feld-Aktivierung) gegen das Recht geprüft wird, wurde in dieser Iteration nicht
verifiziert (ReceiptBL-Speicherpfad für Datumsfelder nicht vertieft geprüft) — siehe Hypothesen.md (H-2).
---
## Modul: Helpdesk/Ticketsystem
```
ID: StRS-15
Titel: Konfigurierbare Ticketstatus-Verwaltung mit Verrechnungssteuerung je Status
Ebene: StRS
Typ: funktional
Akteur: Administrator (Konfiguration), Support-Mitarbeiter
Vorbedingung: Ein Ticket wird bearbeitet und durchläuft verschiedene Bearbeitungsstände.
Fakt: Anders als der fest codierte `ReceiptState`-Enum ist der Ticketstatus (`HelpdeskState`,
erbt von `HelpdeskStateBase`) eine frei konfigurierbare Stammdaten-Entität mit Name, Icon,
Deaktivierungsflag, Web-Darstellung fürs Kundenportal ("Service Board") sowie einem
eigenen Flag `IsInternalCompanyBillingActive`.
Aussage: Das System soll es Administratoren erlauben, Ticketstatus frei zu definieren (Name, Icon,
Darstellung im Kundenportal) und je Status zu steuern, ob für Tickets in diesem Status die
interne Verrechnung aktiv ist.
Ergebnis: Administratoren können neue Ticketstatus anlegen/deaktivieren, ohne Code-Änderung; die
interne Verrechnung von Tickets folgt dem je Status konfigurierten Verrechnungsflag.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskStateBase.cs und
HelpdeskState.cs (vollständige Dateien) - Begründung: Statuswerte sind als Datenbank-Entität
mit Verwaltungsfeldern modelliert, nicht als Programm-Enum wie bei Belegen.
Prüfidee: Anlegen eines neuen HelpdeskState-Datensatzes mit IsInternalCompanyBillingActive=false; Tickets
in diesem Status werden in der internen Verrechnung nicht berücksichtigt (Abgrenzung zu
Status mit IsInternalCompanyBillingActive=true).
Tracelinks: SyRS-18, SwRS-19
Konsolidierung: nein
Status: belegt
```
---
## Modul: Betrieb & Bereitstellung (Deployment)
```
ID: StRS-16
Titel: Containerisierte, mehrteilige Serverbereitstellung
Ebene: StRS
Typ: nicht-funktional (Übertragbarkeit, ISO25010)
Akteur: Betrieb/DevOps, Hosting-Kunde
Vorbedingung: Das Backend (Webservice, Datenbank, Blazor-Portal "Nexus") soll bereitgestellt werden.
Fakt: `docker/compose/compose.yaml` definiert vier eigenständige Container (MSSQL-Datenbank,
Webservice unter `/app/Centron.Host.Console`, SMTP-Mailcatcher für Testzwecke, Blazor-Portal
"Nexus" unter `/app/CentronNexus.Host`) mit expliziten Abhängigkeiten (`depends_on`) und
Neustartrichtlinie (`restart: on-failure`).
Aussage: Das System soll Webservice, Datenbank und Kundenportal als unabhängig containerisierte,
über Docker Compose orchestrierbare Dienste bereitstellbar machen.
Ergebnis: Eine vollständige Serverumgebung (DB, API, Portal) lässt sich mit einem einzigen
Compose-Befehl aus vordefinierten Container-Images starten.
Belege:
- [PRIMÄR] docker/compose/compose.yaml (vollständige Datei) - Begründung: konkrete, lauffähige
Konfigurationsdatei mit Image-Referenzen, Ports und Abhängigkeiten, kein Konzeptpapier.
Prüfidee: `docker compose up` im Verzeichnis docker/compose startet alle vier Dienste; der Webservice
ist erst nach erfolgreichem DB-Start (depends_on) aktiv nutzbar.
Tracelinks: SyRS-19, SwRS-20
Konsolidierung: nein
Status: belegt
```
@@ -0,0 +1,574 @@
# Software Requirements Specification (SwRS)
## c-entron ERP-Suite — Reverse Requirements Engineering (Baseline V1, Iteration 01)
Komponenten, Datenmodelle, software-interne Regeln. Details zu Methodik, Abdeckung und Grenzen:
siehe `Analysebericht.md`.
---
## Modul: Sicherheit & Berechtigungen
```
ID: SwRS-1
Titel: Sessionweites Caching der Benutzerrechte
Ebene: SwRS
Typ: nicht-funktional (Performance-Effizienz, ISO25010)
Akteur: BL-Komponente AppRightsBL
Vorbedingung: HasUserRight wird für einen Benutzer innerhalb derselben Session mehrfach aufgerufen.
Fakt: `HasUserRight` liest über `Session.Advanced.Cache.GetOrAdd($"AllRightsFromAppUser{appUserI3D}", ...)`;
erst beim Cache-Miss wird die SQL-Abfrage gegen `Sichtrus`/`Sichmemb` ausgeführt.
Aussage: Das System soll die vollständige Rechteliste eines Benutzers innerhalb einer Session cachen,
um wiederholte Datenbankzugriffe bei mehrfachen Rechteprüfungen zu vermeiden.
Ergebnis: Nur der erste HasUserRight-Aufruf pro Benutzer und Session löst eine SQL-Abfrage aus; alle
folgenden Aufrufe werden aus dem Cache bedient.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: HasUserRight (Z.644-649)
- Begründung: Cache-Schlüssel und GetOrAdd-Aufruf sind direkt im Code sichtbar.
Prüfidee: Zwei aufeinanderfolgende HasUserRight-Aufrufe für denselben Benutzer in derselben Session:
nur beim ersten Aufruf wird die SQL-Query protokolliert/ausgeführt (z. B. per SQL-Profiler).
Tracelinks: SyRS-1
Konsolidierung: Kandidat: SwRS-2 (ähnlicher Cache-Mechanismus für Web-Account-Rechte, HasWebAccountRight)
Status: belegt
```
```
ID: SwRS-2
Titel: Massenprüfung mehrerer Rechte in einem Datenbankzugriff
Ebene: SwRS
Typ: funktional
Akteur: BL-Komponente AppRightsBL
Vorbedingung: Aufrufer möchte mehrere Rechte eines Benutzers gleichzeitig prüfen (z. B. Create/Edit/Delete/
Search/Unlock für Kunden).
Fakt: `CheckRightsFromUser(int appUserI3D, IList<int> rightI3Ds)` führt eine einzelne SQL-Abfrage mit
`IN (:RightI3Ds)`-Klausel aus und liefert die Teilmenge der tatsächlich zugewiesenen Rechte zurück.
Aussage: Das System soll die Prüfung mehrerer Rechte eines Benutzers in einem einzigen Datenbankzugriff
ermöglichen, statt pro Recht einen eigenen Aufruf zu benötigen.
Ergebnis: Der Aufrufer erhält die Schnittmenge aus angefragten und tatsächlich zugewiesenen Rechten
als Liste von I3Ds zurück.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: CheckRightsFromUser (Z.95-111)
- Begründung: SQL mit IN-Klausel und Parameterliste ist der durchgesetzte Mechanismus.
- [KONTEXT] docs/guides/development/check-userrights.md (AccountBL-Beispiel) - Begründung: zeigt
Verwendungsmuster in einer aufrufenden BL-Klasse.
Prüfidee: Aufruf mit 5 Recht-IDs, von denen der Benutzer 3 besitzt, liefert eine Liste mit genau
diesen 3 IDs.
Tracelinks: SyRS-1
Konsolidierung: Kandidat: SwRS-1
Status: belegt
```
```
ID: SwRS-3
Titel: Hartkodierte Positivliste änderbarer Administrator-Rechte
Ebene: SwRS
Typ: Daten
Akteur: BL-Komponente AppRightsBL
Vorbedingung: Eine Rechteänderung an der Administratoren-Gruppe wird versucht.
Fakt: `GetAssignableAdminRightI3Ds()` liefert eine im Quellcode fest verdrahtete Liste von ca. 38
numerischen Recht-IDs (mit Klartext-Kommentaren, z. B. "Angebote anzeigen - nur Eigene");
nur diese IDs dürfen bei der Administratorgruppe hinzugefügt/entfernt werden.
Aussage: Das System soll die Menge der bei der Administratoren-Gruppe änderbaren Rechte auf eine
fest im Code hinterlegte Liste beschränken.
Ergebnis: Versuche, ein nicht gelistetes Recht der Administratorgruppe hinzuzufügen oder zu entziehen,
werden mit Rückgabewert `false` abgelehnt, ohne Datenbankänderung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: GetAssignableAdminRightI3Ds
(Z.714-759) - Begründung: Liste wird direkt im Code als Prüfgrundlage verwendet (SaveAndAssignGroupToRight).
Prüfidee: Zuweisungsversuch eines Rechts mit I3D, das nicht in der Liste enthalten ist, an die
Administratorgruppe liefert `false`.
Tracelinks: SyRS-3, SyRS-4
Konsolidierung: nein
Status: belegt; Workaround (hartkodierte ID-Liste statt konfigurierbarer Regel — Migrationsrisiko:
bei neuen Rechten muss die Liste manuell im Quellcode gepflegt werden, sonst inkonsistentes
Verhalten zwischen Rechteverwaltung und Administratorgruppen-Schutz)
```
```
ID: SwRS-4
Titel: Hierarchisches Rechteschema in Tabelle Sichrech
Ebene: SwRS
Typ: Daten
Akteur: Entwickler (bei Anlage neuer Rechte), System (Rechteprüfung)
Vorbedingung: Ein neues Recht soll dem System hinzugefügt werden.
Fakt: Rechte werden in der Tabelle `Sichrech` mit den Spalten `I3D` (eindeutige Recht-ID),
`OwnerRecht` (übergeordnetes Recht), `NumChildren` (Anzahl untergeordneter Rechte), `Text`
(Anzeigename) und `Beschreibung` gespeichert; neue Rechte werden per
`ScriptHelpers.AddRightIfNotExists(...)` in Migrationsskripten angelegt.
Aussage: Das System soll Rechte als hierarchische Baumstruktur (Eltern-Kind über OwnerRecht) in der
Datenbank abbilden, sodass Rechtegruppen thematisch gegliedert und in der Rechteverwaltung
strukturiert dargestellt werden können.
Ergebnis: Jedes neue Recht besitzt eine eindeutige I3D, ein Elternrecht (OwnerRecht) und ist über
Migrationsskripte reproduzierbar in jeder Umgebung anlegbar.
Belege:
- [PRIMÄR] docs/guides/development/add-a-new-right.md, Codebeispiel `ScriptHelpers.AddRightIfNotExists(...)`
mit realer INSERT-Anweisung gegen Sichrech (I3D, Nummer, Text, OwnerRecht, NumChildren,
Beschreibung) - Begründung: das dokumentierte SQL ist die tatsächliche Anlagemethode für
Produktivdaten, kein bloßer Vorschlag.
- [KONTEXT] src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/Administration/Rights/UserRightsConst.cs
- Begründung: enthält die im Code referenzierten Recht-Konstanten (nicht inhaltlich gelesen,
nur als Fundstelle bestätigt; Datei ist mit 764 Dateien im Interfaces-Baum Teil einer sehr
großen Struktur — Tiefenprüfung des vollständigen Konstantenbaums nicht erfolgt, siehe Analysebericht).
Prüfidee: Ausführen eines Migrationsskripts mit AddRightIfNotExists erzeugt einen neuen Sichrech-Datensatz
mit korrektem OwnerRecht-Bezug; NumChildren des Elternrechts erhöht sich um 1.
Tracelinks: SyRS-1
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-5
Titel: Entwicklungsseitige Umleitung externer E-Mail-Adressen in Debug-Builds
Ebene: SwRS
Typ: Sicherheit
Akteur: System (Mailversand-Komponente)
Vorbedingung: Die Anwendung läuft als DEBUG-Build; eine E-Mail an eine externe Adresse (nicht endend auf
"nexoware.com") soll versendet werden.
Fakt: `DeveloperSecurity.Email.ValidateAddress(string emailAddress)` ersetzt jede nicht-interne
Zieladresse durch `test@nexoware.com`, sofern `AllowSendingEmailToExternalAddresses`
(Standardwert: `DebugHelper.IsReleaseBuild()`) nicht gesetzt ist; in Release-Builds ist die
Umleitung standardmäßig deaktiviert.
Aussage: Das System soll in Entwicklungs-/Debug-Builds automatisch verhindern, dass E-Mails an
tatsächliche (externe) Kundenadressen versendet werden, indem die Zieladresse durch eine
interne Testadresse ersetzt wird.
Ergebnis: In Debug-Builds erreichen ausgehende E-Mails an externe Adressen nie den echten Empfänger,
sondern immer `test@nexoware.com`; interne (nexoware.com) Adressen bleiben unverändert.
Belege:
- [PRIMÄR] src/backend/Centron.Common/DeveloperSecurity.cs :: ValidateAddress (Z.30-46) - Begründung:
die Ersetzungslogik ist zwingend im Code verankert, nicht optional zuschaltbar außer durch
Codeänderung der Property.
Prüfidee: Debug-Build, Versand an "kunde@fremdefirma.de": tatsächlicher SMTP-Empfänger ist
"test@nexoware.com"; Versand an "kollege@nexoware.com" bleibt unverändert.
Tracelinks: (kein direkter StRS/SyRS-Bezug – reine Entwicklungssicherheitsmaßnahme, kein Fachprozess)
Konsolidierung: nein
Status: belegt; Workaround (baujahresspezifischer Schutzmechanismus für die bestehende Delphi-/
.NET-Desktop-Systemlandschaft; für eine Web-/SaaS-Neuimplementierung ist ein äquivalentes,
umgebungsbasiertes Schutzkonzept — z. B. getrennte Sandbox-Mandanten/Test-Tenants statt
Build-Konfiguration — zu definieren)
```
## Modul: Lizenzierung
```
ID: SwRS-6
Titel: Lizenzmanager als Prozess-Singleton mit expliziter Einmalinitialisierung
Ebene: SwRS
Typ: funktional
Akteur: System (Applikationsstart)
Vorbedingung: Anwendung (c-entron.NET oder Webservice) startet.
Fakt: `LicenseManager.Initialize(settings)` wirft eine Exception, wenn `_instance` bereits gesetzt
ist; `LicenseManager.Instance` wirft eine Exception, wenn `Initialize` noch nicht aufgerufen
wurde. Für Webservice, c-entron.NET und Tests existieren jeweils eigene statische
Settings-Fabriken (`SettingsForWebService`, `SettingsForCentronNet`, `SettingsForTests`).
Aussage: Das System soll den Lizenzmanager pro Prozess genau einmal initialisieren und danach über
einen globalen Zugriffspunkt (Singleton) verfügbar machen, mit klar unterscheidbarer
Konfiguration je Hostumgebung (Webservice, Desktop-Client, Testlauf).
Ergebnis: Doppelte Initialisierung führt zu einer Exception beim Start; Zugriff vor Initialisierung
führt ebenfalls zu einer Exception.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs :: Initialize (Z.174-182),
Instance (Z.185-194) - Begründung: beide Guard-Exceptions sind unmittelbar im Code sichtbar
und erzwingen das Singleton-Verhalten.
Prüfidee: Zweiter Aufruf von Initialize() in derselben Prozessinstanz löst eine Exception aus;
Zugriff auf Instance vor jedem Initialize()-Aufruf löst ebenfalls eine Exception aus.
Tracelinks: SyRS-5, SyRS-6
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-7
Titel: Sonderbehandlung der c-entron-Delphi-Versionsnummer bei der Lizenzprüfung
Ebene: SwRS
Typ: Daten
Akteur: System (Lizenzprüfung beim Login)
Vorbedingung: Ein Login mit der gemeinsamen Centron-Lizenz-GUID und einer Versionsnummer im Muster
"9.3.x.y" (c-entron Delphi) wird geprüft.
Fakt: `TryFixCentronDelphiVersionNumber` ersetzt bei `licenseGuid == ApplicationKind.Centron.LicenseGuid`
und `Major==9 && Minor==3` die übergebene Versionsnummer durch die aktuelle Assembly-Version
des c-entron.NET, bevor die Versionsprüfung erfolgt.
Aussage: Das System soll für den Alt-Client "c-entron Delphi", der dieselbe Lizenz-GUID wie
c-entron.NET verwendet, aber ein inkompatibles Versionsschema (9.3.x.y) besitzt, die
Versionsprüfung so anpassen, dass ein gültiges Delphi-Login nicht fälschlich wegen
scheinbar zu hoher Versionsnummer abgelehnt wird.
Ergebnis: c-entron-Delphi-Logins werden anhand der c-entron.NET-Versionsnummer geprüft, nicht anhand
ihrer eigenen (irreführenden) Versionsnummer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs :: TryFixCentronDelphiVersionNumber
(Z.304-330), inkl. ausführlichem Erklärkommentar - Begründung: Code und Kommentar decken sich
und beschreiben denselben, aktiv durchgesetzten Sonderfall.
Prüfidee: Login mit Version "9.3.40.2" und Centron-Lizenz-GUID wird nicht wegen Versionsüberschreitung
abgelehnt, obwohl 9.3 > die eigentliche c-entron.NET-Lizenzobergrenze (z. B. 2.x) wäre.
Tracelinks: SyRS-5
Konsolidierung: nein
Status: belegt; Workaround (Altlast aus der Koexistenz von c-entron Delphi und c-entron.NET; für
eine Web-/SaaS-Neuimplementierung ohne Delphi-Altclient voraussichtlich entfallend – vor
Migration klären, ob Delphi-Client noch im Feld ist)
```
---
## Modul: Verkaufsbelege
```
ID: SwRS-8
Titel: Dreiwertiger Belegstatus (ReceiptState) als gemeinsamer Zustandsautomat
Ebene: SwRS
Typ: Daten
Akteur: System (ReceiptBase-abgeleitete Entities)
Vorbedingung: Ein Beleg wird angelegt oder verändert.
Fakt: `enum ReceiptState { Active=1 ("offen"), Completed=2 ("abgeschlossen"), Canceled=3
("storniert") }` ist die einzige State-Property auf `ReceiptBase` und wird von allen sieben
Belegtypen gemeinsam genutzt.
Aussage: Das System soll den Lebenszyklus jedes Belegs unabhängig vom konkreten Belegtyp über
denselben dreiwertigen Zustand (offen/abgeschlossen/storniert) abbilden.
Ergebnis: Jeder Beleg befindet sich zu jedem Zeitpunkt in genau einem der drei Zustände.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs (komplette Datei) - Begründung:
abschließende Enum-Definition, keine weiteren Werte im Typ vorhanden.
Prüfidee: Kompilierzeitprüfung/Reflection: ReceiptState besitzt genau die drei genannten Werte.
Tracelinks: StRS-5, SyRS-9
Konsolidierung: nein
Status: belegt
```
Anmerkung [HYPOTHESE] zu SwRS-8: Die Architekturdokumentation (receipts-backend-architecture.md) beschreibt
umgangssprachlich vier Zustände ("Draft/Released/Processed/Cancelled"), die im tatsächlichen Code nicht als
eigene ReceiptState-Werte existieren — siehe `Hypothesen.md` (H-1) für die offene Frage.
```
ID: SwRS-9
Titel: SpecificLogics-Dispatch für belegtypspezifische Rechteprüfung
Ebene: SwRS
Typ: funktional
Akteur: System (ReceiptBL)
Vorbedingung: CanUserEditReceipt wird für einen konkreten receiptKind aufgerufen.
Fakt: `CanUserEditReceipt` delegiert über `this._specificLogics.Execute(receiptKind, f => f.HasRightToEditReceipt(appUser))`
an eine belegtyp-spezifische Implementierung (z. B. `OfferSpecificLogic`, `InvoiceSpecificLogic`),
statt die Rechte-ID direkt hart zu kodieren.
Aussage: Das System soll die Zuordnung zwischen Belegtyp und den dafür jeweils erforderlichen
Benutzerrechten über eine austauschbare, belegtypspezifische Logikkomponente kapseln.
Ergebnis: Jeder Belegtyp kann eigene Rechte-IDs für Bearbeitung/Filialbeschränkung hinterlegen, ohne
die zentrale ReceiptBL ändern zu müssen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs :: CanUserEditReceipt (Z.10272-10295)
- Begründung: Dispatch-Aufruf ist direkt sichtbar; Existenz von mind. OfferSpecificLogic.cs,
InvoiceSpecificLogic.cs, OrderSpecificLogic.cs, ContractSpecificLogic.cs, PickupListSpecificLogic.cs,
DeliveryListSpecificLogic.cs bestätigt per Grep (src/backend/Centron.BL/Sales/Receipts/**).
Prüfidee: Für zwei verschiedene Belegtypen mit unterschiedlichen HasRightToEditReceipt-Implementierungen
liefert CanUserEditReceipt bei gleichem Benutzer unterschiedliche Ergebnisse (Code-Review-Kriterium).
Tracelinks: SyRS-7, StRS-7
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-10
Titel: Ableitung des Belegstatus aus dem Zahlungsflag
Ebene: SwRS
Typ: funktional
Akteur: System (ReceiptBL)
Vorbedingung: UpdateReceiptIsPaid wird mit einem isPaid-Wert ungleich null aufgerufen.
Fakt: `var newState = isPaid.Value ? ReceiptState.Completed : ReceiptState.Active;` gefolgt von
einer Zuweisung, sofern sich der Status ändert (Z.4944ff.).
Aussage: Das System soll den Belegstatus direkt und ausschließlich aus dem übergebenen Zahlungsflag
ableiten (bezahlt → abgeschlossen, nicht bezahlt → offen), ohne weitere Zwischenzustände.
Ergebnis: Nach Aufruf entspricht der Belegstatus exakt der Abbildung isPaid=true→Completed,
isPaid=false→Active.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs :: UpdateReceiptIsPaid (Z.4942-4946)
- Begründung: unmittelbare, unbedingte Zuweisungslogik.
Prüfidee: isPaid=true auf einem Active-Beleg: State wird Completed; isPaid=false auf einem
Completed-Beleg: State wird Active.
Tracelinks: StRS-8, SyRS-9
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-11
Titel: Versionsinkrement als eigenständiger Zustand vor dem eigentlichen Speichern
Ebene: SwRS
Typ: funktional
Akteur: System (ReceiptBL)
Vorbedingung: Ein Beleg mit vom Client angeforderter abweichender Version wird bearbeitet
(`version != currentReceiptVersion.Version`).
Fakt: `GetReceiptVersionForNewVersion` lädt die historische Version, aus der eine neue Version
erzeugt wird; anschließend erfolgt eine Validierung (aktive Barcodes, referenzierende
Folgebelege dürfen kein Hindernis sein), bevor `receipt.Version = currentReceiptVersion.Version + 1`
gesetzt wird.
Aussage: Das System soll das Erzeugen einer neuen Belegversion aus einer beliebigen historischen
Version nur zulassen, wenn keine aktiven Barcodes oder nicht-stornierten Folgebelege dem
entgegenstehen.
Ergebnis: Eine neue Version wird nur erzeugt, wenn die Konsistenzbedingungen erfüllt sind; andernfalls
wird die Operation mit Fehlermeldung abgelehnt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs, Z.3099-3117 - Begründung: Validierungs-
und Versionslogik liegen unmittelbar im selben Codeblock.
Prüfidee: Versuch, aus einer historischen Version mit aktiven Barcodes eine neue Version zu erzeugen,
wird abgelehnt (Fehlermeldung); ohne aktive Barcodes/blockierende Folgebelege gelingt es.
Tracelinks: StRS-6, SyRS-10
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-12
Titel: Duale Persistenzschicht: moderne Entity plus Legacy-Repository-Synchronisation
Ebene: SwRS
Typ: Daten
Akteur: System (DAO-Schicht)
Vorbedingung: Ein Beleg wird gespeichert.
Fakt: Für jeden Belegtyp existiert eine `SaveReceipt*Repository`-Klasse (bestätigt u. a.
`SaveReceiptOfferRepository`, `SaveReceiptOrderRepository`, `SaveReceiptSupplierOrderRepository`,
`SaveReceiptSupplierInvoiceRepository`, `SaveReceiptPickupListRepository`), die von
`SaveReceiptRepository<TReceiptInterface, TReceiptTable>` erbt und die abstrakten Methoden
`SynchronizeReceiptData`/`SynchronizeReceiptItemData` implementiert, um Werte aus der
modernen NHibernate-Entity explizit in die historische Legacy-Tabellenstruktur (z. B.
`AngKopf`, `AufKopf`, `BestKopf2`, `KalkKopf`, `WareKopf`, `LiGutKopf`) zu übertragen.
Aussage: Das System soll Belegdaten beim Speichern nicht ausschließlich über das moderne
NHibernate-Mapping, sondern zusätzlich explizit in die historischen Legacy-Tabellen
synchronisieren, um Abwärtskompatibilität mit bestehenden Auswertungen/Prozessen auf diesen
Tabellen zu erhalten.
Ergebnis: Nach dem Speichern sind sowohl die moderne Sicht (View) als auch die zugrunde liegende
Legacy-Tabelle konsistent befüllt.
Belege:
- [PRIMÄR] src/backend/Centron.DAO/Repositories/Sales/Receipts/SaveReceiptRepository.cs (abstrakte
Basisklasse, Z.190,196) sowie mind. 7 konkrete Implementierungen (Grep-Treffer, u. a.
Offers/SaveReceiptOfferRepository.cs, Order/SaveReceiptOrderRepository.cs) - Begründung:
wiederkehrendes, in der DAO-Schicht real implementiertes Muster, kein Dokumentationsartefakt.
- [KONTEXT] docs/reference/receipts/receipts-backend-architecture.md, Abschnitt "Critical Save Warning"
- Begründung: bestätigt und erläutert die fachliche Notwendigkeit ("nicht der einzige
Persistenzpfad"); explizite Warnung, dass neue Felder sonst nicht gespeichert werden.
Prüfidee: Neues Feld wird nur der modernen Entity/Mapping hinzugefügt, nicht dem Repository: Wert wird
beim Laden über die View sichtbar, geht aber beim erneuten Speichern verloren (Regressionstest-Idee).
Tracelinks: StRS-6, SyRS-10
Konsolidierung: nein
Status: belegt; Workaround (historisch gewachsene Doppelpersistenz; zentrales Migrationsrisiko für
eine Web-/SaaS-Neuimplementierung: bei Neuentwicklung sollte KEINE äquivalente Doppelstruktur
übernommen werden, sondern ein einheitliches Zielschema definiert werden – jedes bestehende
Feld ist gegen beide Pfade zu prüfen, bevor es als vollständig verstanden gilt)
```
---
## Modul: Verträge & automatisierte Abrechnung
```
ID: SwRS-13
Titel: Bedingte LINQ-Filterausdrücke je Berechnungsart in GetActiveContracts
Ebene: SwRS
Typ: funktional
Akteur: System (AutomaticFacturaBL)
Vorbedingung: GetActiveContracts wird mit einem SearchBillingContractsFilter aufgerufen.
Fakt: Die Query kombiniert `f.State == 1`, Zeitraumprüfung mit `AutomatedProlongation`,
bitweise Verknüpfung `filter.CalculationKind & f.CalculationKind`, Zahlungsdatenvergleich
(`LastPaidDate`, `FirstPaidDate`) sowie Filial-, Kunden- und Vertragsart-Filter in einem
einzigen LINQ-Ausdruck gegen `ReceiptContractHead`.
Aussage: Das System soll die Selektionslogik für abrechnungsfähige Verträge als eine zusammengesetzte,
datenbankseitig auswertbare Abfrage umsetzen, die Status, Zeitraum, Zahlungshistorie,
Berechnungsart und organisatorische Filter (Filiale, Kunde, Vertragsart) gleichzeitig
berücksichtigt.
Ergebnis: Ein einziger Datenbankzugriff liefert die vollständige Kandidatenliste für den nachfolgenden
mehrstufigen Ausschlussprozess (SyRS-12).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs
:: GetActiveContracts (Z.820-845) - Begründung: vollständiger, geschlossener LINQ-Ausdruck.
Prüfidee: Vertrag mit LastPaidDate >= ContractEnd und CalculationKind=Auto wird NICHT selektiert
(Bedingung `f.LastPaidDate < f.ContractEnd` nicht erfüllt).
Tracelinks: SyRS-12, StRS-10
Konsolidierung: nein
Status: belegt
```
```
ID: SwRS-14
Titel: Stapelweise (Batch) Nachfilterung großer Vertragsmengen über NamedQueries
Ebene: SwRS
Typ: nicht-funktional (Performance-Effizienz, ISO25010)
Akteur: System (AutomaticFacturaBL)
Vorbedingung: Die initiale Vertragsliste aus GetActiveContracts enthält potenziell sehr viele Einträge.
Fakt: Nachfolgende Zusatzabfragen (`GetContractsWithSpecialArticle`, `GetNoEmptyContracts`,
`GetContractsWithEmptyPos`, `GetNoBillingContracts`) werden nicht für die gesamte Liste auf
einmal, sondern über `.Batch(2000)` in Blöcken von 2000 Vertrags-I3Ds ausgeführt.
Aussage: Das System soll Nachfilterabfragen über große Vertragsmengen in Blöcken von maximal 2000
IDs ausführen, um Grenzen von SQL-IN-Klauseln bzw. Parameteranzahl-Limits zu vermeiden und
die Abfrageperformance zu sichern.
Ergebnis: Auch bei sehr vielen abrechnungsfähigen Verträgen bleibt der Abrechnungslauf ohne
SQL-Parameterlimit-Fehler funktionsfähig.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs,
Z.859-862, 888-892, 896-899, 908-912 (vier unabhängige .Batch(2000)-Aufrufe) - Begründung:
wiederkehrendes, konsistent angewendetes Muster.
Prüfidee: Abrechnungslauf mit > 2000 abrechnungsfähigen Verträgen schlägt nicht mit einem
SQL-Parameterlimit-Fehler fehl (Lasttest-Idee).
Tracelinks: SyRS-12
Konsolidierung: nein
Status: belegt
```
---
## Modul: Mahnwesen
```
ID: SwRS-15
Titel: Offener-Betrag-Berechnung je Mahnstufe aus drei Rechnungsbeträgen
Ebene: SwRS
Typ: Daten
Akteur: System (DunningBL)
Vorbedingung: Statistik über Rechnungen je Mahnstufe wird angefordert.
Fakt: `CalculateDunningStatistics` berechnet den offenen Betrag je Rechnung als
`GrossPriceComplete - PayedGrossAmount - CreditVoucherGrossAmount` und summiert diesen Wert
getrennt für die vier DunningLevel-Werte.
Aussage: Das System soll den offenen Rechnungsbetrag als Bruttorechnungsbetrag abzüglich bereits
gezahlter Beträge und abzüglich verrechneter Gutschriften berechnen.
Ergebnis: Die je Mahnstufe ausgewiesene Summe entspricht dem tatsächlich noch ausstehenden Betrag.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs, Z.221,224,227,230
- Begründung: identische Berechnungsformel an vier Stellen für je eine Mahnstufe wiederholt.
Prüfidee: Rechnung mit GrossPriceComplete=1000, PayedGrossAmount=300, CreditVoucherGrossAmount=100:
offener Betrag in der Statistik ist 600.
Tracelinks: StRS-11, SyRS-14
Konsolidierung: nein
Status: belegt
```
---
## Modul: Umsatzsteuer
```
ID: SwRS-16
Titel: Verkettete Steuersatz-Entität mit Fallback auf artikelspezifischen Standardsatz
Ebene: SwRS
Typ: Daten
Akteur: System (TaxBL)
Vorbedingung: Die übergebene taxRateI3D existiert nicht (mehr) in der Datenbank.
Fakt: `GetTaxRateForReceiptItem` fällt bei `currentTaxRate is null` auf
`GetDefaultTaxtRateByArticle(receiptItemArticleI3D)` zurück, bevor die Kettensuche beginnt.
Aussage: Das System soll bei einem nicht mehr existierenden Steuersatz auf einen artikelspezifischen
Standardsteuersatz zurückfallen, statt die Berechnung mit einem Fehler abzubrechen.
Ergebnis: Auch bei einer ungültigen/gelöschten Steuersatzreferenz liefert die Methode einen
verwendbaren Steuersatz zurück.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/TaxBL.cs, Z.213-216 - Begründung: expliziter Null-Check
mit Fallback-Aufruf im Code.
Prüfidee: Aufruf mit einer nicht existierenden taxRateI3D liefert nicht null, sondern den
artikelspezifischen Standardsatz (sofern für den Artikel einer hinterlegt ist).
Tracelinks: StRS-12, SyRS-15
Konsolidierung: nein
Status: belegt
```
---
## Modul: Kunden-/Lieferantenstammdaten
```
ID: SwRS-17
Titel: Konfigurierbare Kopplung von Buchhaltungsnummer und Kundennummer
Ebene: SwRS
Typ: Daten
Akteur: System (AccountBL), Buchhaltung (Konfiguration)
Vorbedingung: Die Anwendungseinstellung `AccountsBookKeepingNumberEqualsCustomerNumber` ist aktiviert.
Fakt: Beim Anlegen/Import eines Kunden wird `customerData.BookKeepingNumber = customerData.Number.ToString()`
gesetzt, sofern die genannte Einstellung aktiv ist und (im Importfall) noch keine
Buchhaltungsnummer vorhanden ist.
Aussage: Das System soll optional, gesteuert über eine Anwendungseinstellung, die Buchhaltungsnummer
eines Kunden automatisch mit dessen Kundennummer gleichsetzen.
Ergebnis: Bei aktivierter Einstellung stimmen Kundennummer und Buchhaltungsnummer neuer Kunden überein.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Accounts/AccountBL.cs, Z.147-175, 542-564 - Begründung: Einstellung
wird zweimal (Neuanlage, Import) unabhängig ausgewertet und durchgesetzt.
Prüfidee: Mit aktivierter Einstellung: neu angelegter Kunde mit Nummer 4711 erhält BookKeepingNumber
"4711"; bei deaktivierter Einstellung bleibt BookKeepingNumber unabhängig davon editierbar.
Tracelinks: StRS-13, SyRS-16
Konsolidierung: nein
Status: belegt
```
---
## Modul: Zeiterfassungsabrechnung
```
ID: SwRS-18
Titel: Belegtypabhängige UI-Feldsperre mit erklärendem Hinweistext
Ebene: SwRS
Typ: funktional
Akteur: WPF-Client (TimerBillingSettingsPageViewModel)
Vorbedingung: UseBillingDate ist aktiviert und ReceiptKind (Invoice/DeliveryList) ist gesetzt.
Fakt: `UpdateBillingDateIsEnabled()` wählt abhängig von `ReceiptKind` zwischen
`CanChangeDateInInvoices` und `CanChangeDateInDeliveryLists` aus `CentronCache.Instance.ReceiptSettings`;
ist das Recht nicht vorhanden, wird `ShowBillingDateNoteEnabledInfo=true` und ein
belegtypspezifischer Hinweistext ("Datum der Rechnung"/"Datum des Lieferscheins") gesetzt.
Aussage: Das System soll dem Benutzer bei fehlendem Recht nicht nur das Datumsfeld sperren, sondern
auch einen belegtypspezifischen Hinweis anzeigen, welches Recht fehlt.
Ergebnis: Bei fehlendem Recht ist das Feld gesperrt und ein Hinweistext mit dem exakten Rechtenamen
wird angezeigt.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingSettingsPageViewModel.cs
:: UpdateBillingDateIsEnabled (Commit baa9e7bd9b, Zeilen gem. Diff Z.566-590) - Begründung:
vollständige, kürzlich eingeführte und im Repository nachvollziehbare Implementierung.
Prüfidee: ReceiptKind=InvoiceClass, CanChangeDateInInvoices=false: BillingDateIsEnabled=false,
BillingDateNotEnabledInfo enthält "der Rechnung".
Tracelinks: StRS-14, SyRS-17
Konsolidierung: nein
Status: belegt
```
---
## Modul: Helpdesk/Ticketsystem
```
ID: SwRS-19
Titel: Erweiterung der Basis-Statusdaten um Verrechnungs- und Portaldarstellungsfelder
Ebene: SwRS
Typ: Daten
Akteur: System (HelpdeskState-Entity)
Vorbedingung: -
Fakt: `HelpdeskState : HelpdeskStateBase` fügt den Basisfeldern (Name, Number, Description, State)
die Felder `Icon` (byte[]), `IsDeactivated`, `IsInternalCompanyBillingActive`,
`ServiceBoardWebColor`, `ServiceBoardWebIcon` hinzu.
Aussage: Das System soll je Ticketstatus zusätzlich zur reinen Bezeichnung eine visuelle Darstellung
für das Kundenportal sowie ein Verrechnungssteuerungsfeld vorhalten.
Ergebnis: Jeder Ticketstatus kann unabhängig voneinander deaktiviert, mit Portal-Farbe/-Icon versehen
und für die interne Verrechnung ein-/ausgeschlossen werden.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskState.cs (vollständige
Datei, 8 Zeilen) - Begründung: abschließende Feldliste der Entity-Klasse.
Prüfidee: Zwei HelpdeskState-Datensätze mit unterschiedlichem ServiceBoardWebColor erscheinen im
Kundenportal mit der jeweils konfigurierten Farbe (UI-Abgleich).
Tracelinks: StRS-15, SyRS-18
Konsolidierung: nein
Status: belegt
```
---
## Modul: Betrieb & Bereitstellung
```
ID: SwRS-20
Titel: Explizite Dienstabhängigkeit und Neustartrichtlinie in der Compose-Topologie
Ebene: SwRS
Typ: nicht-funktional (Zuverlässigkeit, ISO25010)
Akteur: System (Container-Orchestrierung)
Vorbedingung: Ein Container (webservice oder nexus) beendet sich unerwartet.
Fakt: `webservice` und `nexus` sind in compose.yaml mit `restart: on-failure` konfiguriert; `nexus`
deklariert zusätzlich `depends_on: - webservice`, `webservice` entsprechend `depends_on: - db`.
Aussage: Das System soll einzelne Dienste bei unerwartetem Absturz automatisch neu starten und die
Startreihenfolge (Datenbank vor Webservice vor Portal) über deklarative Abhängigkeiten
sicherstellen.
Ergebnis: Ein abgestürzter Webservice- oder Nexus-Container wird automatisch neu gestartet; ein
Neustart des Gesamtstacks respektiert die Abhängigkeitsreihenfolge.
Belege:
- [PRIMÄR] docker/compose/compose.yaml, Z.19-20, 27, 42-43, 50 - Begründung: konkrete, in der
Konfigurationsdatei sichtbare Direktiven.
Prüfidee: Manuelles Beenden des webservice-Containers: Compose startet ihn automatisch neu, ohne dass
db oder nexus manuell neu gestartet werden müssen.
Tracelinks: StRS-16, SyRS-19
Konsolidierung: nein
Status: belegt
```
@@ -0,0 +1,534 @@
# System Requirements Specification (SyRS)
## c-entron ERP-Suite — Reverse Requirements Engineering (Baseline V1, Iteration 01)
Systemverhalten, Schnittstellen, Performance- und Sicherheitsanforderungen. Nicht-funktionale
Anforderungen sind, wo zutreffend, mit dem entsprechenden ISO/IEC 25010 Qualitätsmerkmal im
Feld `Typ` gekennzeichnet. Details zu Methodik, Abdeckung und Grenzen: siehe `Analysebericht.md`.
---
## Modul: Sicherheit & Berechtigungen
```
ID: SyRS-1
Titel: Serverseitige Rechteprüfung vor sicherheitsrelevanten Operationen
Ebene: SyRS
Typ: Sicherheit
Akteur: System (BL-Schicht)
Vorbedingung: Ein Client (WPF-UI oder Webservice-Aufrufer) fordert eine rechtebeschränkte Operation an.
Fakt: `AppRightsBL.HasUserRight`/`CheckRightsFromUser` führen eine SQL-Abfrage gegen die Tabellen
`Sichtrus`/`Sichmemb` aus und werden aus BL-Methoden heraus aufgerufen (z. B. AccountBL,
vgl. docs/guides/development/check-userrights.md); das Ergebnis wird pro Aufruf serverseitig
berechnet und für die Dauer der Session gecacht.
Aussage: Das System soll vor Ausführung rechtebeschränkter Operationen die Berechtigung des
anfragenden Benutzers serverseitig (nicht nur in der UI) prüfen.
Ergebnis: Operationen ohne ausreichendes Recht werden mit einem Error-Result abgelehnt, unabhängig
davon, ob der Client (WPF/Web) eine UI-Sperre umgeht.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: HasUserRight, HasUserRightWithDefaultMessage
- Begründung: BL-seitige, vom UI-Layer unabhängige Prüfmethode mit Cache und SQL-Beleg.
- [KONTEXT] docs/guides/development/check-userrights.md - Begründung: dokumentiert die verbindliche
Verwendung in BL-Klassen als Entwicklungsstandard.
Prüfidee: Direkter (simulierter) Aufruf einer BL-Methode ohne vorherige UI-Prüfung mit einem Benutzer
ohne Recht liefert Result.Error, nicht Erfolg.
Tracelinks: StRS-1, SwRS-1, SwRS-2
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-2
Titel: Getrenntes Rechtesystem für Web-Konten
Ebene: SyRS
Typ: Sicherheit
Akteur: System (Webservice), externer Web-Account (z. B. Kundenportal/Self-Care)
Vorbedingung: Ein Web-Account meldet sich am Webservice an und fordert eine Operation an.
Fakt: `AppRightsBL.HasWebAccountRight`/`GetAllWebRightsFromWebAccount` verwenden eine eigene
Tabelle `WebAccountsRights`, getrennt von den internen Rechten (`Sichtrus`/`Sichmemb`) der
Desktop-/Mitarbeiter-Benutzer.
Aussage: Das System soll externe Web-Konten über ein von internen Mitarbeiterrechten unabhängiges
Rechtemodell autorisieren, um Vermischung interner und externer Berechtigungen zu vermeiden.
Ergebnis: Ein Web-Account kann ausschließlich über `WebAccountsRights` zugewiesene Rechte nutzen, nie
über `Sichtrus`-Mitarbeiterrechte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: HasWebAccountRight (Zeilen
666-691) - Begründung: eigenständiger Codepfad mit eigener Tabelle, keine Vermischung im Code.
Prüfidee: Web-Account mit Recht X, aber ohne entsprechendes internes Sichtrus-Recht, wird bei HasWebAccountRight(X)
korrekt zugelassen; HasUserRight desselben Datensatzes (falls anwendbar) liefert unabhängiges Ergebnis.
Tracelinks: StRS-1, SwRS-1
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-3
Titel: Schutz der Administratoren-Gruppe vor Löschung und Rechteentzug
Ebene: SyRS
Typ: Sicherheit
Akteur: Administrator
Vorbedingung: Administrator versucht, die Gruppe "Administratoren" (I3D=6) zu löschen oder deren
Rechte über eine nicht-freigegebene Teilmenge zu ändern.
Fakt: `AppRightsBL.DeleteRightGroup` bricht bei `group.I3D == 6` bzw. Gruppenname
"Administratoren" mit Fehlermeldung ab; `SaveAndAssignGroupToRight`/`RemoveAssignGroupToRight`
prüfen für die Administratorgruppe zusätzlich `GetAssignableAdminRightI3Ds()` (hartcodierte
Positivliste von ca. 38 Rechte-IDs), außerhalb derer keine Änderung zulässig ist.
Aussage: Das System soll verhindern, dass die Administratoren-Gruppe gelöscht oder außerhalb einer
fest definierten Positivliste in ihren Rechten verändert wird, um eine versehentliche
Selbstaussperrung von Administratoren zu vermeiden.
Ergebnis: Löschversuche der Administratorengruppe und nicht freigegebene Rechteänderungen werden
abgelehnt (Result-Error bzw. Rückgabe `false`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: DeleteRightGroup (Z.359-360),
GetAssignableAdminRightI3Ds (Z.714-759), SaveAndAssignGroupToRight (Z.266-271) - Begründung:
direkte, unumgehbare Prüfung im Schreibpfad.
Prüfidee: Löschversuch der Gruppe I3D=6 liefert Result.Error "Die Adminstratoren Gruppe darf nicht
gelöscht werden"; Zuweisen eines nicht gelisteten Rechts zur Admin-Gruppe liefert `false`.
Tracelinks: StRS-2, SwRS-3
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-4
Titel: Lückenlose Protokollierung rechterelevanter Änderungen
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit / Security-ISO25010)
Akteur: System
Vorbedingung: Eine rechte-/gruppenbezogene Schreiboperation wird ausgeführt.
Fakt: Jede öffentliche Schreibmethode in `AppRightsBL` (Add/Remove Right-to-Group, Add/Remove
User-to-Group, Create/Delete/Copy Group) ruft am Ende eine `WriteXxxLog`-Methode auf, die
unbedingt (kein optionaler Zweig) einen `AppRightLog`-Eintrag mit `CreatedByI3D`,
`CreatedDate`, `CreatedVersion` und `Kind` schreibt.
Aussage: Das System soll jede rechterelevante Änderung so protokollieren, dass Zeitpunkt, ausführender
Benutzer, Softwareversion und Art der Änderung nachvollziehbar sind.
Ergebnis: Für jede Änderungsoperation existiert genau ein zugehöriger, nicht überspringbarer
AppRightLog-Eintrag.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs :: WriteBaseLog (Z.762-781)
- Begründung: Guard-Klauseln erzwingen vollständige Angaben, Aufruf ist nicht bedingt.
Prüfidee: Für jede der acht Schreibmethoden existiert im Code ein zugehöriger, unbedingter WriteXxxLog-Aufruf
(Code-Review-Kriterium); funktional: AppRightLog-Tabelle wächst um genau einen Eintrag pro Aufruf.
Tracelinks: StRS-3, SwRS-3
Konsolidierung: nein
Status: belegt
```
## Modul: Lizenzierung
```
ID: SyRS-5
Titel: Versions- und Mengenbeschränkte Lizenzprüfung beim Anwendungs-Login
Ebene: SyRS
Typ: Sicherheit
Akteur: System (Webservice-Login), Applikation (c-entron.NET, Service-Board, Outlook-Add-In, ...)
Vorbedingung: Eine Applikation (`ApplicationKind`) versucht sich mit einer Client-Version am Webservice anzumelden.
Fakt: `LicenseManager.CheckLicense(ApplicationKind app, string applicationVersion, LoggedInUser user)`
prüft je Login die Lizenzversion (`CheckLicenseVersion`) und, sofern ein `user` übergeben wird,
die aktuell genutzte Lizenzanzahl gegen `GetLicenseCount` mittels `TicketBL.GetTicketCount`;
bei Überschreitung wird der Login mit Fehlercode `LicenseMaximumReached` abgelehnt.
Aussage: Das System soll bei jeder Anwendungsanmeldung serverseitig prüfen, ob eine gültige Lizenz für
die anfragende Applikation und Version vorliegt und ob die maximale Anzahl gleichzeitig
genutzter Lizenzen nicht überschritten wird.
Ergebnis: Logins ohne gültige Lizenz oder bei ausgeschöpftem Lizenzkontingent werden mit einer
definierten Fehlermeldung abgelehnt; gültige Logins werden zugelassen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs :: CheckLicense (Z.258-302)
- Begründung: durchgesetzte Prüfung inkl. Zähl- und Versionsvergleich im Login-Pfad, mit
spezifischem Fehlercode `DefaultMessageCodes.LicenseMaximumReached`.
Prüfidee: Login mit abgelaufener Lizenzversion liefert Result.Error; Login, der die maximale
Lizenzanzahl überschreitet, liefert Result.Error mit Code LicenseMaximumReached.
Tracelinks: StRS-4, SwRS-6
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-6
Titel: Datenbank-Update wird bei fehlender Lizenz blockiert
Ebene: SyRS
Typ: Sicherheit
Akteur: System (Webservice-Start)
Vorbedingung: Webservice startet und lädt Lizenzdatei.
Fakt: `LicenseManager.LoadLicenses()` ruft `CheckLicense(ApplicationKind.Centron, ...).ThrowIfError()`
VOR dem Datenbank-Strukturupdate auf; der zugehörige Kommentar im Code beschreibt explizit,
dass dies verhindern soll, dass ein Kunde ohne gültige Lizenz die Datenbank auf eine neuere
Struktur aktualisiert und dadurch mit einer älteren Version nicht mehr arbeiten kann.
Aussage: Das System soll ein Datenbankschema-Update beim Start verweigern, wenn keine gültige
Lizenz für die aktuelle Applikationsversion vorliegt.
Ergebnis: Fehlt die Lizenz, bricht der Webservice-Start mit Exception ab; die Datenbank bleibt
unverändert (kein Strukturupdate).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs :: LoadLicenses (Z.219-236)
- Begründung: Reihenfolge im Code (Lizenzprüfung mit ThrowIfError() vor Update-Logik) setzt
die Regel technisch durch.
- [KONTEXT] Inline-Kommentar Z.226-233 derselben Datei - Begründung: erläutert die fachliche Absicht
("If he doesn't have a license, the database should stay the same").
Prüfidee: Webservice-Start ohne gültige Centron-Lizenz: Startvorgang bricht ab, bevor Migrationsskripte
ausgeführt werden (beobachtbar z. B. an unverändertem Schema-Versionsstand).
Tracelinks: StRS-4, SwRS-6
Konsolidierung: nein
Status: belegt
```
---
## Modul: Verkaufsbelege
```
ID: SyRS-7
Titel: Recht- und filialbasierte Bearbeitungsprüfung vor jeder Belegänderung
Ebene: SyRS
Typ: Sicherheit
Akteur: System (ReceiptBL)
Vorbedingung: Eine Änderung an einem Beleg (Speichern, Zahlungsstatus, Erinnerungsdatum, Projektnummer,
Stundensatz, Benutzerstatus) wird angefordert.
Fakt: `CanUserEditReceipt` wird in praktisch jeder öffentlichen Änderungsmethode von `ReceiptBL`
aufgerufen (belegt an mind. 6 unabhängigen Stellen) und kombiniert eine belegtypspezifische
Rechteprüfung (`HasRightToEditReceipt`) mit einer optionalen Filialprüfung
(`HasRightToEditReceiptOnlyOwnBranch` + `BranchBL.IsBranchEqual`).
Aussage: Das System soll vor jeder Änderung an einem Verkaufsbeleg serverseitig prüfen, ob der
anfragende Benutzer sowohl das allgemeine Bearbeitungsrecht für diesen Belegtyp als auch,
falls eingeschränkt, das Recht zur Bearbeitung von Belegen der jeweiligen Filiale besitzt.
Ergebnis: Änderungsversuche ohne ausreichendes Recht bzw. an Belegen einer fremden Filiale werden mit
spezifischer Fehlermeldung (Fehlercode RightCheckFailed) abgelehnt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs :: CanUserEditReceipt (Z.10272-10295),
aufgerufen u. a. in Z.3081, 3625, 4804, 4839, 4880, 4921, 5114, 5268 - Begründung: zentrale,
wiederholt genutzte Prüfmethode, kein Einzelfall.
Prüfidee: Benutzer ohne Bearbeitungsrecht für Rechnungen versucht, eine Rechnung zu speichern; Result
enthält Fehlercode RightCheckFailed und keine Datenbankänderung erfolgt.
Tracelinks: StRS-5, StRS-7, SwRS-9
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-8
Titel: Optimistische Sperre verhindert verlorene Aktualisierungen
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO25010)
Akteur: System (ReceiptBL)
Vorbedingung: Ein Client sendet eine Belegänderung mit einem zuvor geladenen `ConcurrencyControlGuid`.
Fakt: Vor dem Schreiben wird `receipt.ConcurrencyControlGuid != concurrencyControlGuid` geprüft;
bei Ungleichheit liefert die Methode `Result.AsError(..., DefaultMessageCodes.ChangedByOtherInstance)`
und die Änderung wird nicht übernommen.
Aussage: Das System soll Änderungen an einem Beleg zurückweisen, wenn der Beleg seit dem Laden durch
den Client bereits durch eine andere Instanz geändert wurde (Lost-Update-Vermeidung).
Ergebnis: Der Client erhält den Fehlercode `ChangedByOtherInstance` und muss den Beleg neu laden,
bevor eine erneute Änderung möglich ist.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs, Z.4808-4809, 4843-4844, 4884-4885, 4939-4940,
5272-5273 - Begründung: identisches Prüfmuster an mindestens 5 unabhängigen Update-Pfaden.
Prüfidee: Zwei parallele Ladevorgänge desselben Belegs, sequentielle Speicherversuche: der zweite
Speicherversuch mit veraltetem Guid schlägt mit ChangedByOtherInstance fehl.
Tracelinks: StRS-7, SwRS-9
Konsolidierung: Kandidat: SyRS-9 (verwandter Zustands-Schutzmechanismus)
Status: belegt
```
```
ID: SyRS-9
Titel: Stornierte Belege sind gegen Zahlungsstatusänderung geschützt
Ebene: SyRS
Typ: funktional
Akteur: System (ReceiptBL), Debitorenbuchhaltung
Vorbedingung: Ein Beleg befindet sich im Status `Canceled` (storniert).
Fakt: `UpdateReceiptIsPaid` prüft `receipt.State == ReceiptState.Canceled` und liefert in diesem
Fall unbedingt einen Error zurück ("... wurde storniert und kann daher nicht als bezahlt
oder nicht bezahlt eingestellt werden."), bevor der Zahlungsstatus geändert wird.
Aussage: Das System soll verhindern, dass der Zahlungsstatus eines bereits stornierten Belegs
geändert wird.
Ergebnis: Versuche, den Zahlungsstatus eines stornierten Belegs zu setzen, werden abgelehnt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs :: UpdateReceiptIsPaid (Z.4936-4937)
- Begründung: unbedingte Prüfung vor jeder Statusänderung, keine Ausnahme im Code sichtbar.
Prüfidee: UpdateReceiptIsPaid auf einem Beleg mit State=Canceled liefert Result.Error unabhängig vom
übergebenen isPaid-Wert.
Tracelinks: StRS-5, SwRS-8, SwRS-10
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-10
Titel: Vollständige Versionierung bei jeder Belegspeicherung
Ebene: SyRS
Typ: nicht-funktional (Zuverlässigkeit, ISO25010)
Akteur: System (ReceiptBL)
Vorbedingung: Ein bestehender Beleg wird gespeichert und ist keine reine Neuanlage.
Fakt: Im Speicherpfad wird nach erfolgreicher Rechte-/Concurrency-Prüfung unbedingt
`this._specificLogics.Execute(receipt, f => f.SaveReceiptVersion(receipt, previousReceiptVersion))`
aufgerufen (Z.3629), unabhängig vom konkreten Belegtyp (SpecificLogics-Pattern).
Aussage: Das System soll bei jeder Speicherung eines geänderten Belegs unabhängig vom Belegtyp eine
Versionshistorie fortschreiben.
Ergebnis: Zu jedem gespeicherten Änderungsstand eines Belegs existiert ein Versionsdatensatz.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs, Z.3625-3633 - Begründung: Aufruf liegt im
gemeinsamen, belegtyp-unabhängigen Speicherpfad, nicht in einer optional übersprungenen Verzweigung.
Prüfidee: Für jeden der sieben Belegtypen: Speichern einer Änderung erzeugt einen neuen Versionsdatensatz
(stichprobenartig für mind. 2 Belegtypen zu verifizieren, siehe Analysebericht/Lücken).
Tracelinks: StRS-6, SwRS-11, SwRS-12
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-11
Titel: Ausnahmerecht für Zahlungseingang unabhängig vom allgemeinen Bearbeitungsrecht
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter Debitorenbuchhaltung/Zahlungseingang
Vorbedingung: Benutzer besitzt nicht das allgemeine Bearbeitungsrecht für den Belegtyp, wohl aber das
Recht `INCOMING_PAYMENT_TRANSACTIONS`.
Fakt: `UpdateReceiptIsPaid` behandelt ein fehlgeschlagenes `CanUserEditReceipt` mit Fehlercode
`RightCheckFailed` als nicht endgültig abgelehnt, sofern der Benutzer zusätzlich
`UserRightsConst.Controlling.Finances.INCOMING_PAYMENT_TRANSACTIONS` besitzt; in diesem Fall
wird die Operation dennoch fortgesetzt.
Aussage: Das System soll Mitarbeitern mit dem speziellen Recht für Zahlungseingänge erlauben, den
Zahlungsstatus eines Belegs zu setzen, auch wenn sie kein allgemeines Bearbeitungsrecht für
diesen Belegtyp besitzen.
Ergebnis: Ein Benutzer mit ausschließlich dem Zahlungseingangsrecht kann `UpdateReceiptIsPaid`
erfolgreich ausführen, jedoch keine sonstigen Belegänderungen vornehmen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs :: UpdateReceiptIsPaid (Z.4921-4934)
- Begründung: expliziter Sonderfall-Codepfad mit eigenem Rechtekonstantenbezug.
Prüfidee: Benutzer mit ausschließlich INCOMING_PAYMENT_TRANSACTIONS (kein allgemeines Bearbeitungsrecht):
UpdateReceiptIsPaid liefert Erfolg; SaveReceipt (allgemein) liefert weiterhin RightCheckFailed.
Tracelinks: StRS-8
Konsolidierung: nein
Status: belegt
```
---
## Modul: Verträge & automatisierte Abrechnung
```
ID: SyRS-12
Titel: Mehrstufige Selektion abrechnungsfähiger Verträge
Ebene: SyRS
Typ: funktional
Akteur: System (AutomaticFacturaBL)
Vorbedingung: Ein automatisierter oder manuell ausgelöster Abrechnungslauf wird gestartet.
Fakt: `GetActiveContracts` filtert zunächst auf `State == 1` (aktiv), gültigen Zeitraum
(ContractBegin/ContractEnd, ggf. AutomatedProlongation) und Berechnungsart; `SearchBillingContracts`
reduziert die Trefferliste danach in mehreren Schritten weiter: `InvoicePeriodCalculate`
(Abrechnungszeitraum), Ausschluss dynamischer Bedarfsverträge ohne Sonderartikel-Stichtag,
Ausschluss von Verträgen ohne abrechenbare Positionen ("leere RE vermeiden"), Kennzeichnung
von Verträgen mit Stückzahl- bzw. Barcode-/Seriennummer-Besonderheiten.
Aussage: Das System soll vor der eigentlichen Rechnungserzeugung sicherstellen, dass nur Verträge mit
gültigem Status, fälligem Abrechnungszeitraum und tatsächlich abrechenbarem Inhalt in den
Abrechnungslauf gelangen, um Leerrechnungen und fehlerhafte automatische Buchungen zu vermeiden.
Ergebnis: Die an `StoreInvoiceToContract` übergebene Vertragsliste enthält ausschließlich geprüfte,
abrechnungsfähige Verträge.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs
:: SearchBillingContracts (Z.847-919, insb. Kommentar "leere RE vermeiden" Z.886) - Begründung:
mehrstufige, im Code nachvollziehbare Ausschlusslogik, kein einzelner Filter.
Prüfidee: Aktiver Vertrag ohne Vertragspositionen wird trotz fälligem Intervall NICHT in die finale
Abrechnungsliste aufgenommen (WithEmptyPos-Fall).
Tracelinks: StRS-9, SwRS-13, SwRS-14
Konsolidierung: nein
Status: belegt
```
```
ID: SyRS-13
Titel: Berücksichtigung von Sonderartikel-Stichtagen bei dynamischen Bedarfsverträgen
Ebene: SyRS
Typ: funktional
Akteur: System (AutomaticFacturaBL)
Vorbedingung: Vertrag hat CalculationKind=Need und CalcNeedKind=Dynamic.
Fakt: Solche Verträge werden aus der Abrechnungsliste entfernt (`contracts.RemoveAll(...)`), außer
es liegt ein Sonderartikel mit einem Stichtag vor dem Ende des Abrechnungszeitraums
(`WithSpecialArticle`) vor, ermittelt über die NamedQuery `GetContractsWithSpecialArticle`.
Aussage: Das System soll dynamische Bedarfsverträge nur dann automatisch abrechnen, wenn ein
konkreter, terminierter Abrechnungsanlass (Sonderartikel mit Stichtag) vorliegt.
Ergebnis: Dynamische Bedarfsverträge ohne aktuellen Abrechnungsanlass werden nicht automatisch berechnet.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs,
Z.859-884 - Begründung: konkrete Query- und Ausschlusslogik im Code.
Prüfidee: Dynamischer Bedarfsvertrag ohne Sonderartikel-Stichtag im Abrechnungszeitraum wird aus der
Trefferliste entfernt; mit passendem Stichtag bleibt er enthalten.
Tracelinks: StRS-9, StRS-10
Konsolidierung: nein
Status: belegt
```
---
## Modul: Mahnwesen
```
ID: SyRS-14
Titel: Zeitraumbezogene Mahnsperre je Kunde/Objekt
Ebene: SyRS
Typ: funktional
Akteur: System (DunningBL)
Vorbedingung: Für einen Kunden oder ein konkretes Objekt (Rechnung) ist eine Mahnsperre mit Start-/Enddatum
gesetzt (`dunningStop`, `dunningStopBegin`, `dunningStopEnd`).
Fakt: `UpdateDunningStopAndInfo(objectI3D, objectKind, dunningStop, dunningInfo, dunningStopBegin,
dunningStopEnd, loggedInUser)` persistiert die Sperre inkl. Freitext-Info und optionalem
Zeitraum je referenziertem Objekt (`CentronObjectKindNumeric`).
Aussage: Das System soll erlauben, das Mahnwesen für einen Kunden oder ein einzelnes Objekt zeitlich
begrenzt oder unbegrenzt auszusetzen, mit dokumentiertem Grund.
Ergebnis: Während des gesperrten Zeitraums wird das betroffene Objekt im Mahnlauf nicht weiter eskaliert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs :: UpdateDunningStopAndInfo
(Z.392-ff.) - Begründung: dedizierte Methode mit allen notwendigen Parametern zur Durchsetzung.
Prüfidee: Setzen einer Mahnsperre mit dunningStopEnd in der Zukunft: das Objekt wird im nächsten
GetDunningCustomers-Aufruf als gesperrt markiert bzw. ausgeschlossen (je nach Filterparameter).
Tracelinks: StRS-11, SwRS-15
Konsolidierung: nein
Status: belegt
```
---
## Modul: Umsatzsteuer
```
ID: SyRS-15
Titel: Rückwärtssuche in der Steuersatzhistorie bis zum passenden Gültigkeitszeitraum
Ebene: SyRS
Typ: funktional
Akteur: System (TaxBL)
Vorbedingung: Eine Steuersatzkette (`ValueAddedTax.NextTaxRate`) mit mindestens einem historischen und
einem aktuellen Satz existiert.
Fakt: `GetTaxRateForReceiptItem` läuft zunächst bis zum jüngsten Kettenglied (`NextTaxRate == null`)
und geht anschließend rückwärts, bis ein Satz gefunden wird, dessen Gültigkeitszeitraum
(`ExpirationDate` des Vorgängers) das übergebene `receiptDate` abdeckt.
Aussage: Das System soll bei mehreren historisch aufeinanderfolgenden Steuersätzen denjenigen
auswählen, dessen Gültigkeitszeitraum das Belegdatum tatsächlich einschließt.
Ergebnis: Für ein gegebenes receiptDate wird genau ein zeitlich passender Steuersatz zurückgegeben.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/TaxBL.cs, Z.212-229 - Begründung: die Schleifenlogik mit
ExpirationDate-Prüfung ist direkt im Code sichtbar.
Prüfidee: Kette mit Steuersatz A (gültig bis 30.06.), Nachfolger B (ab 01.07.): receiptDate=15.06.
liefert A, receiptDate=15.07. liefert B.
Tracelinks: StRS-12, SwRS-16
Konsolidierung: nein
Status: belegt
```
---
## Modul: Kunden-/Lieferantenstammdaten
```
ID: SyRS-16
Titel: Granulare Rechteprüfung je CRUD-Operation auf Geschäftspartnerdaten
Ebene: SyRS
Typ: Sicherheit
Akteur: System (AccountBL)
Vorbedingung: Ein Account (Kunde/Lieferant) wird angelegt, bearbeitet oder gelöscht.
Fakt: `AccountBL` prüft vor dem jeweiligen Vorgang gezielt das passende Recht
(CREATE_CUSTOMER/EDIT_CUSTOMER/DELETE_CUSTOMER bzw. RIGHT_LIEFERANTANLEGEN/-AENDERN) über
`AppRightsBL.CheckRightsFromUser` und bricht bei fehlendem Recht mit `RightCheckFailed` ab.
Aussage: Das System soll für Anlage, Bearbeitung und Löschung von Geschäftspartner-Stammdaten jeweils
spezifische, einzeln prüfbare Rechte durchsetzen.
Ergebnis: Ein Benutzer mit z. B. nur EDIT_CUSTOMER kann bestehende Kunden bearbeiten, aber keine neuen
anlegen oder löschen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Accounts/AccountBL.cs, Z.1302-1348 - Begründung: getrennte
If-Abfragen je Operation mit jeweils eigenem Rechtebezug.
- [KONTEXT] docs/guides/development/check-userrights.md (identisches Codebeispiel) - Begründung:
bestätigt, dass dieses Muster als Referenzimplementierung dokumentiert ist.
Prüfidee: Benutzer mit ausschließlich EDIT_CUSTOMER: Bearbeiten eines bestehenden Kunden gelingt,
Anlegen eines neuen Kunden liefert RightCheckFailed.
Tracelinks: StRS-13, SwRS-17
Konsolidierung: Kandidat: SyRS-1 (gleiches zugrundeliegendes Rechteprüfungsmuster CheckRightsFromUser,
unterschiedliche Fachdomäne)
Status: belegt
```
---
## Modul: Zeiterfassungsabrechnung
```
ID: SyRS-17
Titel: Getrennte Rechte für Datumsänderung bei Rechnung und Lieferschein
Ebene: SyRS
Typ: Sicherheit
Akteur: System (ReceiptWebServiceBL)
Vorbedingung: ReceiptSettings werden für einen angemeldeten Benutzer ermittelt.
Fakt: `CanChangeDateInDeliveryLists` prüft `UserRightsConst...DeliveryList.CAN_CHANGE_DATE`,
`CanChangeDateInInvoices` prüft unabhängig davon `UserRightsConst...Invoice.CAN_CHANGE_DATE` –
zwei eigenständige Rechte-IDs für zwei Belegtypen.
Aussage: Das System soll die Berechtigung zur Datumsänderung für Rechnungen und für Lieferscheine
unabhängig voneinander vergebbar machen.
Ergebnis: Ein Benutzer kann z. B. das Datum von Lieferscheinen ändern dürfen, ohne automatisch auch
das Recht für Rechnungsdaten zu besitzen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/Receipts/ReceiptWebServiceBL.cs, Z.996,998
- Begründung: zwei getrennte Rechtekonstanten werden unabhängig ausgewertet.
Prüfidee: Benutzer mit DeliveryList.CAN_CHANGE_DATE, aber ohne Invoice.CAN_CHANGE_DATE:
CanChangeDateInDeliveryLists=true, CanChangeDateInInvoices=false.
Tracelinks: StRS-14, SwRS-18
Konsolidierung: nein
Status: belegt
```
---
## Modul: Helpdesk/Ticketsystem
```
ID: SyRS-18
Titel: Ticketstatus als Stammdaten statt Programmkonstante
Ebene: SyRS
Typ: Daten
Akteur: System (HelpdeskBL/HelpdeskState)
Vorbedingung: Ein Ticket wird einem Status zugeordnet.
Fakt: `HelpdeskState` wird über NHibernate gemappt (`HelpdeskStateMaps.cs`) und in der Datenbank
verwaltet, im Gegensatz zum festen `ReceiptState`-Enum bei Verkaufsbelegen (vgl. SwRS-8).
Aussage: Das System soll den Ticketstatus als datenbankgestützte, administrierbare Stammdatenliste
führen, nicht als im Quellcode fest kodierte Werteliste.
Ergebnis: Neue Ticketstatus können ohne Software-Update angelegt werden.
Belege:
- [PRIMÄR] src/backend/Centron.DAO/Mappings/CustomerArea/Support/HelpdeskStateMaps.cs (Existenz einer
NHibernate-Mapping-Klasse) - Begründung: Mapping-Klassen existieren ausschließlich für
datenbankgestützte Entitäten, nicht für Enums.
Prüfidee: Ein neuer HelpdeskState-Datensatz ist über die Rechteverwaltungs-/Admin-UI anlegbar und
sofort als Auswahloption bei der Ticketbearbeitung verfügbar, ohne Deployment.
Tracelinks: StRS-15, SwRS-19
Konsolidierung: Kandidat: SwRS-8 (gegensätzliches Muster: Belegstatus fest vs. Ticketstatus konfigurierbar –
als Konsolidierungshinweis für Zielarchitektur relevant, ob ein einheitliches Statuskonzept
sinnvoll ist)
Status: belegt
```
---
## Modul: Betrieb & Bereitstellung
```
ID: SyRS-19
Titel: Linux-Fähigkeit des Webservice-Hosts
Ebene: SyRS
Typ: nicht-funktional (Übertragbarkeit, ISO25010)
Akteur: System (Webservice-Host)
Vorbedingung: Webservice wird in einem Linux-Container gestartet.
Fakt: Das Docker-Image `centron.azurecr.io/centron_webservice` startet den Prozess
`/app/Centron.Host.Console` unter Linux (kein Windows-Container-Basisimage in compose.yaml
erkennbar); zusätzlich referenziert `LicenseManager.cs` einen bedingten Codepfad
`#elif WINDOWS` mit sonst plattformneutralem Verhalten.
Aussage: Das System soll den Webservice-Host plattformunabhängig (insbesondere unter Linux)
betreibbar machen, nicht ausschließlich unter Windows.
Ergebnis: Der Webservice startet und arbeitet in einem Linux-Container ohne Windows-spezifische
Laufzeitumgebung.
Belege:
- [PRIMÄR] docker/compose/compose.yaml, Z.13-16 - Begründung: konkrete Startkonfiguration ohne
Windows-Abhängigkeit.
- [KONTEXT] docs/guides/services/web-service-on-linux.md (referenziert, Inhalt in dieser Iteration
nicht gelesen) - Begründung: Dateiname deutet auf dediziertes Vorgehen für Linux-Betrieb hin;
[HYPOTHESE]: genauer Funktionsumfang unter Linux (z. B. ob alle Features identisch zu Windows
verfügbar sind) wurde nicht verifiziert, siehe Hypothesen.md (H-3).
Prüfidee: Webservice-Container basierend auf einem Linux-Basisimage startet erfolgreich und beantwortet
einen Health-Check-Request.
Tracelinks: StRS-16, SwRS-20
Konsolidierung: nein
Status: belegt
```
@@ -0,0 +1,26 @@
# Traceability-Tabelle
StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg
---|---|---|---
StRS-1 | SyRS-1 | SwRS-1, SwRS-2 | AppRightsBL.cs (HasUserRight, CheckRightsFromUser)
StRS-1 | SyRS-2 | SwRS-1 | AppRightsBL.cs (HasWebAccountRight)
StRS-2 | SyRS-1 | SwRS-3 | AppRightsBL.cs (SaveRightGroup, DeleteRightGroup — Branch-Check)
StRS-2 | SyRS-3 | SwRS-3 | AppRightsBL.cs (GetAssignableAdminRightI3Ds, DeleteRightGroup)
StRS-3 | SyRS-4 | SwRS-3 | AppRightsBL.cs (WriteBaseLog + WriteXxxLog-Methoden)
StRS-4 | SyRS-5 | SwRS-6, SwRS-7 | LicenseManager.cs (CheckLicense, TryFixCentronDelphiVersionNumber)
StRS-4 | SyRS-6 | SwRS-6 | LicenseManager.cs (LoadLicenses)
— | — | SwRS-4 | docs/guides/development/add-a-new-right.md, UserRightsConst.cs (Sichrech-Schema; kein direkter StRS/SyRS-Bezug, Basisinfrastruktur)
— | — | SwRS-5 | Centron.Common/DeveloperSecurity.cs (Entwicklungssicherheitsmaßnahme, kein Fachprozess)
StRS-5 | SyRS-7 | SwRS-9 | ReceiptBL.cs (ReceiptBase, CanUserEditReceipt, SpecificLogics-Dispatch)
StRS-6 | SyRS-10 | SwRS-11, SwRS-12 | ReceiptBL.cs (Versionierung), SaveReceiptRepository.cs (Legacy-Sync)
StRS-7 | SyRS-8 | SwRS-9 | ReceiptBL.cs (ConcurrencyControlGuid-Prüfung, TryLockReceipt)
StRS-8 | SyRS-9, SyRS-11 | SwRS-8, SwRS-10 | ReceiptBL.cs (UpdateReceiptIsPaid, ReceiptState)
StRS-9 | SyRS-12 | SwRS-13, SwRS-14 | AutomaticFacturaBL.Contracts.cs (SearchBillingContracts, GetActiveContracts)
StRS-10 | SyRS-12, SyRS-13 | SwRS-13 | AutomaticFacturaBL.Contracts.cs (ContractCalculationKind-Zweige)
StRS-11 | SyRS-14 | SwRS-15 | DunningBL.cs (GetDunningCustomers, CalculateDunningStatistics, UpdateDunningStopAndInfo)
StRS-12 | SyRS-15 | SwRS-16 | TaxBL.cs (GetTaxRateForReceiptItem, GetTaxRateChain)
StRS-13 | SyRS-16 | SwRS-17 | AccountBL.cs (Rechteprüfung CRUD, BookKeepingNumber-Kopplung)
StRS-14 | SyRS-17 | SwRS-18 | ReceiptWebServiceBL.cs (CAN_CHANGE_DATE), TimerBillingSettingsPageViewModel.cs
StRS-15 | SyRS-18 | SwRS-19 | HelpdeskState.cs, HelpdeskStateBase.cs, HelpdeskStateMaps.cs
StRS-16 | SyRS-19 | SwRS-20 | docker/compose/compose.yaml
@@ -0,0 +1,230 @@
# Messprotokoll – V1 Baseline (Prompt-only) – Prompt-Version 01, Lauf 4 (Wiederholungsmessung)
> Vierter Lauf des Prompts `01_Prompt.md`. **Konfiguration identisch zu Lauf 3** – gleiches
> Modell, gleiche Flags, gleicher Codebasis-Snapshot. Zweck: Bestimmung der **Laufvarianz**
> bei unveränderter Versuchsbedingung, um die Verbesserungen aus dem Shell-Zugriff von
> Zufallsstreuung trennen zu können.
## Lauf
- **Prompt-Datei:** `Versuche/Versuch_01/01_Prompt.md`
- **SHA-256 (Prompt):** `1B0DB06B8E0A5B92A5EFBDBEC5A0C554351FC928A16AEF34AAD9EAA0893C02FF`
(identisch zu allen bisherigen Läufen)
- **Startzeit:** 2026-08-25T15:05:17.4372276+02:00
- **Endzeit:** 2026-08-25T15:28:51.3123231+02:00
- **Dauer gesamt:** 00:23:34 (Wanduhr) bzw. 00:22:44 (`duration_ms`) — API: 00:22:09 (`duration_api_ms`)
- **Anders als in allen Vorläufen liegt die API-Dauer hier *unter* der Wanduhrzeit**, weil
dieser Lauf ohne Subagenten arbeitete und damit keine nebenläufigen Anfragen summierte.
- **Root-Verzeichnis:** `c:\DEV\MasterArbeit\QuellCode\CentronERP`
- **Codebasis-Commit:** `79c1142f489a32ba6a4a4cb043fd7f8550a9f257` (dirty: nein)
- **Snapshot-Zustand:** bereinigt von KI-Konfigurationen: **ja** (strenge Prüfung: 0 Treffer);
Remote entkoppelt: **ja**
- **Prompt-Repo-Commit:** `0ec86aed8cb8781054c86cbe0dd9f5eb0f7e5f05`
## Werkzeugkonfiguration
- **Laufverzeichnis-ID:** `v2.1.0-acab`
- **Ablage:** `Iteration 1/claude-sonnet-5/builtin/high/`
- **Parallele Läufe:** nein
- **Skill-Version:** `2.1.0` (wie 2.0.1, zusätzlich verpflichtende Modellabfrage vor dem Lauf)
- **Claude-Code-Version:** 2.1.245
- **CLI-Pfad:** `C:\Users\ChristophSchwoerer\.vscode\extensions\anthropic.claude-code-2.1.245-win32-x64\resources\native-binary\claude.exe`
- **Effort:** `high` — **nicht zur Laufzeit gesetzt**, sondern aus der Sitzung geerbt und
nachtraeglich aus dem Session-Transkript rekonstruiert (247 Nachrichten, durchgaengig `high`).
`RawResult.json` enthaelt kein `effort`-Feld. Ab Skill-Version 3.4.0 wird der Wert per
`--effort` explizit gesetzt.
- **Modell:** `claude-sonnet-5` (explizit gesetzt, vom Versuchsleiter vor dem Lauf gewählt);
zusätzlich `claude-haiku-4-5-20251001` für interne Hilfsaufrufe (4.176 Input-/20 Output-Tokens)
- **Permission-Mode:** `acceptEdits`
- **Toolfreigabe:**
- `--allowedTools "Bash" "PowerShell"`
- `--disallowedTools` mit 33 Einträgen (22 × `Bash(...)`, 11 × `PowerShell(...)`) für
schreibende Kommandos, Git-Mutationen und Build-Werkzeuge – identisch zu Lauf 3
- **Isolationsmechanismus:** eingefrorener Codebasis-Snapshot ohne KI-Konfigurationen,
zusätzlich `--safe-mode` und `--strict-mcp-config`
- **MCP-Server / Agentendateien:** keine – aus dem Snapshot entfernt, zusätzlich `--safe-mode`
- **Subagenten:** **0** (`spawned: 0`, `by_type: {}`)
- **Fast-Mode:** aus
## Verbrauch
### Hauptagent (`usage`)
| Messgröße | Wert |
|---|---|
| Input-Tokens | 280 |
| Output-Tokens | 121.969 (davon 25.826 Thinking-Tokens) |
| Cache-Write-Tokens | 256.300 |
| Cache-Read-Tokens | 27.179.499 |
| Agent-Turns | 147 |
### Gesamtlauf inkl. Subagenten (`modelUsage`, abrechnungsrelevant)
| Messgröße | `claude-sonnet-5` | `claude-haiku-4-5-20251001` | Summe |
|---|---:|---:|---:|
| Input-Tokens | 280 | 4.176 | 4.456 |
| Output-Tokens | 121.969 | 20 | 121.989 |
| Cache-Write-Tokens | 256.300 | 0 | 256.300 |
| Cache-Read-Tokens | 27.179.499 | 0 | 27.179.499 |
| Tokens gesamt | 27.558.048 | 4.196 | **27.562.244** |
**Tokens gesamt: 27.562.244** (Summe aus Input, Output, Cache-Write und Cache-Read ueber alle Modelle; `total_cost_usd` steht weiterhin in `RawResult.json`)
Da keine Subagenten liefen, sind Haupt- und Gesamtwerte für `claude-sonnet-5` hier identisch –
in allen Vorläufen klafften sie deutlich auseinander.
## Ergebnis
- **Status:** erfolgreich (`is_error: false`, `subtype: "success"`, `stop_reason: "end_turn"`,
`terminal_reason: "completed"`, Exit-Code 0, `Stderr.log` leer)
- **Session-ID:** `f3744c04-c4e2-4d9b-8fd6-d2e5e8ba2c15`
- **Permission-Denials:** **0**
- **Erzeugte Dateien:** alle 7 geforderten Artefakte in `Ergebnisse\`
| Datei | Größe | Inhalt |
|---|---:|---|
| `StRS.md` | 29.243 B | 16 Anforderungen |
| `SyRS.md` | 31.070 B | 19 Anforderungen |
| `SwRS.md` | 33.879 B | 20 Anforderungen |
| `Traceability.md` | 2.085 B | 21 Datenzeilen |
| `Hypothesen.md` | 2.156 B | 4 Einträge (H-1…H-4) |
| `Glossar.md` | 2.980 B | Domänenbegriffe |
| `Analysebericht.md` | 19.813 B | Modulinventar mit Tiefenklassifikation, Konsistenzcheck, Selbstbewertung |
Summe: **55 Anforderungen** über drei Ebenen.
- **Root unverändert:** ja. Vorher/Nachher-Vergleich identisch (beide leer), HEAD `79c1142`.
- **Abschlusstext des Agenten:** siehe `RawResult.json` (`result`)
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 16 | 29,1 % |
| SyRS | 19 | 34,5 % |
| SwRS | 20 | 36,4 % |
| **Gesamt** | **55** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| funktional | 23 | 41,8 % |
| Sicherheit | 13 | 23,6 % |
| Daten | 10 | 18,2 % |
| nicht-funktional (Zuverlässigkeit, ISO25010) | 4 | 7,3 % |
| nicht-funktional (Übertragbarkeit, ISO25010) | 2 | 3,6 % |
| nicht-funktional (Performance-Effizienz, ISO25010) | 2 | 3,6 % |
| nicht-funktional (Zuverlässigkeit / Security-ISO25010) | 1 | 1,8 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 67 |
| davon `PRIMÄR` | 54 (80,6 %) |
| davon `SEKUNDÄR` | 5 (7,5 %) |
| davon `KONTEXT` | 8 (11,9 %) |
| Belege je Anforderung (Median) | 1 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 54 (98,2 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 51 | 92,7 % |
| als `HYPOTHESE` gekennzeichnet | 4 | 7,3 % |
| als Workaround vermerkt | 4 | 7,3 % |
| Konsolidierungskandidaten | 6 | 10,9 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **erfüllt** (37 risikorelevante Anforderungen, alle gedeckt) |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 55 von 55 mit Tracelinks (100,0 %) |
## Vergleich aller Läufe (identischer Prompt)
| Messgröße | Lauf 1 (ohne Shell) | Lauf 2 (Abbruch) | Lauf 3 (mit Shell) | **Lauf 4 (mit Shell)** |
|---|---:|---:|---:|---:|
| Status | erfolgreich | API-Fehler | erfolgreich | erfolgreich |
| Modell | claude-sonnet-5 | claude-sonnet-5 | claude-sonnet-5 | claude-sonnet-5 |
| Permission-Denials | 36 | 0 | 0 | **0** |
| Dauer (Wanduhr) | 31:31 | 31:24 | 23:40 | **23:34** |
| Dauer (API) | 47:05 | 49:57 | 43:25 | **22:09** |
| Agent-Turns | 43 | 8 | 69 | **147** |
| Subagenten | 8 × Explore | 6 × general-purpose | 7 × Explore | **0** |
| Anforderungen gesamt | 96 | 89 (unvollst.) | 106 | **55** |
| — StRS / SyRS / SwRS | 28 / 28 / 40 | 45 / 44 / – | 30 / 38 / 38 | 16 / 19 / 20 |
| Traceability-Zeilen | 44 | – | 56 | 21 |
| Hypothesen | 12 | – | 9 | 4 |
| Output-Tokens (gesamt) | 249.040 | 226.613 | 229.997 | **121.989** |
| Cache-Read-Tokens | 11.959.137 | 15.618.130 | 10.542.089 | **27.179.499** |
| Tokens gesamt | 13.052.010 | 16.655.125 | 11.516.200 | **27.562.244** |
## Anmerkungen/Auffälligkeiten
1. **Zentrales Ergebnis dieser Wiederholungsmessung: Die Laufvarianz ist sehr groß.** Bei
*identischer* Konfiguration und *identischem* Prompt lieferte Lauf 4 **55 Anforderungen
gegenüber 106 in Lauf 3** – knapp die Hälfte. Auch Traceability (21 statt 56 Zeilen),
Hypothesen (4 statt 9) und Output-Tokens (121.989 statt 229.997) halbierten sich nahezu,
während die Kosten **stiegen** (7,69 statt 11.516.200 Tokens).
**Konsequenz für die Auswertung:** Der Vergleich Lauf 1 gegen Lauf 3 (96 gegenüber 106
Anforderungen) liegt vollständig innerhalb dieser Streuung. Die Anforderungsanzahl taugt
damit **nicht** als Wirkungsmaß für die Werkzeugkonfiguration. Belastbar bleibt allein die
Denial-Zahl (36 gegenüber 0), die eine direkte Eigenschaft der Konfiguration ist. Für
inhaltliche Aussagen sind mehrere Läufe je Bedingung und ein qualitatives Maß nötig.
2. **Ursache der Streuung: der Agent wählte eine völlig andere Strategie.** Lauf 4 startete
**keinen einzigen Subagenten** (Lauf 1: 8, Lauf 2: 6, Lauf 3: 7) und arbeitete stattdessen
in 147 eigenen Turns – mehr als doppelt so viele wie Lauf 3. Der gesamte Kontext lief dabei
durch den Hauptagenten, sichtbar an 27,18 Mio. Cache-Read-Tokens (2,6-fach gegenüber Lauf 3).
Das erklärt die höheren Kosten bei geringerem Output: Der Hauptagent las viel wiederholt,
statt Leseleistung an Subagenten mit eigenem Kontext auszulagern.
3. **Erstmals liegt die API-Dauer unter der Wanduhrzeit** (22:09 gegenüber 23:34). Das bestätigt
die Deutung aus den Vorprotokollen: Die Überschreitung in Lauf 1–3 entstand ausschließlich
durch nebenläufige Subagenten. Ohne sie summiert sich nichts mehr auf.
4. **Der Subagenten-Einsatz ist die dominierende Störgröße der Versuchsanordnung.** Er variierte
über vier Läufe bei identischem Prompt zwischen 0 und 8 Subagenten und zwischen zwei Typen
(`Explore`, `general-purpose`). Er bestimmt Laufzeit, Kosten, Token-Verteilung und
Ergebnisumfang stärker als die untersuchte Werkzeugkonfiguration. Für die Arbeit sollte
entweder je Bedingung über mehrere Läufe gemittelt oder der Subagenten-Einsatz im Prompt
bzw. per Flag festgeschrieben werden.
5. **Geringere Abdeckung, aber ehrlich dokumentiert.** Der Agent analysierte nach eigener Angabe
nur 10 geschäftskritische Module mit Quellcodebeleg und legt unanalysierte Bereiche (Einkauf,
Produktion, Projektverwaltung, kompletter WPF-Client, Nexus-Portal, externe API-Integrationen,
EDI) im `Analysebericht.md` offen. Der Bericht ist mit 19,8 KB der umfangreichste aller Läufe
und enthält ein Modulinventar mit Tiefenklassifikation (TIEF/MITTEL/FLACH/NICHT ANALYSIERT).
Weniger Anforderungen gehen hier also mit mehr Transparenz über die Lücken einher.
6. **Abweichende Dateistruktur bei Traceability und Hypothesen.** `Traceability.md` verwendet
eine Markdown-Tabelle ohne führendes `|`, `Hypothesen.md` eine Tabelle statt Überschriften
je Hypothese. Beides ist prompt-konform, erschwert aber die automatisierte Auswertung über
Läufe hinweg. Für die Arbeit wäre ein festes Ausgabeformat im Prompt sinnvoll.
7. **Zählabweichung bei Hypothesen** (wie in allen Läufen): `Hypothesen.md` führt 4 Einträge,
in den Anforderungsdateien stehen 6 Inline-Markierungen `[HYPOTHESE]`.
8. **Skill-Verbesserungen aus diesem Lauf** (bereits umgesetzt):
- Das Modell wird ab sofort **vor jedem Lauf beim User erfragt**; es gibt keinen Default mehr.
Kurzformen (`opus`, `sonnet`) sind untersagt, da sie sich über die Zeit verschieben.
- Die Snapshot-Prüfung meldete zunächst 3 Treffer, weil ein verkürzter Regex zusammen mit dem
case-insensitiven `Select-String` auf echte Produktdateien ansprach
(`ClaudeCodeChatModelClient.cs`, `GoogleGeminiChatModelClient.cs` – Teil des
KI-Assistenz-Features der ERP-Suite). Der strenge, verankerte Regex liefert korrekt 0.
Im Skill ist das nun als Warnung samt Beispielpfaden dokumentiert.
9. **Manuelle Eingriffe während des Laufs:** keine.
@@ -0,0 +1 @@
{"is_error":false,"duration_api_ms":1328822,"num_turns":147,"stop_reason":"end_turn","session_id":"f3744c04-c4e2-4d9b-8fd6-d2e5e8ba2c15","total_cost_usd":7.685625800000001,"usage":{"input_tokens":280,"cache_creation_input_tokens":256300,"cache_read_input_tokens":27179499,"output_tokens":121969,"output_tokens_details":{"thinking_tokens":25826},"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":256300,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":832,"cache_read_input_tokens":294066,"cache_creation_input_tokens":676,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":676},"type":"message"}],"speed":"standard"},"modelUsage":{"claude-haiku-4-5-20251001":{"inputTokens":4176,"outputTokens":20,"cacheReadInputTokens":0,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.004276,"contextWindow":200000,"maxOutputTokens":32000,"canonicalModel":"claude-haiku-4-5","provider":"firstParty"},"claude-sonnet-5":{"inputTokens":280,"outputTokens":121969,"cacheReadInputTokens":27179499,"cacheCreationInputTokens":256300,"webSearchRequests":0,"costUSD":7.681349800000001,"contextWindow":1000000,"maxOutputTokens":64000,"canonicalModel":"claude-sonnet-5","provider":"firstParty"}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","fast_mode_disabled_reason":"extra_usage_disabled","subagent_stats":{"spawned":0,"requested":{"background":0,"foreground":0,"unset":0},"started_in_background":0,"max_depth":0,"spawned_by_subagents":0,"completed":0,"failed":0,"killed":{"parent":0,"user":0,"system":0},"refused":{"depth_limit":0,"concurrency_limit":0,"budget":0},"by_type":{}},"subtype":"success","api_error_status":null,"result":"Der Lauf ist abgeschlossen. Zusammenfassung:\n\n**Ergebnis** (in `c:\\DEV\\MasterArbeit\\Versuche\\Versuch_01\\01_Lauf_2026-08-25_1505\\Ergebnisse\\`):\n- **55 Anforderungen** (StRS-1..16, SyRS-1..19, SwRS-1..20) über 10 fachliche Module: Rechteverwaltung, Lizenzierung, Verkaufsbelege-Kernarchitektur, Verträge/automatisierte Abrechnung, Mahnwesen, Umsatzsteuer, Kunden-/Lieferantenstammdaten, Zeiterfassungsabrechnung, Helpdesk-Statusverwaltung, Betrieb/Docker-Bereitstellung.\n- Jede Anforderung mit Fakt/Aussage-Trennung, klassifizierten Belegen (PRIMÄR/SEKUNDÄR/KONTEXT), Prüfidee und Tracelinks; sicherheits-/abrechnungs-/berechtigungsrelevante Aussagen tragen durchweg mindestens einen PRIMÄR-Beleg aus echtem Quellcode (z. B. `AppRightsBL.cs`, `LicenseManager.cs`, `ReceiptBL.cs`, `AutomaticFacturaBL.Contracts.cs`, `TaxBL.cs`).\n- 4 offene Hypothesen (H-1 bis H-4) dokumentiert, Konsistenzcheck ohne Duplikate/fehlende Belege/kaputte Tracelinks, vollständiges Moduleninventar mit ehrlicher Tiefenklassifikation (TIEF/MITTEL/FLACH/NICHT ANALYSIERT) im `Analysebericht.md`.\n\n**Wichtigste Einschränkung**: Angesichts der Codebasis-Größe (>11.000 Quelldateien) wurden nur 10 geschäftskritische Module tatsächlich mit Quellcode belegt; große Bereiche (Einkauf, Produktion, Projektverwaltung, kompletter WPF-Client, Nexus-Portal, externe API-Integrationen, EDI) blieben unanalysiert – das ist in Abschnitt 3.4 und 4 des Analyseberichts offengelegt, nicht verschwiegen.","ttft_ms":11081,"ttft_stream_ms":1148,"time_to_request_ms":36,"type":"result","duration_ms":1363916,"uuid":"43ba2f31-1596-4239-9d67-7896c1740965","queued_turn_count":0}
@@ -0,0 +1,949 @@
[
{
"id": "StRS-1",
"ebene": "StRS",
"titel": "Rollen-/gruppenbasierte Rechteverwaltung",
"typ": "Sicherheit",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-1, SyRS-4, SwRS-1, SwRS-2",
"konsolidierung": "nein",
"pruefidee": "Einem Benutzer wird ein Recht ausschließlich über Gruppenmitgliedschaft zugewiesen; Entfernen",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-2",
"ebene": "StRS",
"titel": "Filialbezogene Einschränkung von Verwaltungsrechten",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-1, SwRS-3",
"konsolidierung": "nein",
"pruefidee": "Benutzer mit MANAGE_RIGHTS_ONLY_OWN_BRANCH versucht Gruppe einer fremden Filiale zu löschen;",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-3",
"ebene": "StRS",
"titel": "Nachvollziehbarkeit von Rechteänderungen",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-4, SwRS-3",
"konsolidierung": "nein",
"pruefidee": "Nach AddRightToRightGroup existiert ein neuer AppRightLog-Eintrag mit Kind=AddRightToGroup.",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-4",
"ebene": "StRS",
"titel": "Feature- und Applikationslizenzierung pro Kunde",
"typ": "funktional",
"belege": [
"SEKUNDÄR"
],
"status": "belegt",
"hypothese": true,
"workaround": false,
"tracelinks": "SyRS-2, SwRS-6",
"konsolidierung": "nein",
"pruefidee": "Kunde ohne Lizenz für Modul X: LicenseManager.HasLicense(X) liefert false, UI blendet Modul X aus.",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-5",
"ebene": "StRS",
"titel": "Einheitlicher Belegprozess über den gesamten Auftrag-zu-Zahlung-Zyklus",
"typ": "funktional",
"belege": [
"PRIMÄR",
"SEKUNDÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-7, SyRS-8, SwRS-8",
"konsolidierung": "nein",
"pruefidee": "Für jeden der sieben Belegtypen existiert eine Entity-Klasse, die von ReceiptBase erbt und",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-6",
"ebene": "StRS",
"titel": "Nachvollziehbare, unveränderliche Belegversionshistorie",
"typ": "funktional",
"belege": [
"PRIMÄR",
"SEKUNDÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-10, SwRS-11, SwRS-12",
"konsolidierung": "nein",
"pruefidee": "Beleg wird zweimal gespeichert (Version 1 → 2); GetReceiptVersionByI3D(..., version:1) liefert",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-7",
"ebene": "StRS",
"titel": "Schutz vor gleichzeitiger, kollidierender Bearbeitung eines Belegs",
"typ": "nicht-funktional (Zuverlässigkeit, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-8, SwRS-9",
"konsolidierung": "nein",
"pruefidee": "Benutzer A lädt Beleg (Guid=X), Benutzer B speichert denselben Beleg zuerst (Guid ändert",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-8",
"ebene": "StRS",
"titel": "Verwaltung des Zahlungsstatus eines Belegs durch die Debitorenbuchhaltung",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-9, SyRS-11, SwRS-8, SwRS-10",
"konsolidierung": "nein",
"pruefidee": "Setzen von isPaid=true auf einem aktiven Beleg ändert dessen State auf Completed; erneutes",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-9",
"ebene": "StRS",
"titel": "Automatisierte, wiederkehrende Vertragsabrechnung",
"typ": "funktional",
"belege": [
"PRIMÄR",
"SEKUNDÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-12, SyRS-13, SwRS-13, SwRS-14",
"konsolidierung": "nein",
"pruefidee": "Vertrag mit CalculationKind=Auto, State=aktiv, fälligem Intervall und mind. einer abrechenbaren",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-10",
"ebene": "StRS",
"titel": "Unterschiedliche Abrechnungssteuerung je Vertrag (automatisch / nach Bedarf / manuell)",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-12, SwRS-13",
"konsolidierung": "nein",
"pruefidee": "Zwei sonst identische Verträge mit CalculationKind=Auto bzw. =Need: nur der Auto-Vertrag wird",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-11",
"ebene": "StRS",
"titel": "Mehrstufiges Mahnwesen für überfällige Rechnungen",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-14, SwRS-15",
"konsolidierung": "nein",
"pruefidee": "Rechnung mit DunningLevel=Level1 und Restbetrag > 0 erscheint in",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-12",
"ebene": "StRS",
"titel": "Zeitlich korrekte Umsatzsteuerermittlung für Belegpositionen",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-15, SwRS-16",
"konsolidierung": "nein",
"pruefidee": "Belegposition mit Belegdatum vor einer historischen Steuersatzänderung liefert den alten",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-13",
"ebene": "StRS",
"titel": "Vereinheitlichte Geschäftspartner-Stammdaten (Kunde und/oder Lieferant in einer Entität)",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-16, SwRS-17",
"konsolidierung": "nein",
"pruefidee": "Ein Account-Datensatz mit gesetzter CustomerNumber UND SupplierNumber lässt sich anlegen und",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-14",
"ebene": "StRS",
"titel": "Rechtebasierte Freigabe zum manuellen Überschreiben des Abrechnungsdatums",
"typ": "funktional",
"belege": [
"PRIMÄR",
"SEKUNDÄR"
],
"status": "belegt",
"hypothese": true,
"workaround": false,
"tracelinks": "SyRS-17, SwRS-18",
"konsolidierung": "Kandidat: StRS-1 (gleiches zugrundeliegendes Rechtesystem, hier auf ein einzelnes Feld",
"pruefidee": "Benutzer ohne CAN_CHANGE_DATE-Recht öffnet Timer-Billing-Einstellungen: Datumsfeld ist",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-15",
"ebene": "StRS",
"titel": "Konfigurierbare Ticketstatus-Verwaltung mit Verrechnungssteuerung je Status",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-18, SwRS-19",
"konsolidierung": "nein",
"pruefidee": "Anlegen eines neuen HelpdeskState-Datensatzes mit IsInternalCompanyBillingActive=false; Tickets",
"qm": "",
"uebernahme": ""
},
{
"id": "StRS-16",
"ebene": "StRS",
"titel": "Containerisierte, mehrteilige Serverbereitstellung",
"typ": "nicht-funktional (Übertragbarkeit, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-19, SwRS-20",
"konsolidierung": "nein",
"pruefidee": "`docker compose up` im Verzeichnis docker/compose startet alle vier Dienste; der Webservice",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-1",
"ebene": "SyRS",
"titel": "Serverseitige Rechteprüfung vor sicherheitsrelevanten Operationen",
"typ": "Sicherheit",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-1, SwRS-1, SwRS-2",
"konsolidierung": "nein",
"pruefidee": "Direkter (simulierter) Aufruf einer BL-Methode ohne vorherige UI-Prüfung mit einem Benutzer",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-2",
"ebene": "SyRS",
"titel": "Getrenntes Rechtesystem für Web-Konten",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-1, SwRS-1",
"konsolidierung": "nein",
"pruefidee": "Web-Account mit Recht X, aber ohne entsprechendes internes Sichtrus-Recht, wird bei HasWebAccountRight(X)",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-3",
"ebene": "SyRS",
"titel": "Schutz der Administratoren-Gruppe vor Löschung und Rechteentzug",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-2, SwRS-3",
"konsolidierung": "nein",
"pruefidee": "Löschversuch der Gruppe I3D=6 liefert Result.Error \"Die Adminstratoren Gruppe darf nicht",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-4",
"ebene": "SyRS",
"titel": "Lückenlose Protokollierung rechterelevanter Änderungen",
"typ": "nicht-funktional (Zuverlässigkeit / Security-ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-3, SwRS-3",
"konsolidierung": "nein",
"pruefidee": "Für jede der acht Schreibmethoden existiert im Code ein zugehöriger, unbedingter WriteXxxLog-Aufruf",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-5",
"ebene": "SyRS",
"titel": "Versions- und Mengenbeschränkte Lizenzprüfung beim Anwendungs-Login",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-4, SwRS-6",
"konsolidierung": "nein",
"pruefidee": "Login mit abgelaufener Lizenzversion liefert Result.Error; Login, der die maximale",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-6",
"ebene": "SyRS",
"titel": "Datenbank-Update wird bei fehlender Lizenz blockiert",
"typ": "Sicherheit",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-4, SwRS-6",
"konsolidierung": "nein",
"pruefidee": "Webservice-Start ohne gültige Centron-Lizenz: Startvorgang bricht ab, bevor Migrationsskripte",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-7",
"ebene": "SyRS",
"titel": "Recht- und filialbasierte Bearbeitungsprüfung vor jeder Belegänderung",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-5, StRS-7, SwRS-9",
"konsolidierung": "nein",
"pruefidee": "Benutzer ohne Bearbeitungsrecht für Rechnungen versucht, eine Rechnung zu speichern; Result",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-8",
"ebene": "SyRS",
"titel": "Optimistische Sperre verhindert verlorene Aktualisierungen",
"typ": "nicht-funktional (Zuverlässigkeit, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-7, SwRS-9",
"konsolidierung": "Kandidat: SyRS-9 (verwandter Zustands-Schutzmechanismus)",
"pruefidee": "Zwei parallele Ladevorgänge desselben Belegs, sequentielle Speicherversuche: der zweite",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-9",
"ebene": "SyRS",
"titel": "Stornierte Belege sind gegen Zahlungsstatusänderung geschützt",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-5, SwRS-8, SwRS-10",
"konsolidierung": "nein",
"pruefidee": "UpdateReceiptIsPaid auf einem Beleg mit State=Canceled liefert Result.Error unabhängig vom",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-10",
"ebene": "SyRS",
"titel": "Vollständige Versionierung bei jeder Belegspeicherung",
"typ": "nicht-funktional (Zuverlässigkeit, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-6, SwRS-11, SwRS-12",
"konsolidierung": "nein",
"pruefidee": "Für jeden der sieben Belegtypen: Speichern einer Änderung erzeugt einen neuen Versionsdatensatz",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-11",
"ebene": "SyRS",
"titel": "Ausnahmerecht für Zahlungseingang unabhängig vom allgemeinen Bearbeitungsrecht",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-8",
"konsolidierung": "nein",
"pruefidee": "Benutzer mit ausschließlich INCOMING_PAYMENT_TRANSACTIONS (kein allgemeines Bearbeitungsrecht):",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-12",
"ebene": "SyRS",
"titel": "Mehrstufige Selektion abrechnungsfähiger Verträge",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-9, SwRS-13, SwRS-14",
"konsolidierung": "nein",
"pruefidee": "Aktiver Vertrag ohne Vertragspositionen wird trotz fälligem Intervall NICHT in die finale",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-13",
"ebene": "SyRS",
"titel": "Berücksichtigung von Sonderartikel-Stichtagen bei dynamischen Bedarfsverträgen",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-9, StRS-10",
"konsolidierung": "nein",
"pruefidee": "Dynamischer Bedarfsvertrag ohne Sonderartikel-Stichtag im Abrechnungszeitraum wird aus der",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-14",
"ebene": "SyRS",
"titel": "Zeitraumbezogene Mahnsperre je Kunde/Objekt",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-11, SwRS-15",
"konsolidierung": "nein",
"pruefidee": "Setzen einer Mahnsperre mit dunningStopEnd in der Zukunft: das Objekt wird im nächsten",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-15",
"ebene": "SyRS",
"titel": "Rückwärtssuche in der Steuersatzhistorie bis zum passenden Gültigkeitszeitraum",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-12, SwRS-16",
"konsolidierung": "nein",
"pruefidee": "Kette mit Steuersatz A (gültig bis 30.06.), Nachfolger B (ab 01.07.): receiptDate=15.06.",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-16",
"ebene": "SyRS",
"titel": "Granulare Rechteprüfung je CRUD-Operation auf Geschäftspartnerdaten",
"typ": "Sicherheit",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-13, SwRS-17",
"konsolidierung": "Kandidat: SyRS-1 (gleiches zugrundeliegendes Rechteprüfungsmuster CheckRightsFromUser,",
"pruefidee": "Benutzer mit ausschließlich EDIT_CUSTOMER: Bearbeiten eines bestehenden Kunden gelingt,",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-17",
"ebene": "SyRS",
"titel": "Getrennte Rechte für Datumsänderung bei Rechnung und Lieferschein",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-14, SwRS-18",
"konsolidierung": "nein",
"pruefidee": "Benutzer mit DeliveryList.CAN_CHANGE_DATE, aber ohne Invoice.CAN_CHANGE_DATE:",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-18",
"ebene": "SyRS",
"titel": "Ticketstatus als Stammdaten statt Programmkonstante",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-15, SwRS-19",
"konsolidierung": "Kandidat: SwRS-8 (gegensätzliches Muster: Belegstatus fest vs. Ticketstatus konfigurierbar –",
"pruefidee": "Ein neuer HelpdeskState-Datensatz ist über die Rechteverwaltungs-/Admin-UI anlegbar und",
"qm": "",
"uebernahme": ""
},
{
"id": "SyRS-19",
"ebene": "SyRS",
"titel": "Linux-Fähigkeit des Webservice-Hosts",
"typ": "nicht-funktional (Übertragbarkeit, ISO25010)",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": true,
"workaround": false,
"tracelinks": "StRS-16, SwRS-20",
"konsolidierung": "nein",
"pruefidee": "Webservice-Container basierend auf einem Linux-Basisimage startet erfolgreich und beantwortet",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-1",
"ebene": "SwRS",
"titel": "Sessionweites Caching der Benutzerrechte",
"typ": "nicht-funktional (Performance-Effizienz, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-1",
"konsolidierung": "Kandidat: SwRS-2 (ähnlicher Cache-Mechanismus für Web-Account-Rechte, HasWebAccountRight)",
"pruefidee": "Zwei aufeinanderfolgende HasUserRight-Aufrufe für denselben Benutzer in derselben Session:",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-2",
"ebene": "SwRS",
"titel": "Massenprüfung mehrerer Rechte in einem Datenbankzugriff",
"typ": "funktional",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-1",
"konsolidierung": "Kandidat: SwRS-1",
"pruefidee": "Aufruf mit 5 Recht-IDs, von denen der Benutzer 3 besitzt, liefert eine Liste mit genau",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-3",
"ebene": "SwRS",
"titel": "Hartkodierte Positivliste änderbarer Administrator-Rechte",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt; Workaround (hartkodierte ID-Liste statt konfigurierbarer Regel — Migrationsrisiko:",
"hypothese": false,
"workaround": true,
"tracelinks": "SyRS-3, SyRS-4",
"konsolidierung": "nein",
"pruefidee": "Zuweisungsversuch eines Rechts mit I3D, das nicht in der Liste enthalten ist, an die",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-4",
"ebene": "SwRS",
"titel": "Hierarchisches Rechteschema in Tabelle Sichrech",
"typ": "Daten",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-1",
"konsolidierung": "nein",
"pruefidee": "Ausführen eines Migrationsskripts mit AddRightIfNotExists erzeugt einen neuen Sichrech-Datensatz",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-5",
"ebene": "SwRS",
"titel": "Entwicklungsseitige Umleitung externer E-Mail-Adressen in Debug-Builds",
"typ": "Sicherheit",
"belege": [
"PRIMÄR"
],
"status": "belegt; Workaround (baujahresspezifischer Schutzmechanismus für die bestehende Delphi-/",
"hypothese": false,
"workaround": true,
"tracelinks": "(kein direkter StRS/SyRS-Bezug – reine Entwicklungssicherheitsmaßnahme, kein Fachprozess)",
"konsolidierung": "nein",
"pruefidee": "Debug-Build, Versand an \"kunde@fremdefirma.de\": tatsächlicher SMTP-Empfänger ist",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-6",
"ebene": "SwRS",
"titel": "Lizenzmanager als Prozess-Singleton mit expliziter Einmalinitialisierung",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-5, SyRS-6",
"konsolidierung": "nein",
"pruefidee": "Zweiter Aufruf von Initialize() in derselben Prozessinstanz löst eine Exception aus;",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-7",
"ebene": "SwRS",
"titel": "Sonderbehandlung der c-entron-Delphi-Versionsnummer bei der Lizenzprüfung",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt; Workaround (Altlast aus der Koexistenz von c-entron Delphi und c-entron.NET; für",
"hypothese": false,
"workaround": true,
"tracelinks": "SyRS-5",
"konsolidierung": "nein",
"pruefidee": "Login mit Version \"9.3.40.2\" und Centron-Lizenz-GUID wird nicht wegen Versionsüberschreitung",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-8",
"ebene": "SwRS",
"titel": "Dreiwertiger Belegstatus (ReceiptState) als gemeinsamer Zustandsautomat",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": true,
"workaround": false,
"tracelinks": "StRS-5, SyRS-9",
"konsolidierung": "nein",
"pruefidee": "Kompilierzeitprüfung/Reflection: ReceiptState besitzt genau die drei genannten Werte.",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-9",
"ebene": "SwRS",
"titel": "SpecificLogics-Dispatch für belegtypspezifische Rechteprüfung",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-7, StRS-7",
"konsolidierung": "nein",
"pruefidee": "Für zwei verschiedene Belegtypen mit unterschiedlichen HasRightToEditReceipt-Implementierungen",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-10",
"ebene": "SwRS",
"titel": "Ableitung des Belegstatus aus dem Zahlungsflag",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-8, SyRS-9",
"konsolidierung": "nein",
"pruefidee": "isPaid=true auf einem Active-Beleg: State wird Completed; isPaid=false auf einem",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-11",
"ebene": "SwRS",
"titel": "Versionsinkrement als eigenständiger Zustand vor dem eigentlichen Speichern",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-6, SyRS-10",
"konsolidierung": "nein",
"pruefidee": "Versuch, aus einer historischen Version mit aktiven Barcodes eine neue Version zu erzeugen,",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-12",
"ebene": "SwRS",
"titel": "Duale Persistenzschicht: moderne Entity plus Legacy-Repository-Synchronisation",
"typ": "Daten",
"belege": [
"PRIMÄR",
"KONTEXT"
],
"status": "belegt; Workaround (historisch gewachsene Doppelpersistenz; zentrales Migrationsrisiko für",
"hypothese": false,
"workaround": true,
"tracelinks": "StRS-6, SyRS-10",
"konsolidierung": "nein",
"pruefidee": "Neues Feld wird nur der modernen Entity/Mapping hinzugefügt, nicht dem Repository: Wert wird",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-13",
"ebene": "SwRS",
"titel": "Bedingte LINQ-Filterausdrücke je Berechnungsart in GetActiveContracts",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-12, StRS-10",
"konsolidierung": "nein",
"pruefidee": "Vertrag mit LastPaidDate >= ContractEnd und CalculationKind=Auto wird NICHT selektiert",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-14",
"ebene": "SwRS",
"titel": "Stapelweise (Batch) Nachfilterung großer Vertragsmengen über NamedQueries",
"typ": "nicht-funktional (Performance-Effizienz, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "SyRS-12",
"konsolidierung": "nein",
"pruefidee": "Abrechnungslauf mit > 2000 abrechnungsfähigen Verträgen schlägt nicht mit einem",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-15",
"ebene": "SwRS",
"titel": "Offener-Betrag-Berechnung je Mahnstufe aus drei Rechnungsbeträgen",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-11, SyRS-14",
"konsolidierung": "nein",
"pruefidee": "Rechnung mit GrossPriceComplete=1000, PayedGrossAmount=300, CreditVoucherGrossAmount=100:",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-16",
"ebene": "SwRS",
"titel": "Verkettete Steuersatz-Entität mit Fallback auf artikelspezifischen Standardsatz",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-12, SyRS-15",
"konsolidierung": "nein",
"pruefidee": "Aufruf mit einer nicht existierenden taxRateI3D liefert nicht null, sondern den",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-17",
"ebene": "SwRS",
"titel": "Konfigurierbare Kopplung von Buchhaltungsnummer und Kundennummer",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-13, SyRS-16",
"konsolidierung": "nein",
"pruefidee": "Mit aktivierter Einstellung: neu angelegter Kunde mit Nummer 4711 erhält BookKeepingNumber",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-18",
"ebene": "SwRS",
"titel": "Belegtypabhängige UI-Feldsperre mit erklärendem Hinweistext",
"typ": "funktional",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-14, SyRS-17",
"konsolidierung": "nein",
"pruefidee": "ReceiptKind=InvoiceClass, CanChangeDateInInvoices=false: BillingDateIsEnabled=false,",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-19",
"ebene": "SwRS",
"titel": "Erweiterung der Basis-Statusdaten um Verrechnungs- und Portaldarstellungsfelder",
"typ": "Daten",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-15, SyRS-18",
"konsolidierung": "nein",
"pruefidee": "Zwei HelpdeskState-Datensätze mit unterschiedlichem ServiceBoardWebColor erscheinen im",
"qm": "",
"uebernahme": ""
},
{
"id": "SwRS-20",
"ebene": "SwRS",
"titel": "Explizite Dienstabhängigkeit und Neustartrichtlinie in der Compose-Topologie",
"typ": "nicht-funktional (Zuverlässigkeit, ISO25010)",
"belege": [
"PRIMÄR"
],
"status": "belegt",
"hypothese": false,
"workaround": false,
"tracelinks": "StRS-16, SyRS-19",
"konsolidierung": "nein",
"pruefidee": "Manuelles Beenden des webservice-Containers: Compose startet ihn automatisch neu, ohne dass",
"qm": "",
"uebernahme": ""
}
]
@@ -0,0 +1,62 @@
## Gefundene Anforderungen
Maschinell aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet (Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.
Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach Likert-Skala tritt daneben und wird hier nicht ersetzt.
### Verteilung über die Ebenen
| Ebene | Anzahl | Anteil |
|---|---:|---:|
| StRS | 16 | 29,1 % |
| SyRS | 19 | 34,5 % |
| SwRS | 20 | 36,4 % |
| **Gesamt** | **55** | 100 % |
### Anforderungstypen
| Typ | Anzahl | Anteil |
|---|---:|---:|
| funktional | 23 | 41,8 % |
| Sicherheit | 13 | 23,6 % |
| Daten | 10 | 18,2 % |
| nicht-funktional (Zuverlässigkeit, ISO25010) | 4 | 7,3 % |
| nicht-funktional (Übertragbarkeit, ISO25010) | 2 | 3,6 % |
| nicht-funktional (Performance-Effizienz, ISO25010) | 2 | 3,6 % |
| nicht-funktional (Zuverlässigkeit / Security-ISO25010) | 1 | 1,8 % |
### Belegqualität
| Messgröße | Wert |
|---|---:|
| Belege gesamt | 67 |
| davon `PRIMÄR` | 54 (80,6 %) |
| davon `SEKUNDÄR` | 5 (7,5 %) |
| davon `KONTEXT` | 8 (11,9 %) |
| Belege je Anforderung (Median) | 1 |
| Anforderungen mit mindestens einem `PRIMÄR`-Beleg | 54 (98,2 %) |
### Übernahmewürdigkeit
**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.
### Status
| Kategorie | Anzahl | Anteil |
|---|---:|---:|
| belegt | 51 | 92,7 % |
| als `HYPOTHESE` gekennzeichnet | 4 | 7,3 % |
| als Workaround vermerkt | 4 | 7,3 % |
| Konsolidierungskandidaten | 6 | 10,9 % |
| mit ISO-25010-Qualitätsmerkmal | 0 | 0,0 % |
### Regelkonformität (Prüfung gegen die Vorgaben des Prompts)
| Vorgabe | Ergebnis |
|---|---|
| **Belegpflicht** – jede Anforderung mindestens ein Artefaktbeleg | **erfüllt** (0 Anforderungen ohne Beleg) |
| **Risikobasierte Priorisierung** – Sicherheit, Abrechnung, Berechtigungen brauchen einen `PRIMÄR`-Beleg oder die Kennzeichnung `[HYPOTHESE]` | **erfüllt** (37 risikorelevante Anforderungen, alle gedeckt) |
| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | **erfüllt** |
| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | *nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26) |
| **Traceability** – Verknüpfung zwischen den Ebenen | 55 von 55 mit Tracelinks (100,0 %) |
@@ -0,0 +1,5 @@
# Subagenten-Aufrufe
Session `f3744c04-c4e2-4d9b-8fd6-d2e5e8ba2c15`, Transkript `f3744c04-c4e2-4d9b-8fd6-d2e5e8ba2c15.jsonl`.
`subagent_stats`: **0** Subagenten gesamt, davon **0** von Subagenten gestartet (max_depth 0). Direkt vom Hauptagenten erwartet: **0**. Im Transkript gefunden: **0**.
@@ -0,0 +1,109 @@
# Analysebericht — Reverse Requirements Engineering CentronERP
Versuch 01 (Baseline, Prompt-only), Iteration 01. Erstellt am 2026-08-25. Untersuchungsgegenstand: gesamte Codebasis unter `C:\DEV\MasterArbeit\QuellCode\CentronERP` (15.554 `.cs`-Dateien, 1.233 `.xaml`-Dateien, ca. 90 fachliche Business-Logic-Module unter `src/backend/Centron.BL`, mehrere eigenständige Anwendungen: WPF-Desktop-Client, CentronNexus-Webanwendung, diverse API-/Integrationsprojekte). Ergebnis: 43 StRS-, 150 SyRS- und 132 SwRS-Anforderungen (325 gesamt) in elf fachlichen Analyseclustern.
## 1. Vorgehen
Da eine gleich tiefe Analyse aller ca. 90 Business-Logic-Module, aller WPF-Views/ViewModels und aller Datenbankentitäten in einem Lauf nicht leistbar ist, wurde die Analysetiefe selbstständig priorisiert (wie im Auftrag vorgesehen): Es wurden elf fachliche Cluster gebildet und jeweils durch einen eigenen Analyse-Durchgang mit Lesezugriff auf Quellcode, Dokumentation (`docs/`) und Commit-Historie bearbeitet:
| Cluster | Schwerpunkt | Primäre Codebereiche |
|---|---|---|
| ARCH | Anwendungsarchitektur & Systemrahmen | `Centron.WPF.UI/{Modules,Start,Managers,Layout,Wizards,Localization}`, `Centron.Core`, `docs/reference/architecture` |
| SEC | Sicherheit & Berechtigungen | `Centron.BL/{Security,PasswordManager,PasswordManagementArea,TwoFactorAuthenticator}`, `CentronRights.md`, `docs/reference/security` |
| CRM | Stammdaten (Geschäftspartner, Kunden, Mitarbeiter) | `Centron.BL/{BusinessPartner,CustomerArea,EmployeeArea,CountryArea}` |
| SALES | Vertrieb & Einkauf | `Centron.BL/{Sales,Buying,Purchasing,ProductMatrix,TradePool}` |
| BILL | Abrechnung, Fakturierung & Verträge | `Centron.BL/{VoucherManagement,Accounting,Finances}`, `docs/reference/receipts`, ZUGFeRD/XRechnung-Doku |
| TIME | Zeiterfassung, Projekte & Tickets (intern) | `Centron.BL/{Time,TicketProjects,Projects,TaskManager,MyDay,Calendar,AppointmentRequests}` |
| LOG | Lager, Logistik & Produktion | `Centron.BL/{Warehousing,Logistics,Production,Devices}` |
| ADM | Administration, Systemkonfiguration & Kommunikation | `Centron.BL/{Administration,SystemArea,Customizations,Modules,Notifications,Mailings,Mail,MailScanner}` |
| DOC | Dokumente & Reporting | `Centron.BL/{DocuBoard,DocumentationArea,Reporting,ReportEngine,TextModuleArea}`, `Centron.Api.docuFORM` |
| INT | Externe Integrationen & Schnittstellen | `Centron.BL/{EDI,DataExchange,WebServices,Gateway,Integrations}`, `Centron.Gateway`, `src/apis/*`, `src/webservice` |
| NEX | CentronNexus (Ticket-/Helpdesk-System) | `src/nexus/*`, `Centron.BL/{ExternalHelpdesk,CentronNexus,NexusNotifications,NexusTicketViews}` |
Jeder Cluster-Durchgang erfasste Fakten mit Artefaktbeleg, leitete Anforderungskandidaten für StRS/SyRS/SwRS ab und klassifizierte Belege als PRIMÄR/SEKUNDÄR/KONTEXT. In einem zweiten Schritt wurden die Kandidaten je Cluster in das finale ID-Schema (`<Ebene>-<CLUSTER>-<laufende Nummer>`) überführt und intra-cluster Tracelinks gebildet. Abschließend wurden alle elf Cluster zentral zusammengeführt, ein cluster-übergreifender Konsistenzcheck durchgeführt (Abschnitt 3) und cluster-übergreifende Konsolidierungskandidaten identifiziert (Abschnitt 4).
## 2. Abdeckung nach Modul
### 2.1 Vollständig bzw. gezielt tief analysiert (mit Artefaktbelegen in StRS/SyRS/SwRS)
Business-Logic-Module: `Security`, `PasswordManager`, `PasswordManagementArea`, `TwoFactorAuthenticator`, `BusinessPartner`, `CustomerArea`, `EmployeeArea`, `CountryArea`, `Sales`, `Buying`, `Purchasing`, `ProductMatrix`, `TradePool`, `VoucherManagement`, `Accounting`, `Finances`, `Time`, `TicketProjects`, `Projects`, `TaskManager`, `MyDay`, `Calendar`, `AppointmentRequests`, `Warehousing`, `Logistics`, `Production`, `Devices`, `Administration`, `SystemArea`, `Customizations`, `Modules`, `Notifications`, `Mailings`, `Mail`, `MailScanner`, `DocuBoard`, `DocumentationArea`, `Reporting`, `ReportEngine`, `TextModuleArea`, `EDI`, `DataExchange`, `WebServices`, `Gateway`, `Integrations`, `ExternalHelpdesk`, `CentronNexus` (BL-Anteil), `NexusNotifications`, `NexusTicketViews`.
Eigenständige Projekte: `src/nexus/CentronNexus`, `src/nexus/CentronNexus.Host`, `Centron.Gateway`, `Centron.Api.docuFORM`, `src/apis/Centron.Api.EbInterface`, `src/apis/Centron.APIs.{CopDataAccess,EgisDataAccess,FinAPI,IcecatDataAccess,ITscopeDataAccess}`, `src/webservice` (als Integrationsplattform), `Centron.WPF.UI/{Modules,Start,StartupArgs,Managers,Layout,Wizards,Localization}`, `Centron.Core`.
Dokumentation: alle Dateien unter `docs/reference/` und `docs/guides/` sowie `docs/features/automatic-helpdesk-creation-templates.md` wurden gelesen und als Belege verwendet; `CentronRights.md` vollständig.
Innerhalb dieser Module wurde nicht jede einzelne Datei vollständig gelesen — die Cluster-Agenten haben gezielt Statusmaschinen, Validierungslogik, Berechtigungsprüfungen und Berechnungsregeln über Grep/Glob lokalisiert und die betroffenen Methoden/Klassen im Detail gelesen. Bekannte Detaillücken pro Cluster sind in den jeweiligen "Abdeckung"-Abschnitten der Rohbefunde dokumentiert (siehe `_staging/*.md`) und teilweise als `[HYPOTHESE]` in Hypothesen.md erfasst.
### 2.2 Nur stichprobenhaft/oberflächlich analysiert
- `src/apis/Centron.Api.Gls`, `src/apis/Centron.Api.Shipcloud` (Versanddienstleister-APIs): nur als Kontextreferenz aus dem LOG-Cluster erwähnt, keine eigene Tiefenanalyse (siehe SyRS-LOG-15, als Hypothese/Lücke dokumentiert).
- `src/nexus/CentronNexus.OutlookAddIn`: nur oberflächlich, Kernlogik von CentronNexus.Host stand im Vordergrund.
- `Centron.WPF.UI/{Dialogs,Views,ViewModels}`: nur punktuell dort gelesen, wo eine Anforderung dies erforderte (z. B. `PriceMatrixViewModel.cs` im BILL-Cluster); die überwiegende Mehrheit der >1.200 XAML-Views und zugehörigen ViewModels wurde nicht gesichtet.
- `Centron.BL/CentronIcons`: nur als Ausgangspunkt genannt, nicht inhaltlich vertieft.
- `Centron.DAO`, `Centron.Interfaces`, `Centron.Common`: nur indirekt über gezielte Grep-Suchen (z. B. nach Statusmaschinen/Constraints) einbezogen, nicht als eigenständiges Modul analysiert.
- Commit-Historie (52.135 Commits): nicht durchsucht, mit einer gezielten Ausnahme (Commit `baa9e7bd9b`, explizit im TIME-Cluster-Auftrag verankert und als Beleg in TIME-07 verwendet).
### 2.3 Nicht analysiert (keine eigene Betrachtung in dieser Iteration)
Business-Logic-Module ohne jede Betrachtung: `Accounts`, `ArtificialIntelligence`, `ChangeTracking`, `Chats`, `CheckListArea`, `Core` (BL-internes, nicht zu verwechseln mit `Centron.Core`), `CPra`, `Exceptions`, `ExpectedEvents`, `ExternalToolsBL`, `GUI`, `Helpers`, `IndexSearch`, `ItPlanner`, `MassUpdate`, `Mobile`, `MyCentron`, `Outlook` (BL-Anteil), `PasswordManagementArea/PasswordManagementKeywordBL` (nur namentlich als Legacy-Verdacht erwähnt, nicht im Detail gelesen — siehe SwRS-SEC-06), `Processes`, `Resources`, `RiverDivo`, `SelfCare`, `Services`, `SocialMedia`, `Statistics`, `Storage`, `Tags`, `Telemetry` (nur indirekt über SyRS-ARCH-13 gestreift), `ToDoArea`, `Tools`, `Transactions`, `Urls`, `VideoPortal`, `WebLinks`, `WebSuite`, `WebVersion`.
Weitere nicht analysierte Bereiche: `src/shared/Centron.Controls`, `src/shared/Centron.Controls.Preview`, `src/centron/Centron.WPF.UI.Extension`, `azure/`, `azure-blazor/`, `deployment/`, `docker/`, `scripts/`, `nugets/`, `tests/*` (alle Testprojekte — hier hätten Testfälle als zusätzliche, oft sehr präzise Belege für Geschäftsregeln dienen können, wurden aber aus Zeitgründen nicht herangezogen).
**Konkrete Lücke mit Auftragsbezug:** Der Auftrag verlangt explizit, Betriebs-/Sicherheitsanforderungen "gezielt auch aus indirekt sichtbaren Artefakten" wie Deployment-Skripten und Logging-Policies abzuleiten. Die Verzeichnisse `deployment/`, `docker/` und `azure/` (CI/CD-Pipelines) wurden in dieser Iteration nicht geöffnet — das ist die größte bekannte Abdeckungslücke gegenüber dem Auftrag und sollte in einer Folge-Iteration priorisiert werden (siehe Abschnitt 5).
## 3. Konsistenzcheck (mechanisch durchgeführt und iterativ korrigiert)
Nach Zusammenführung der elf Cluster wurde ein automatisierter Konsistenzcheck über den gesamten Anforderungsbestand (StRS.md, SyRS.md, SwRS.md, Traceability.md, Hypothesen.md) durchgeführt:
1. **Doppelte oder mehrfach vergebene IDs:** keine gefunden (325 Anforderungen, 325 eindeutige IDs; das cluster-präfigierte Schema `<Ebene>-<CLUSTER>-<Nr>` garantiert Eindeutigkeit ohne zentrale Koordination).
2. **Anforderungen ohne Beleg:** keine gefunden — jede der 325 Anforderungen enthält mindestens eine `Belege:`-Zeile mit PRIMÄR/SEKUNDÄR/KONTEXT-Klassifikation.
3. **Tracelinks auf nicht existierende IDs:** keine gefunden — alle in `Tracelinks:`-Feldern, in der Traceability-Tabelle und in `Konsolidierung:`-Feldern referenzierten IDs sind im Bestand definiert (automatisierter Soll-/Ist-Abgleich über alle 325 IDs).
4. **Risikobasierte Evidenzregel (Sicherheits-, Abrechnungs-, Berechtigungsanforderungen benötigen mindestens einen PRIMÄR-Beleg, sonst zwingend `HYPOTHESE`):** Bei der ersten Zusammenführung wurden **4 Verstöße** gefunden — die Anforderungen `SyRS-BILL-10`, `SyRS-BILL-17`, `SwRS-BILL-03` und `SwRS-BILL-05` trugen den Status `belegt`, obwohl nur ein `SEKUNDÄR`-Beleg (Dokumentation, nicht im Quellcode gegengelesen) vorlag. Diese wurden im Rahmen dieses Berichts korrigiert: Status auf `HYPOTHESE` mit Begründung geändert und in `Hypothesen.md` nachgetragen. Nach der Korrektur bestehen keine offenen Verstöße gegen diese Regel (verifiziert für alle Anforderungen mit `Typ: Sicherheit` sowie für die Cluster SEC und BILL).
5. **Vollständigkeit der Hypothesen-Sammlung:** Es wurde zusätzlich geprüft, ob alle Anforderungen mit dem Wortbestandteil `HYPOTHESE` im Status-Feld auch in `Hypothesen.md` erscheinen. Ursprünglich fehlten 21 Anforderungen, die zwar insgesamt als `belegt` eingestuft waren, aber eine eingebettete `[HYPOTHESE]`-Markierung zu einem Detailaspekt trugen (uneinheitliche Notation zwischen den Clustern ARCH/INT/SEC/CRM einerseits, die diese Nuance nutzten, und den übrigen Clustern andererseits, die nur strikt "Status = HYPOTHESE" exportierten). Diese wurden ergänzt (Abschnitt "Eingebettete Teilhypothesen" in `Hypothesen.md`). `Hypothesen.md` referenziert nun alle 54 Anforderungen mit Status-Wort `HYPOTHESE` plus 2 vom SALES-Cluster nachrichtlich (nicht Status-bildend) gemeldete Anforderungen.
## 4. Cluster-übergreifende Konsolidierungskandidaten
Die Konsolidierungshinweise innerhalb der einzelnen Anforderungen (`Konsolidierung:`-Feld) wurden von den Cluster-Durchgängen ausschließlich **innerhalb** des jeweiligen Clusters vergeben, da zum Zeitpunkt der Cluster-Analyse keine Sicht auf die anderen Cluster bestand. Bei der Zusammenführung wurden folgende **cluster-übergreifende** Konsolidierungskandidaten identifiziert (Betriebsbegriffe, die in mehreren Clustern unabhängig voneinander als eigenständige fachliche Regel dokumentiert wurden):
- **Belegstatus-Automat (ReceiptState: Active/Completed/Canceled):** unabhängig in BILL (`SyRS-BILL-01`, `SyRS-BILL-04`) und SALES (`SyRS-SALES-01`, `SyRS-SALES-10`, `SwRS-SALES-01`, `SwRS-SALES-02`, `SwRS-SALES-05`, `SwRS-SALES-10`) als dieselbe zugrunde liegende Statusmaschine des Beleg-Frameworks (`IReceiptBase`/`ReceiptBL`) beschrieben. Kandidat für eine gemeinsame SwRS-Anforderung "Belegstatus-Automat" im Zielsystem statt getrennter Beschreibung je Modul.
- **E-Rechnungsformate (ZUGFeRD/XRechnung):** in drei Clustern parallel behandelt — BILL (Kernlogik, `SyRS-BILL-06/09/10/17/19`, `StRS-BILL-01`), DOC (PDF/A-3-Erzeugung und Archivierung, `SwRS-DOC-06`, `SyRS-DOC-05/06`) und INT (als Schnittstellenformat im Kontext von ebInterface/EDI, `StRS-INT-01`, `SwRS-INT-07`). Für die Zielarchitektur sollte eine einzige, modulübergreifende "E-Invoicing"-Fähigkeit spezifiziert werden statt einer Aufteilung nach technischer Zuständigkeit (Fakturierung vs. Dokumentenerzeugung vs. Schnittstelle).
- **Mahnwesen/Belegsperre (Mahnstufe/Dunning Level):** unabhängig in BILL (`StRS-BILL-03`, `SwRS-BILL-01`, `SyRS-BILL-16`) und SALES (`SyRS-SALES-16`) sowie am Rande in DOC (`SwRS-DOC-09`, Sperre von Mahnschreiben-Reports) beschrieben. Sollte im Zielsystem als eine zentrale Regel (Kunde gesperrt ab Mahnstufe X → wirkt auf alle Belegarten) konsolidiert werden, statt separat für Vertrieb und Abrechnung geführt zu werden.
- **Kunden-/externer Portal-Login (WebAccount):** in vier Clustern beschrieben — ARCH (Architekturüberblick, `SyRS-ARCH-02/16`), SEC (Authentifizierungsregeln, `SwRS-SEC-03/04`, `SyRS-SEC-03/04/13/16`), CRM (Stammdatenbezug, `SyRS-CRM-05`) und NEX (Kundenportal-Nutzung, `StRS-NEX-01/04`, `SyRS-NEX-08/10`). Ergänzend beschreibt SALES ein davon unabhängiges, eigenständiges `TradeCustomerLogin`-Verfahren für den Handelswaren-Bereich (`SyRS-SALES-14`, als Hypothese markiert, ob dies ein bewusst getrenntes Legacy-System ist). Für die Neuimplementierung ist zu klären, ob ein einheitliches externes Identitätsmodell alle vier/fünf Ausprägungen ablösen soll.
- **Timer-Abrechnung als Spezialfall der Belegerzeugung:** TIME (`StRS-TIME-01`, `SyRS-TIME-04/06`, `SwRS-TIME-08`, über `ReceiptItemTimerBL`) erzeugt Positionen in denselben Belegarten (Auftrag/Lieferschein/Rechnung), die auch in BILL/SALES beschrieben werden. Die Timer-Abrechnung sollte im Zielsystem als ein spezifischer Positions-Erzeugungspfad in die gemeinsame Belegarchitektur eingeordnet werden, nicht als eigenständiger Abrechnungsweg.
- **I3D-Primärschlüsselkonvention:** als technisches Datenmodell-Muster in praktisch jedem Cluster referenziert (siehe Glossar) — kein fachlicher Konsolidierungsbedarf, aber ein deutlicher Hinweis, dass die Neuimplementierung durchgängig von diesem Legacy-Namensmuster wegmigrieren sollte (technische Migrationsanmerkung, kein Requirement-Duplikat).
Diese cluster-übergreifenden Kandidaten sind zusätzlich zu den in den einzelnen Anforderungen dokumentierten intra-cluster-`Konsolidierung:`-Feldern zu verstehen; sie wurden nicht in die einzelnen Requirement-Blöcke zurückgeschrieben, um Nacharbeiten durch die Fachvalidierung (Schritt 7) nicht vorwegzunehmen.
## 5. Zentrale inhaltliche Befunde (Auswahl, priorisiert nach Risiko)
Diese Befunde stammen aus den Cluster-Analysen und werden hier gebündelt hervorgehoben, da sie unmittelbaren Handlungsbedarf für die Zielarchitektur signalisieren:
- **Passwort-Hashing ohne Salt (SHA1):** Im Login-Code der internen Benutzerverwaltung (`AppUser`/`Sichbenu`) wird ein Salt-Mechanismus nicht konsequent genutzt; SHA1 gilt für Passwort-Speicherung als veraltet (siehe SwRS-SEC-03, Cluster SEC, PRIMÄR belegt inkl. Code-TODO-Kommentar).
- **Klartext-Passwortversand per E-Mail** bei Neuanlage von Web-Accounts (Cluster SEC).
- **Kein erkennbarer Kontosperrmechanismus** nach fehlgeschlagenen Login-Versuchen (Cluster SEC, als `SyRS-SEC-16` mit Status HYPOTHESE dokumentiert, da nicht auszuschließen ist, dass dies auf Infrastrukturebene abgedeckt wird).
- **Hartkodierte Zugangsdaten/Tokens** bei mindestens zwei Drittanbieter-Integrationen (GLS, ITScope) sowie **deaktivierte TLS-Zertifikatsprüfung** bei einer FTPS-Verbindung (`SwRS-INT-01`, als HYPOTHESE markiert, da die Begründung im Code fehlt) — Cluster INT.
- **Clientseitige statt serverseitige Validierung von Aktionspreisen** (`BILL-24`-Rohbefund, in SwRS-BILL-03 als HYPOTHESE aufgrund fehlenden PRIMÄR-Belegs geführt, aber unabhängig davon als Architekturrisiko dokumentiert): Preisintegrität ist im aktuellen System nicht serverseitig erzwungen.
- **Begriffsverwirrung "DocuBoard"/"docuFORM":** Beide Namen legen eine Dokumentenverwaltungsfunktion nahe, bezeichnen im Code aber IT-Asset- bzw. Drucker-Fleet-Management. Für die Zielarchitektur ist dies vor allem als Hinweis auf irreführende Modulbenennung relevant, nicht als fachliche Anforderung selbst (Cluster DOC).
## 6. Selbstbewertung
**Vollständig analysierte Module:** siehe Abschnitt 2.1 — ca. 50 von ca. 90 Business-Logic-Modulen sowie die wichtigsten Integrationsprojekte und die gesamte technische Dokumentation unter `docs/`.
**Nur stichprobenhaft analysierte Bereiche:** siehe Abschnitt 2.2 — insbesondere die WPF-UI-Schicht (Views/ViewModels) wurde nur dort vertieft, wo eine konkrete Anforderung dies erforderte; die überwiegende Mehrheit der über 1.200 XAML-Views wurde nicht gesichtet. Auch die Datenzugriffsschicht (`Centron.DAO`) wurde nur über gezielte Stichproben statt vollständig durchsucht.
**Nicht analysierte Module:** siehe Abschnitt 2.3 — rund 35–40 Business-Logic-Module (u. a. `ArtificialIntelligence`, `SocialMedia`, `VideoPortal`, `SelfCare`, `MyCentron`, `WebSuite`, `Mobile`, `Statistics`, `Storage`) sowie alle Deployment-/CI-CD-Artefakte (`deployment/`, `docker/`, `azure/`) und alle Testprojekte (`tests/*`).
**Stellen mit dünner Beleglage** (hoher Anteil SEKUNDÄR/KONTEXT oder HYPOTHESE):
- Cluster **INT** (Integrationen): mehrere Sicherheits-relevante Befunde (Zertifikatsprüfung, Schlüsselmanagement) sind nur über Code-Kommentare oder Konfigurationswerte, nicht über eine explizite Dokumentation der Absicht belegt.
- Cluster **ARCH**: mehrere Referenzdokumente (`mvvm-in-centron.md`, `requests-and-responses.md`) waren leer oder unvollständig, sodass zentrale Architekturmuster aus Namenskonventionen und Nachbardokumenten rekonstruiert werden mussten (siehe embedded Hypotheses zu SwRS-ARCH-04/05).
- Cluster **BILL**: 4 von 30 Anforderungen (13 %) mussten wegen fehlendem PRIMÄR-Beleg nachträglich auf HYPOTHESE korrigiert werden (Abschnitt 3, Punkt 4) — deutet darauf hin, dass die ZUGFeRD-Feldzuordnungsdokumentation zwar inhaltlich sehr detailliert, aber nicht durchgängig mit dem tatsächlichen Quellcode gegengelesen wurde.
- Cluster **CRM**: mit 7 von 28 Anforderungen (25 %) der höchste Hypothesen-Anteil — v. a. offene Fragen zu Dubletten-Erkennung, Nebenläufigkeitssicherheit der Kundennummernvergabe und uneinheitlicher USt-IdNr.-Führung.
- Cluster **NEX**: ebenfalls hoher Hypothesen-Anteil (7 von 25) — CentronNexus als separate Web-/Blazor-Anwendung wurde primär über die Backend-Anbindung (`Centron.BL`), weniger über den eigentlichen Frontend-Code analysiert.
**Empfehlungen für eine Folge-Iteration:**
1. **Deployment-/Betriebsartefakte nachholen** (`deployment/`, `docker/`, `azure/`) — bislang komplett unanalysiert, obwohl der Auftrag ausdrücklich Betriebs- und Sicherheitsanforderungen aus solchen Artefakten fordert.
2. **WPF-UI-Schicht (Views/ViewModels) gezielt vertiefen**, insbesondere dort, wo SwRS-Anforderungen bislang nur auf BL-Ebene belegt sind, UI-seitige Validierung aber ggf. abweicht (Konsistenz Client-/Serverprüfung, vgl. Befund zu Aktionspreisen).
3. **Die 4 auf HYPOTHESE korrigierten BILL-Anforderungen sowie alle als "eingebettete Teilhypothese" markierten Punkte** gezielt im Quellcode nachverifizieren, bevor sie als Migrationsgrundlage dienen.
4. **Bislang nicht analysierte Module mit vermutetem Sicherheits-/Compliance-Bezug priorisieren**, insbesondere `ArtificialIntelligence` (KI-Funktionen, Datenschutzrelevanz), `SelfCare`/`MyCentron` (weitere Kundenportal-Varianten neben WebAccount) und `Mobile`.
5. **Testprojekte (`tests/*`) als zusätzliche Beleg-/Validierungsquelle heranziehen** — Testfälle enthalten häufig präzise, ausführbare Beschreibungen von Geschäftsregeln und könnten insbesondere HYPOTHESE-Einträge in PRIMÄR-belegte Anforderungen umwandeln.
6. **Cluster-übergreifende Konsolidierung vertiefen** (Abschnitt 4) — die dort identifizierten fünf Kandidaten sollten in einer Folge-Iteration in konkrete, zusammengeführte Ziel-Anforderungen überführt werden, statt (wie hier) nur als Hinweis dokumentiert zu sein.
@@ -0,0 +1,151 @@
# Glossar — CentronERP
Domänenbegriffe, die in den Anforderungen von StRS/SyRS/SwRS verwendet werden. Zusammengeführt aus den elf Analyseclustern (Kürzel in Klammern = Cluster, in dem der Begriff zuerst/hauptsächlich verwendet wird; ein Begriff kann in mehreren Clustern relevant sein). Bei mehrfach vorkommenden Begriffen mit unterschiedlicher Nuance ist dies vermerkt; bei zwei fachlich unterschiedlichen Konzepten mit gleichlautendem deutschem Begriff sind beide getrennt aufgeführt.
- **Abschlussgrund (Complete Reason)** (SALES): Stammdatensatz, der beim Schließen eines Angebots den Grund für dessen Abschluss (z. B. Nichtzustandekommen) dokumentiert.
- **AccountDevice** (LOG): Im System verwaltetes Kundengerät (Hardware-Asset beim Kunden), u. a. mit Support-Tickets verknüpft, per Soft-Delete verwaltet.
- **Adviser1I3D…Adviser6I3D ("Betreuer")** (CRM): Kundenbezogene Zuordnung mehrerer Mitarbeiterrollen (Innendienst, Außendienst, Techniker 1/2, zwei weitere unbenannte Rollen).
- **AESCryptoLogic** (SEC): AES-basierte Verschlüsselungskomponente für schützenswerte Zugangsdaten im aktiven Passwort-Manager-Modul (`PasswordManagerBL`).
- **Aktionspreis (ActionPrice)** (BILL): Zeitlich befristeter Sonderpreis eines Herstellers/Distributors für einen Artikel, angezeigt in der Preismatrix im Gültigkeitszeitraum.
- **AnlageLog** (BILL): Zentrale, belegtypübergreifende Protokolltabelle für Audit-Log-Einträge (Erstellung, Änderung, Abrechnung, Kündigung etc.), referenziert Belege über `AnlageI3D`+`AnlageArt`.
- **Angebot (Offer)** (SALES): Unverbindliches Vertriebsdokument, Startpunkt der Belegkette; kann in Auftrag, Lieferschein oder Rechnung weitergeleitet werden.
- **Anrede/Abrede** (DOC): Textbausteine am Anfang ("Anrede", z. B. Begrüßung) bzw. Ende ("Abrede", z. B. Grußformel/AGB-Hinweis) eines Belegs oder einer Mail.
- **Anzahlungsrechnung (Down Payment Invoice)** (SALES): Aus einem Auftrag erzeugte, mit diesem referenziell verknüpfte Rechnung über eine Vorauszahlung.
- **AppGroup / Sichrech / Sichtrus / Sichmemb** (SEC): Rechte-Datenmodell — `Sichrech` = Rechte-Katalog, `Sichmemb` = Zuordnung Benutzer↔Gruppe, `Sichtrus` = Zuordnung Gruppe↔Recht, `AppGroup` = objektorientiertes Pendant zur Gruppen-Entität.
- **ApplicationKind** (ARCH, SEC): Katalog aller Client-Anwendungen, die sich am c-entron-Web-Service anmelden dürfen (z. B. c-entron.NET, Service-Board, WebCart), mit zugehöriger Lizenz-GUID, Ablaufverhalten und optional einem erforderlichen/ausschließenden Recht.
- **ApplicationSettings vs. Stammdat** (ADM): Zwei parallel existierende DB-Ablagen für Systemeinstellungen — `Stammdat` (historisch, Zugriff über `AppSettingsConst`) vs. `ApplicationSettings` (aktuell, Zugriff über `ApplicationSettingID`).
- **AppointmentRequest (Terminanfrage)** (TIME): An einen Kunden versendeter Vorschlag mehrerer möglicher Termine; Rückmeldung wird über Microsoft Exchange verarbeitet.
- **AppUser (Sichbenu)** (SEC): Interner c-entron-Mitarbeiterbenutzer, gespeichert in Tabelle `Sichbenu`; eigenes Passwortfeld, Aktivierungsstatus, Verknüpfung zu `Employee`. Abzugrenzen von `Employee` (Personal-Stammdaten der Person selbst) — beide führen eigene, nicht deckungsgleiche "aktiv"-Konzepte (CRM).
- **Auftrag (Order)** (SALES): Verbindlicher Kundenbeleg, entsteht ausschließlich aus einem Angebot; kann in Lieferschein, Rechnung oder Vertrag weitergeleitet werden.
- **Barcode / Seriennummer** (LOG): Synonym verwendete Begriffe für ein einzeln identifizierbares Exemplar eines Artikels, verfolgt über einen eigenen Zustandsautomat (`BarcodeState`).
- **Beleg (Receipt)** (SALES, TIME, BILL): Sammelbegriff für alle im System verwalteten Geschäftsdokumente (Angebot, Auftrag, Lieferschein, Rechnung, Gutschrift, Abholliste, Vertrag, Bestellung, Wareneingang etc.), abgebildet über ein gemeinsames polymorphes Framework (`IReceiptBase`, `ReceiptBL`); im Zeiterfassungskontext insbesondere die Zielbelege der Timer-Abrechnung (Auftrag, Lieferschein, Rechnung).
- **Belegnummernkreis (NumberGroup)** (BILL): Konfigurierbarer, meist mandantenweiter Zähler zur eindeutigen, race-condition-sicheren Vergabe von Belegnummern (Rechnungen, Verträge etc.).
- **Bestellung (SupplierOrder)** (SALES): Einkaufsseitiger Beleg an einen Lieferanten; kann ausschließlich in einen Wareneingang (SupplierDeliveryList) weitergeleitet werden.
- **Bestellvorschlagsliste (BVL, OrderSuggestionList)** (SALES): Zentrales Einkaufswerkzeug, das offenen Bedarf aus Artikeln, Aufträgen und Lagerbeständen konsolidiert zur Bestellauslösung an Lieferanten vorschlägt.
- **BillingStateI3D** (TIME): Feld an der Ticketzeit, das den Abrechnungszustand referenziert (z. B. offen/reserviert/nicht abrechnen).
- **Calculable (Abrechenbarkeit)** (TIME): Boolesches Flag an einer Ticketzeit, das angibt, ob die Zeit grundsätzlich in Rechnung gestellt werden darf.
- **CentronModuleCategory** (ARCH): Enum zur fachlichen Gruppierung aller registrierten Module (z. B. Sales, Ticket, Billing, Administration); verwandtes Konzept zur "Modulkategorie" (ADM) für die UI-Gruppierung.
- **CentronWebserviceMailType** (ADM): Zentrale Einstellung, die das E-Mail-Transportprotokoll (SMTP, Exchange/EWS oder Microsoft Graph) für den serverseitigen Mailversand festlegt.
- **ContractArticleReferenzes** (BILL): Verknüpfungsentität zwischen einem Vertragsartikel und den zugehörigen RMM-Abrechnungsregeln (Kontingentmenge, Über-/Unterbuchungsdeckelung).
- **COP** (INT): Externer Produktdatendienst, der über eine SOAP-Schnittstelle Artikeldaten, verwandte Produkte und Lieferantenzuordnungen bereitstellt.
- **CrmProject** (TIME): Vertriebsprojekt (Kundenprojekt) mit Umsatz-/Margenprognose, Beratern und Entscheidungsdatum, losgelöst von der reinen Ticketbearbeitung.
- **Direktlieferung — zwei unterschiedliche Bedeutungen:**
- *Auftragsmerkmal* (`IsDirectDelivery`, LOG): kennzeichnet eine direkte Lieferung ohne Zwischenlagerung/Standardkommissionierung und beeinflusst z. B. den Versand von Kommissionierungs-E-Mails.
- *Streckengeschäft* (SALES): Beschaffungsvariante, bei der eine Lieferantenbestellung direkt für einen konkreten Kundenauftrag ausgelöst wird, ohne über das eigene Lager zu laufen; Liefertermine werden zwischen Bestellung und Auftrag synchronisiert.
- **DMS-Sync** (DOC): Kennzeichnung, ob/wann ein `Document` in ein externes Dokumentenmanagementsystem synchronisiert wurde (Felder `DMSSyncUniqueID`, `DMSSyncDate`, `DMSSyncType`, `DMSSyncEmployeeI3D`).
- **DocBee** (TIME): Externes mobiles Zeiterfassungssystem, das Zeitbuchungen über eine definierte Schnittstelle an CentronERP übermittelt.
- **docuFORM** (DOC): Name eines externen Drittsystems für Multifunktionsdrucker-Fleet-Management (Geräte, Zählerstände), angebunden über `Centron.Api.docuFORM` per REST/OAuth2 — **nicht** zu verwechseln mit Dokumentgenerierung.
- **DocuBoard** (DOC): Namespace/Ordnername im Quellcode (`Centron.BL/DocuBoard`), der entgegen der Erwartung **kein** Dokumentenmodul bezeichnet, sondern IT-Asset-/Gerätemanagement (Partner, Artikelzuordnung, AD-Systembenutzer-Ausschluss). Die eigentliche Dokumentenverwaltung liegt unter `Administration/FileManagement`.
- **Domain-Blacklist** (ADM): Liste gesperrter Empfänger-Domains/-Muster, gegen die jede Ziel-E-Mail-Adresse vor dem Versand geprüft wird.
- **Dongle-ID** (ARCH): Aus der Lizenz abgeleitete Kundennummer, u. a. zur Identifikation einer c-entron-Installation in Analytics/Telemetrie.
- **DSGVO-Löschung (Anonymisierung)** (CRM): Prozess, bei dem personenbezogene Daten einer Kontaktperson auf Anfrage entfernt/überschrieben werden, ohne den Datensatz technisch vollständig zu löschen (Soft-Anonymisierung mit Audit-Trail).
- **DueDateDelayInHours** (NEX): Prioritätsabhängige Vorlaufzeit (Stunden) zur automatischen Berechnung des Fälligkeitsdatums eines Tickets.
- **EDI (Electronic Data Interchange)** (INT, SALES): Automatisierter, strukturierter elektronischer Austausch von Geschäftsdokumenten (Bestellung, Auftragsbestätigung, Lieferschein, Rechnung) zwischen Handelspartnern ohne manuelle Neuerfassung; im Einkauf u. a. für automatisiert eingespielte Auftragsbestätigungen genutzt.
- **EGIS** (INT): Elektronische Bestell-/Rechnungsaustauschplattform für die IT-Distribution, angebunden über XML-basierte HTTP-Requests.
- **EscalationLevel** (NEX): Numerisches Feld am Ticket, das die zuletzt erreichte Eskalationsstufe (0–3) speichert.
- **ESR/QR-Referenz** (ADM): Schweizer Zahlungsreferenzverfahren (Einzahlungsschein mit Referenznummer bzw. QR-Rechnung); je Mandant eines von bis zu vier Bankkonten als aktives Referenzkonto wählbar.
- **Fertigungsauftrag (ArticleProductionOrder)** (LOG): Konkreter, ausführbarer Auftrag zur Produktion einer Artikelmenge auf Basis einer Stückliste und definierter Fertigungsschritte.
- **Festschreibung (IsFixed)** (BILL): Zustand einer Rechnung, ab dem inhaltliche Änderungen softwareseitig gesperrt sind (typischerweise nach Buchung/Export).
- **Filiale (Branch)** (ARCH): Niederlassung eines Mandanten mit eigenen Nummernkreisen und rechtebasierten Einschränkungen (z. B. Recht "nur eigene Filiale"); genaue Abgrenzung zu "Mandant" laut Recherche nicht abschließend geklärt.
- **Freigabewesen — zwei unterschiedliche Bedeutungen:**
- *Cart-Release-Workflow* (SALES): mehrstufiger Genehmigungsprozess für Web-Warenkörbe mit Rollen Ersteller, Prüfer ("Checker"), Besteller ("Orderer") und Zuständen Created → ReadyForCheck → Checked/DeclinedByChecker → Ordered/DeclinedByOrderer.
- *CustomerApprovalEnabledSBO* (NEX): kundenspezifische Einstellung, ob von Kunden über das Portal erstellte Tickets vor Sichtbarkeit für den Support intern freigegeben werden müssen.
- **FTP/FTPS/SFTP** (INT): Drei Dateiübertragungsprotokolle für den EDI-Dateiaustausch mit Lieferanten — FTP unverschlüsselt, FTPS mit TLS auf FTP-Basis, SFTP eigenständig SSH-basiert verschlüsselt.
- **GfK** (INT): Marktforschungsinstitut, an das aufbereitete Verkaufs-/Bestandsdaten zur Branchenauswertung (Sell-out-Reporting) übermittelt werden.
- **Group Setting Class** (ADM): Serverseitige Business-Logic-Klasse, die mehrere fachlich zusammengehörige Einstellungen lädt, typisiert kapselt (DTO) und über eine dedizierte API bereitstellt, statt direkten Tabellenzugriff zu erlauben.
- **Handelsware / Warenpool (TradePool)** (SALES): Separater, über XML-Importe gespeister externer Artikelpool für Handelsware, unabhängig vom internen Artikelstamm, mit eigenem Kundenlogin-System.
- **Hauptlager** (LOG): Zentrales, immer implizit vorhandenes Standardlager eines Mandanten (technisch häufig `I3D = -1`), abgegrenzt von benannten Nebenlagern.
- **HelpdeskCreationTemplate** (NEX): Speicherbare Voreinstellung für die automatische Ticketerstellung aus Bestellpositionen (nicht identisch mit TicketPattern).
- **HelpdeskEditor** (NEX): Zuordnungsentität zwischen einem Ticket (Helpdesk) und einem Mitarbeiter als Bearbeiter.
- **HelpdeskState (Ticketstatus)** (NEX, TIME): Konfigurierbare Lookup-Entität für Ticket-Status (kein fester Enum); Administratoren können Status anlegen, deaktivieren und einen als "geschlossen" markieren — "geschlossen" ist also keine feste Codierung, sondern eine Einstellung.
- **Hotline-Masterkey** (ADM): Zentral hinterlegtes, separat verwaltetes kryptografisches Geheimnis, mit dem weitere sensible Zugangsdaten (z. B. MailScanner-Postfachpasswörter, OAuth-Client-Secrets) zusätzlich AES-verschlüsselt werden; ohne Masterkey keine Ver-/Entschlüsselung möglich.
- **I3D**: Durchgängig in der CentronERP-Codebasis und -Datenbank verwendete Bezeichnung für den Primärschlüssel (technische ID) einer Entität; funktionales Pendant zu einer generischen "Id"-Spalte, teils auch fachlich sichtbar (z. B. `CustomerNumber = I3D`).
- **Icecat** (INT): Herstellerunabhängige, mehrsprachige Produktdatenbank (Datenblätter, Beschreibungen, Bilder), abgefragt per EAN oder Hersteller-Produkt-ID.
- **Inventur (Stocktaking)** (LOG): Geschäftsvorgang zur Zählung und zum Abgleich des tatsächlichen mit dem gebuchten Lagerbestand, mit eigenem Zustandsautomat (offen/geschlossen/gelöscht, mit/ohne Seriennummernpflicht).
- **IsOnlyInternalVisible** (NEX): Ticket-Flag, das ein Ticket vollständig vor Kunden-Logins verbirgt, unabhängig vom sonstigen Rechtelevel.
- **ITScope** (INT): IT-Beschaffungs-/Marktplatzplattform, über die Bestellungen an mehrere Distributoren gebündelt sowie Produktdaten und Kontingent-Informationen (Quota) abgerufen werden.
- **Kommissionierung** (LOG): Prozess der Zusammenstellung der für einen Auftrag benötigten Artikel/Seriennummern aus dem Lagerbestand vor der Lieferung.
- **Kontingent (Vertrag)** (BILL): Im Wartungs-/Servicevertrag vereinbartes Leistungs- oder Geldvolumen, das über die Vertragslaufzeit durch Rechnungen verbraucht und durch Gutschriften wieder freigegeben wird.
- **Kreditlimit (CreditLimit)** (SALES): Der einem Kunden zugewiesene maximale offene Forderungsbetrag; bei Überschreitung durch einen neuen Beleg wird ein Bestätigungsdialog ausgelöst.
- **Kundenherkunft (CustomerAncestry)** (CRM): Stammdaten-Klassifikationswert, der die Herkunft/Quelle eines Kunden beschreibt (z. B. Akquisekanal); referenziert über `Customer.CustomerOriginI3D`.
- **Leitweg-ID** (BILL): Adressierungs-/Routing-Code für öffentliche Auftraggeber in Deutschland, identifiziert die empfangende Behörde in einer XRechnung.
- **LicenseGuids / LicenseManager** (ARCH, SEC): Zentrale Liste GUID-basierter Lizenzmerkmale (Anwendungen und einzelne Features); `LicenseManager.Instance.HasLicense(...)` prüft, ob eine GUID für den aktuellen Mandanten freigeschaltet ist.
- **Lizenzmodul (ProductionManagement)** (LOG): Separat lizenzierbare Funktionsgruppe für Produktionsmanagement (Maschinen, Stücklisten, Fertigungsaufträge); ohne gültige Lizenz gesperrt/eingeschränkt.
- **LogKind** (ADM): Statuswert einer Systembenachrichtigung (Successful, PartlyError, Error), u. a. für Filterung und automatisierte Fehleranalyse.
- **Mahnstufe (Dunning Level)** (BILL, SALES): Eskalationsstufe (1–3) im Mahnwesen, an die Fristen, Gebühren und optionale Belegsperren gekoppelt sind; ab konfigurierbarem Schwellwert werden neue Belege für den betroffenen Kunden gesperrt.
- **MailScanner / Virtual Mail Assistant (VMA)** (ADM): Komponente zum automatisierten Abholen/Verarbeiten eingehender E-Mails aus konfigurierten Postfächern; Profilzugriff über Recht `ACCESS_VMA_MODULE` geschützt.
- **MailTemplateReference** (ADM): Eindeutige Kennzeichnung einer Mailvorlage über Kombination von ObjectKind, ObjectI3D, SubObjectKind und TemplatePrio.
- **Mandant** (ADM, ARCH, CRM): Eine in sich abgeschlossene Unternehmens-/Firmeneinheit innerhalb von CentronERP mit eigenen Stammdaten (Logos, Bankverbindungen, Standardland); genau ein Mandant ist als Standard-Mandant markiert. Die genaue Abgrenzung zu "Filiale" ist laut ARCH-Recherche nicht abschließend geklärt.
- **Matchcode** (CRM): Kurzbezeichnung/Suchbegriff eines Kunden, zusätzlich zum Namen für die Freitextsuche verwendet.
- **MEF (Managed Extensibility Framework)** (ARCH): .NET-Technologie zum dynamischen Laden von Plugin-Assemblies zur Laufzeit; Basis der c-entron "Extension Engine".
- **Mention-Syntax** (NEX): Im Kommentartext eingebettete Erwähnung eines Mitarbeiters im Format `[@Name:employeeI3D]`, löst eine gezielte Benachrichtigung aus.
- **Mindestbestand (Meldebestand)** (LOG): Je Artikel und Lager konfigurierbare Bestandsschwelle, deren Unterschreitung eine automatische Bestellvorschlagsgenerierung auslöst.
- **Mindestpreis (MinPrice)** (SALES): Je Artikel hinterlegter niedrigster zulässiger Verkaufsnettopreis; Unterschreitung erfordert besonderes Benutzerrecht oder Zweitfreigabe (Vier-Augen-Prinzip).
- **ModuleFeatures** (ARCH): Zentrale Klasse mit booleschen Feature-Flags, über die Module unabhängig vom Rechtesystem ein-/ausgeblendet werden können.
- **Modulkategorie** (ADM): Feste, lokalisierte Gruppierungsebene für Anwendungsmodule (z. B. "Vertrieb", "Abrechnung", "Administration") zur strukturierten Anzeige (u. a. Favoritenmenü); vgl. `CentronModuleCategory` (ARCH).
- **MyDay ("Mein Tag")** (TIME): Modul zur tagesbezogenen Arbeitszeit-/Aktivitätsübersicht eines Mitarbeiters, gespeist u. a. aus Ticketzeiten, Kalender und Telefonie.
- **MyDayWorkItem** (TIME): Einzelner Tageseintrag innerhalb von MyDay, z. B. ein aus einer Ticketzeit abgeleiteter Arbeitsblock.
- **Nebenlager (SecondaryStock)** (LOG): Zusätzliches, benanntes Lager (z. B. Filiallager, Technikerfahrzeug, Projektlager) neben dem Hauptlager, mit eigener Bestandsführung je Artikel (`SecondaryStockArticle`).
- **NeedsUserValidation** (INT): Datenbankflag an EDI-Belegköpfen; zeigt an, dass ein importierter Beleg vor endgültiger Übernahme noch manuell geprüft/zugeordnet werden muss.
- **NexusNotification** (NEX): Datensatz für eine Push-Benachrichtigung im CentronNexus-System (Empfänger, Typ, Bezugsticket, Text), verteilt über einen SignalR-artigen Hub (`NotificationsHubHelper`).
- **NexusTicketView** (NEX): Gespeicherte Filter-/Spaltenkonfiguration für die Ticketliste, persönlich oder global geteilt.
- **NonCalculableTimersHandling** (TIME): Konfigurationsoption, die steuert, ob nicht abrechenbare Ticketzeiten beim Belegerzeugen ausgelassen oder mit Preis 0 ausgewiesen werden.
- **NotificationUser** (ADM): Frei definierbarer Benachrichtigungsempfänger (nicht zwingend Systembenutzer) mit Name/Telefon/E-Mail, beliebigen Geschäftsobjekten zuordenbar.
- **ObjectExternalReference** (TIME): Generischer Verknüpfungsmechanismus zwischen einem CentronERP-Objekt (z. B. Ticket, Ticketzeit) und einer ID in einem externen System (z. B. DocBee).
- **OIDC / `oid`-Claim / OpenID Connect / Microsoft Entra ID** (ARCH, SEC): Standardprotokoll für föderierte Anmeldung; im ID-Token enthaltene eindeutige Objekt-ID des Benutzerkontos in Microsoft Entra ID, über die ein c-entron-Benutzerkonto mit dem externen Identitätsanbieter verknüpft wird — c-entron tauscht das Microsoft-ID-Token gegen ein eigenes Sitzungs-Ticket.
- **OpenTrans 2.1** (INT): Herstellerneutraler XML-Branchenstandard für elektronischen Geschäftsdokumentenaustausch im IT-/Bürobedarfshandel, u. a. von ALSO als Basis verwendet.
- **Pauschale / Ausgleichsartikel (Balance Item)** (SALES): Sammelposition (Flatrate) in einem Auftrag, gegen die einzelne Leistungen (z. B. Helpdeskzeiten) wertmäßig verrechnet werden.
- **PasswordManager vs. PasswordManagementArea** (SEC): Zwei unterschiedliche, nicht zu verwechselnde Module — `PasswordManagerBL` (Hotline-/Kundenzugangsdaten, aktiv genutzt, AES-verschlüsselt, lizenzpflichtig) und `PasswordManagementArea`/`PasswordManagementKeywordBL` (vermutlich veraltetes Altmodul ohne wirksame Verschlüsselung).
- **PDF/A-3b** (DOC): ISO-Standard zur Langzeitarchivierung von PDF-Dokumenten mit eingebetteten Dateianhängen (Voraussetzung für ZUGFeRD); erzwingt u. a. eingebettete Schriften.
- **Produktmatrix (ProductMatrix)** (SALES): Werkzeug zur strukturierten Bewertung der Relevanz von Produktkategorien/-produkten je Kunde (Cross-/Upselling-Steuerung) mit Änderungshistorie.
- **Provisionierung** (SALES): Automatisierte Zuordnung eines Provisionsempfängers (Kundenbetreuer) und -anteils zu einem neuen Auftrag anhand konfigurierbarer Regeln.
- **PSD2** (INT): EU-Zahlungsdiensterichtlinie, die u. a. den regulierten Zugriff von Drittanbietern auf Bankkonten mit Einwilligung des Kontoinhabers ermöglicht.
- **ReceiptState** (BILL, SALES): Einheitliche, belegtypübergreifende Statusmaschine mit den Werten Active ("offen"), Completed ("abgeschlossen") und Canceled ("storniert").
- **ReportGroup/ReportData** (DOC): Grundstruktur der FastReport-basierten Reporting-Engine — `ReportGroup` bündelt Reports eines Belegtyps, `ReportData` ist der einzelne Report (FastReport-Definition, Base64-serialisiert) mit Parametern und Abfragen.
- **Restricting Right (einschränkendes Recht)** (SEC): Sonderkategorie von Berechtigung, die eine bereits gewährte Sichtbarkeit zusätzlich einschränkt (z. B. "nur eigene Datensätze", "nur eigene Filiale"), statt zusätzliche Handlungen freizuschalten.
- **Reverse Charge** (BILL): Umkehr der Steuerschuldnerschaft auf den Leistungsempfänger gem. §13b UStG; Rechnung weist 0 % USt. mit Hinweistext aus.
- **RFID-Token** (CRM, LOG): Verschlüsselt gespeicherte Kennung eines physischen Transponders, einem Mitarbeiter zugeordnet — allgemein für Zutritts-/Zeiterfassung (CRM) bzw. speziell zur An-/Abmeldung an einer Maschine/einem Fertigungsschritt zur automatischen Arbeitszeiterfassung (LOG).
- **RMA-Lager** (LOG): Spezielle, meist prozessbedingt gesperrte Lager für den Retouren-/Reklamationsprozess (Kunden-, Eigen-, Versand- und Auftragslager), von regulärer Lagerauswahl und ggf. Inventur ausgeschlossen.
- **RMM (Remote Monitoring & Management)** (BILL): Externes System (in c-entron z. B. "Riverbird") zur Fernüberwachung von Kunden-IT-Infrastruktur, liefert Nutzungsdaten als Grundlage für nutzungsbasierte Vertragsabrechnung.
- **RTF (Rich Text Format)** (ADM): Internes Speicherformat für formatierten Text in Mailvorlagen und Signaturen; Klartext wird bei Bedarf automatisch in RTF konvertiert.
- **Schedule (Kalendertermin)** (TIME): Kalendereintrag, u. a. automatisch aus einer geplanten/gebuchten Ticketzeit erzeugt, mit Outlook/Exchange synchronisierbar.
- **ScanBarcode (Seriennummernpflicht, "SN-Pflicht")** (LOG): Artikel-Flag, das festlegt, ob ein Artikel über individuelle Seriennummern (Barcodes) einzeln nachverfolgt oder rein mengenbasiert geführt wird.
- **Sentinel-Datum (1900-01-01)** (CRM): Im Legacy-Datenmodell verwendeter technischer Ersatzwert für "kein Datum gesetzt" bei `LeavingDate`, anstelle von NULL.
- **SEPA-Mandatsreferenz** (BILL): Eindeutige Referenznummer eines SEPA-Lastschriftmandats, ermächtigt den Bankeinzug beim Kunden.
- **SEPA / PAIN.008** (INT): Single Euro Payments Area — einheitlicher europäischer Zahlungsverkehrsraum; PAIN.008 ist das ISO-20022-XML-Nachrichtenformat für SEPA-Lastschriften (banken-/länderspezifisch in mehreren Versionen, z. B. GBIC3/GBIC4).
- **ServiceBoard** (NEX): Web-basierte Ticket-/Kanban-Oberfläche von CentronNexus für Support-Mitarbeiter.
- **SHA1 / Salt** (SEC): SHA1 ist eine für Passwort-Speicherung als veraltet/schwach geltende Hash-Funktion; ein "Salt" ist ein zufälliger Zusatzwert vor dem Hashing gegen Rainbow-Table-Angriffe — im untersuchten Login-Code wird dieser Mechanismus nicht konsequent genutzt.
- **ShowHelpdeskRight** (NEX): Rechtestufen-Enum (None/OnlyOwn/OnlyOwnBranch/All), bestimmt den Sichtbarkeitsumfang von Tickets für einen Benutzer.
- **Soft-Delete** (LOG, DOC): Löschstrategie, bei der ein Datensatz nicht physisch entfernt, sondern nur als gelöscht markiert wird (`IsDeleted=true` bzw. entitätsspezifisches `State`-Flag), um Historie/Nachvollziehbarkeit zu erhalten (siehe auch **State-Flag**).
- **Sonderpreise** (ARCH): Im c-entron.NET-Adressstamm hinterlegte kundenspezifische Preise, die die im WebCart sichtbaren Artikel/Preise für den jeweiligen Web-Account bestimmen.
- **Standardadresse (DefaultCustomer) / DefaultCreditor** (CRM): Die als Vorgabe markierte Adresse eines Kunden (pro Kunde genau eine) bzw. analog die Standard-Lieferantenadresse bei Kreditoren.
- **State/Locked** (CRM): Zwei getrennte Felder zur Steuerung der Nutzbarkeit eines Kunden — `State` (aktiv/inaktiv als Ganzzahl) und `Locked` (Sperr-Flag); beide müssen für "aktiv nutzbar" positiv sein.
- **State-Flag** (DOC): Wiederkehrendes Muster in mehreren Entitäten (Documentation, TextModule, ReportData), bei dem ein Integer-Feld `State` (0/1) Aktivierung bzw. logisches Löschen (Soft-Delete) abbildet statt physischem Löschen.
- **Stückliste (BOM, `ArticleProductionMaterial`)** (LOG): Liste der für die Fertigung eines Artikels benötigten Materialkomponenten und Mengen.
- **Stundenzuschlag (HourlySurchargeRate)** (TIME): Prozentualer Auf-/Abschlag auf den Artikelpreis, abhängig von Wochentag, Uhrzeit oder Feiertag auf abgerechnete Zeiten angewendet.
- **SystemAuthenticationMethod** (ARCH): Systemweite Einstellung, die das primär zu verwendende Authentifizierungsverfahren (None/Basic/ActiveDirectory/OpenIdConnect) festlegt.
- **TAPI** (ARCH): Telephony API — Windows-Standardschnittstelle für Telefonie-Integration, hier über die modifizierte Drittanbieterkomponente TraySoft AddTAPI.NET genutzt.
- **TaskManagementTask** (TIME): Wiederkehrende, automatisiert ausgeführte Aufgabe (z. B. automatische Ticketerstellung oder Report-Versand) mit konfigurierbarem Wiederholungsrhythmus.
- **Teil-Kommissionierung (PartialCommissionOrder)** (LOG): Kommissionierungssatz, der nur einen Teil der Positionen/Mengen eines Auftrags abdeckt, mit eigenem Fortschrittsstatus (unvollständig/vollständig/teilweise/geliefert).
- **Textbaustein (TextModule)** (DOC): Konfigurierbarer, wiederverwendbarer Textabschnitt (Anrede/Abrede/Prozesstext) mit Platzhaltern, kunden-, benutzer- oder global-spezifisch hinterlegbar.
- **Ticket — zwei unterschiedliche Bedeutungen:**
- *Sitzungs-Ticket* (ARCH, SEC): serverseitig ausgestellter, zeitlich begrenzter Authentifizierungs-Token (Plain-Text-String, hier 30 Minuten gültig) nach erfolgreichem Login, dient bei jedem API-Aufruf als Authentifizierungsnachweis.
- *Helpdesk-/Support-Ticket* (NEX, TIME): fachlicher Vorgang im Ticket-/Helpdesksystem, Basis der Ticketzeiterfassung und Kundenkommunikation.
- **TicketPattern** (NEX): Vordefinierte Vorlage zur Ticketerstellung mit vorbelegten Feldern (Typ, Kategorie, Beschreibung, Abteilung etc.).
- **TicketProject** (TIME): Projekt-Objekt, das mehrere Tickets/Aufgaben bündelt und mit eigenem Status, Terminplan und Fortschritt geführt wird.
- **TicketProjectDependency** (TIME): Abhängigkeitsbeziehung zwischen zwei Objekten eines Ticketprojekts nach dem Gantt-Prinzip (z. B. Ende-Anfang).
- **Ticketzeit / HelpdeskTimer** (TIME): Auf einem Ticket erfasster Zeiteintrag eines Mitarbeiters mit Start-, Stopp- und Pausenzeit, Basis der späteren Abrechnung.
- **Timer-Abrechnung (TimerBilling)** (TIME): Vorgang, bei dem erfasste Ticketzeiten gebündelt in Positionen eines Auftrags, Lieferscheins oder einer Rechnung überführt werden.
- **Titelposition** (BILL): Gruppierende Rechnungsposition, die mehrere untergeordnete Artikelpositionen zusammenfasst; kann beim E-Rechnungsexport nur eingeklappt (aggregiert) exportiert werden.
- **USt-IdNr. (Umsatzsteuer-Identifikationsnummer)** (CRM): Steuerliche Kennung eines Geschäftspartners für innergemeinschaftliche Geschäfte; im System an mehreren Stellen redundant geführt.
- **Vier-Augen-Prinzip** (SALES): Kontrollmechanismus, bei dem eine kritische Aktion (hier: Preis unterhalb Mindestpreis) nur nach Freigabe/Authentifizierung durch eine zweite, berechtigte Person zulässig ist.
- **Warenkorb (ReceiptCart)** (SALES): Technisch als Angebot mit zusätzlichem `CartState` geführter, über das Kunden-Web-Portal erstellter Bestellvorgang.
- **WEEE**: Abkürzung für "Waste Electrical and Electronic Equipment" (Elektro-/Elektronikgerätegesetz); im System eine Pflichtnummer je Artikelposition für WEEE-pflichtige Artikel in Aufträgen (SALES).
- **WebAccount** (ARCH, CRM, NEX, SEC): Eigener Kontotyp für externe Kunden (Kunden der Kunden), getrennt vom internen Mitarbeiter-Login (`AppUser`), u. a. für WebCart/CentronNexus-Kundenportal genutzt — technisch im selben Login-Namensraum eindeutigkeitsgeprüft wie interne Konten, ggf. mit mehreren verknüpften Kontaktpersonen (Multi-Web-Account).
- **WebHook** (INT): Technisches Muster, bei dem das System bei einem Ereignis proaktiv eine HTTP-POST-Nachricht an eine vom Empfänger vorgegebene URL sendet (Gegenstück zum Polling-Modell).
- **Weiterleitung/Forwarding (Belegkette)** (SALES): Vorgang, bei dem Positionen eines Belegs (z. B. Angebot) in einen Folgebeleg (z. B. Auftrag) übernommen werden; technisch über `ReceiptBL.ForwardReceipt()` und je Belegart erlaubte Quell-/Zielarten gesteuert.
- **XRechnung** (BILL): XML-basiertes E-Rechnungsformat nach EN16931, in Deutschland verpflichtend für Rechnungen an öffentliche Auftraggeber; benötigt zwingend eine Leitweg-ID.
- **ZUGFeRD** (BILL, DOC, INT): Deutsches Hybridformat für elektronische Rechnungen, kombiniert ein menschenlesbares PDF/A-3-Dokument mit eingebettetem strukturiertem XML (Cross Industry Invoice).
- **c-entron Nexus** (ARCH): Separate, web-/Blazor-basierte Anwendung ("c-entron Web") für externe Web-Accounts (u. a. WebCart-Shop), ergänzend zum WPF-Desktop-Client; Basis des CentronNexus-Ticket-/Helpdesksystems.
- **ebInterface** (INT): Österreichischer nationaler Standard für strukturierte XML-E-Rechnungen, u. a. verpflichtend für Rechnungen an österreichische Bundesbehörden.
- **finAPI** (INT): Deutscher Multibanking-/Kontoinformationsdienstleister (Third-Party-Provider), über den PSD2-konform auf Bankkonten und Kontoumsätze zugegriffen wird.
@@ -0,0 +1,140 @@
# Hypothesen — offene Punkte für Schritt 7 (fachliche Validierung)
Alle Anforderungen mit Status `HYPOTHESE` aus StRS/SyRS/SwRS, gruppiert nach Analysecluster. Jede Zeile nennt die betroffene ID, den Titel und die fehlende Information, die zur Bestätigung nötig wäre.
**Hinweis zur Vollständigkeit:** Die Cluster-Agenten haben zwei unterschiedliche Notationsformen für Unsicherheit verwendet: (a) Status **strikt** `HYPOTHESE` für Anforderungen, die insgesamt unbestätigt sind (siehe Abschnitte unten), und (b) Status `belegt` mit einer **eingebetteten** `[HYPOTHESE]`-Markierung für einen einzelnen Detailaspekt einer ansonsten belegten Anforderung. Da beide Formen laut Auftragsstellung ("alle mit `[HYPOTHESE]` markierten Aussagen") erfassungspflichtig sind, werden Fall (b) gesondert im Abschnitt "Eingebettete Teilhypothesen" am Ende dieses Dokuments aufgeführt.
## Anwendungsarchitektur & Systemrahmen (ARCH)
- **SwRS-ARCH-06** (Fehlende repository-interne Web-Service-API-Referenz): Die zentrale Web-Service-API-Dokumentation existiert offenbar nur als externe PDF auf einem internen Netzlaufwerk (`P:\Entwicklung C#\...`); diese war im Rahmen der Recherche nicht zugreifbar, sodass unklar bleibt, ob/wo eine vollständige, versionierte API-Referenz für die c-entron Web-Service-Schnittstelle tatsächlich existiert.
## Sicherheit & Berechtigungen (SEC)
- **SyRS-SEC-16** (Fehlender Brute-Force-Schutz bei Login-Versuchen): Kein Beleg im Anwendungscode für Zähler fehlgeschlagener Logins, Kontosperrung oder Rate-Limiting gefunden; offen ist, ob dies auf Infrastrukturebene (Reverse Proxy/WAF/API-Gateway) oder für AD-Logins über Active-Directory-eigene Kontosperrrichtlinien abgedeckt wird - im untersuchten Code-Cluster nicht einsehbar.
- **SwRS-SEC-05** (Zwei parallele, unabhängige 2FA-Subsysteme): Offen ist, in welchem konkreten Aufrufkontext (welche UI-Aktion, welcher Workflow) `TwoFactorAuthenticationBL.ValidateAuthenticationPin` tatsächlich im Produktivbetrieb verwendet wird - nur die Definition der Klasse wurde gelesen, nicht ihre Aufrufer.
- **SwRS-SEC-06** (Legacy-Passwortmodul ohne wirksame Verschlüsselung): Offen ist, ob das Modul `PasswordManagementArea` noch aktiv von der WPF-UI referenziert wird oder bereits vollständig durch das Hotline-basierte Passwort-Manager-Modul (`PasswordManagerBL`) ersetzt wurde - dazu wäre eine Prüfung der UI-Referenzen/Aufrufer nötig, die in dieser Recherche nicht durchgeführt wurde.
## Stammdaten: Geschäftspartner, Kunden, Mitarbeiter (CRM)
- **StRS-CRM-01** (Statusmodell für Geschäftspartner): Ob Lieferanten-Sperre über ein anderes Feld/Modul realisiert wird – im gesichteten `Supplier`-Entity fehlt ein zu `Customer.Locked` äquivalentes Feld.
- **StRS-CRM-04** (Dubletten-Erkennung und Zusammenführung von Geschäftspartnern): Negativbefund (keine Dubletten-/Merge-Logik gefunden) beruht auf gezielter Grep-Suche über einen begrenzten Verzeichnisbereich; nicht abschließend geprüft, ob Logik in einem nicht durchsuchten Modul oder externen Tool existiert.
- **SyRS-CRM-07** (Rechtebeschränkung Kundenzugriff): Ob `RIGHT_KUNDENSTAMM` und `SEARCH_CUSTOMER` bewusst unterschiedliche Berechtigungsstufen abbilden oder ein historisches Duplikat sind.
- **SwRS-CRM-07** (Redundante USt-IdNr. ohne Formatvalidierung): Welches der drei redundanten Felder (`Address.AdressSalesTaxIdentificationNumber`, `CustomerFinanceInfo.SalesTaxIdentificationNumber`, `Customer.VATNotActive`) tatsächlich führend ist und ob eine Formatvalidierung an anderer, hier nicht durchsuchter Stelle existiert.
- **SwRS-CRM-10** (Fehlende Duplikatsprüfung bei RFID-Tokens): Ob Eindeutigkeit von `RfidTokenEncrypted` ggf. per DB-Unique-Index sichergestellt ist – DAO-/Mapping-Definitionen wurden für dieses Cluster nicht vollständig durchsucht.
- **SwRS-CRM-11** (Kundenbetreuerrollen (Adviser1-6)): Fachliche Bezeichnung/Verwendung von `Adviser5I3D`/`Adviser6I3D` ist im gesichteten Code nicht dokumentiert.
- **SwRS-CRM-12** (Kundenindividuelle Pflichtangaben-Flags): Ob und wie `PurchaseOrderNumberRequiered`/`ProjNrNeeded`/`ProductionConfigurationRequiring` tatsächlich in der Auftragserfassung ausgewertet/durchgesetzt werden, wurde außerhalb dieses Clusters nicht verifiziert.
## Vertrieb & Einkauf (SALES)
In diesem Cluster trägt keine Anforderung den strikten Status "HYPOTHESE" (alle 32 Anforderungen sind primär durch Code belegt,
Status "belegt" bzw. "belegt; Workaround"). Die folgenden drei Anforderungen enthalten jedoch einen dokumentierten offenen
Punkt bzw. eine eingebettete Hypothese und werden nachrichtlich aufgeführt, da sie für die Konsolidierung relevant sein könnten:
- **SyRS-SALES-14** (Authentifizierung Handelspartner-Portal): Offen ist, ob das eigenständige TradeCustomerLogin-Verfahren (eigener Salt/Hash, losgelöst von AppUser/WebAccount) ein bewusst separates Legacy-System ist oder ob es künftig durch das zentrale Login-/Web-Account-System ersetzt werden soll; keine Information im Code darüber gefunden, ob dieses Verfahren noch aktiv genutzt wird.
- **SwRS-SALES-11** (Blockade von Bar-Belegen): Offen ist, ob Barverkauf für die Web/SaaS-Neuimplementierung überhaupt als Anforderung gilt oder ob die aktuelle Blockade eine bewusste, dauerhafte Produktentscheidung ist; im Code kein Hinweis auf geplante Aufhebung gefunden.
- **SwRS-SALES-13** (Manueller Angebotsabschluss (Legacy)): Offen ist, ob `OfferBL.CloseOfferByHand()` (CustomerAssets-Architektur) im aktuellen UI überhaupt noch erreichbar/aktiv ist, oder ob dieser Pfad bereits vollständig durch das neuere Receipt-Framework (`ReceiptOfferBL`/`OfferSpecificLogic`, siehe SwRS-SALES-10) abgelöst wurde; ohne Einsicht in die UI-Schicht nicht klärbar.
## Abrechnung, Fakturierung & Verträge (BILL)
- **SyRS-BILL-19** (Standard-Steuersatz 19% bei leeren Titelpositionen): Regel nur durch zwei übereinstimmende Dokumentationsartefakte belegt (docs/reference/zugferd-feldzuordnung-anwender.md:331, docs/reference/zugferd-field-mapping.md:365), kein PRIMÄR-Codebeleg (konkrete Codezeile in `InvoiceZugferdBL.cs` für den 19%-Default nicht gegengelesen). Für den Risikobereich Abrechnung/Steuerberechnung ist vor Übernahme in die konsolidierte Spezifikation eine Verifikation im Quellcode nötig.
## Zeiterfassung, Projekte & Tickets (intern) (TIME)
Keine Anforderungen mit Status HYPOTHESE im Cluster TIME. Alle 35 Kandidaten sind mit Status "belegt" oder "belegt; Workaround" eingestuft (siehe SwRS-TIME-12 und SwRS-TIME-13 sowie SyRS-TIME-15 für die Workaround-Fälle mit eingeschränkter Belegtiefe bzw. beobachtetem Code-Defekt statt reiner Anforderung).
## Lager, Logistik & Produktion (LOG)
- **SyRS-LOG-15** (Schnittstellen zu Versanddienstleistern (GLS, Shipcloud)): Keine Tiefenanalyse der API-Projekte `Centron.Api.Gls` und `Centron.Api.Shipcloud` im Rahmen dieses Clusters durchgeführt - offen sind u.a. das genaue Statusmapping einer Sendung, die Fehlerbehandlung bei Übergabefehlern sowie ob/wie der Sendungsstatus in den Barcode-/Lieferschein-Zustandsautomaten dieses Clusters zurückgespielt wird.
## Administration, Systemkonfiguration & Kommunikation (ADM)
- **StRS-ADM-04** (Kontextabhängige E-Mail-Signaturen): Offen, ob die Signaturquelle "Outlook" (lokales Windows-Client-Profil/Registry) in einer Web-/SaaS-Architektur ohne lokalen Windows-Client überhaupt sinnvoll fortgeführt werden kann oder durch rein zentrale (Centron-)Signaturverwaltung ersetzt werden muss - im Code keine Migrationsentscheidung dokumentiert.
- **SwRS-ADM-17** (Domain-Blacklist für Mailversand): Offen, welche fachliche Absicht hinter der Zeichen-für-Zeichen-Regex-Konstruktion für Nicht-"@"-Einträge steht (Sub-Domain-Wildcard vs. Teilstringsperre) - im Code nicht kommentiert, Klärung mit Fachbereich empfohlen.
- **SwRS-ADM-18** (Objektspezifische Mail-Tracking-Schlüsselwörter): Offen, wie die konfigurierten Tracking-Keywords beim Mailempfang tatsächlich ausgewertet werden (Verknüpfungslogik zu MailScanner/Zuordnung eingehender Antworten wurde in diesem Rechercheumfang nicht gelesen).
- **SwRS-ADM-19** (Rechteprüfung beim Zugriff auf MailScanner-Profile): Offen, ob `SaveProfile`, `DeleteProfile` und `SaveTasks` an anderer Stelle (z. B. WebService-/API-Schicht) ebenfalls rechtegeprüft werden - im gelesenen BL-Code selbst nicht erkennbar, nicht abschließend verifiziert.
- **SyRS-ADM-06** (Externe Lizenzserver-Anbindung): Offen, ob/wie das aktuelle On-Premise-Lizenzmodell (Hardware-ID- und Einzeldatenbank-Bindung über externen c-entron-Office-Lizenzserver) auf eine Multi-Tenant-SaaS-Architektur übertragen werden soll - im Code keine Aussage zu einer geplanten SaaS-Lizenzierung.
## Dokumente & Reporting (DOC)
- **SwRS-DOC-03** (S/MIME-Signaturprüfung bei archivierten E-Mail-Dokumenten): Unklar, ob die geloggte Warnung bei fehlgeschlagener S/MIME-Verifikation tatsächlich bis in die Benutzeroberfläche durchgereicht wird oder nur im Server-Log verbleibt — WPF-Client-Code wurde in diesem Cluster nicht geprüft.
- **SyRS-DOC-08** (Schnittstelle zu externem Drucker-Fleet-Management docuFORM): Kein Aufrufer/Consumer des `DocuFormRestApiClient` wurde in `Centron.BL` innerhalb des untersuchten Bereichs gefunden; Verwendungszweck (Abrechnung? Controlling?) und aufrufende Business-Logik sind unklar, ggf. in einem anderen Cluster (Administration/Gerätemanagement) verortet.
## Externe Integrationen & Schnittstellen (INT)
- **SwRS-INT-19** (Export von Verkaufsdaten für GfK-Marktforschung): Datei `GfkExportBL.cs` nur oberflächlich gesichtet (erste 60 Zeilen); genaues Exportformat (Feldstruktur), tatsächlicher Übertragungsweg (konkrete FTP-Zieladresse) und Trigger/Frequenz des Exports nicht verifiziert.
## CentronNexus (Ticket-/Helpdesk-System) (NEX)
- **StRS-NEX-01** (Kunden-Ticketerstellung mit optionalem internen Freigabeverfahren): Konkreter Freigabe-Workflow-Schritt, der ein Ticket mit `HelpdeskState == null` final in einen sichtbaren Status überführt, wurde in diesem Cluster nicht lokalisiert (evtl. Teil des CRM/Sales-Clusters - dortiges Rechercheergebnis abgleichen).
- **StRS-NEX-03** (Annahme-/Ablehnungsworkflow für neue Tickets): Der Enum `HelpdeskAfterOpenAction { Reject, Accept }` wurde isoliert gefunden; die konsumierende UI-/BL-Logik liegt außerhalb der gelesenen Dateien. Fehlende Information: konkreter Aufrufkontext, Auswirkung von Reject (Ticket löschen? Status zurücksetzen? Rückmeldung an Kunden?).
- **SyRS-NEX-06** (Echtzeit-Synchronisation des Ticketstatus zwischen Web und Outlook-Add-In): Der konkrete Transportmechanismus (SignalR-Hub-Name, Verbindung zu `NotificationsHubHelper`) wurde nicht im Detail verifiziert - `TicketUpdateService`-Implementierung liegt außerhalb der gelesenen Dateien.
- **SyRS-NEX-09** (Konfigurierbare Freigabe-/Berechtigungsmatrix für externe Helpdesk-Anbindung): Es wurde keine Business-Logik gefunden, die die Flags `AllowHelpdeskCreation`/`AllowCloseHelpdesks`/`TicketReleaseSystemEnabled` zur Laufzeit auswertet. Fehlende Information: Wo/wie werden diese Flags konsultiert (Controller/WebServices außerhalb der Startpunkte)?
- **SyRS-NEX-11** (Ticketerstellung aus E-Mail-Kontext im Outlook-Add-In): Die `CreateNewTicket`-Komponente selbst wurde in diesem Lauf nicht gelesen; exakte Feldvorbelegung (über MailSubject/AccountI3D hinaus) nicht verifiziert.
- **SwRS-NEX-07** (Vorlagenverwaltung für automatische Ticketerstellung aus Bestellungen): Basiert nur auf Feature-Dokumentation, nicht auf Code (`HelpdeskCreationTemplateBL.cs` nicht gelesen). Fehlende Information: exakte Implementierungsdetails, z.B. ob `CreateSeparateTicketsMode.Custom` tatsächlich eine Positionsauswahl unterstützt.
- **SwRS-NEX-09** (Definierter Ticket-Abschluss-Workflow inkl. ToDo-Bereinigung): `CanCloseHelpdesk`-Regeln (z.B. Pflichtfelder, offene Timer) wurden nicht im Detail gelesen (Datei `HelpdeskCloseBL.cs` nur Zeilen 1-140 von >300). Fehlende Information: genaue Ablehnungsgründe beim Schließen.
---
## Eingebettete Teilhypothesen (Status: "belegt", mit punktueller `[HYPOTHESE]`-Markierung)
Diese 21 Anforderungen sind in ihrem Kern durch Artefakte belegt (Status `belegt` bzw. `belegt; Workaround`), enthalten aber einen ausdrücklich als `[HYPOTHESE]` gekennzeichneten Teilaspekt, der ebenfalls fachlicher Validierung bedarf.
### Anwendungsarchitektur & Systemrahmen (ARCH)
- **StRS-ARCH-03** (Eingeschränkte Sprachauswahl im Produktivbetrieb): Produktentscheidung, ob Mehrsprachigkeit für Endkunden freigeschaltet werden soll, ist offen.
- **StRS-ARCH-04** (Mandanten- und Filialverwaltung): Abgrenzung "Mandant" vs. "Filiale" nur aus Namensgebung/Icon abgeleitet, keine Fachdokumentation gelesen.
- **StRS-ARCH-05** (WebCart als Kundenweb-Kanal): Detailarchitektur von c-entron Nexus (Blazor-Code) nicht gelesen, nur README ausgewertet.
- **SwRS-ARCH-04** (Persistenz benutzerspezifischer UI-Layouts): Speicherort/Synchronisationsverhalten nicht verifiziert.
- **SwRS-ARCH-05** (Einheitliches MVVM-Grundgerüst): Referenzdokumentation `mvvm-in-centron.md` leer/unvollständig; Muster nur aus Nachbardokumenten/Namenskonventionen rekonstruiert.
- **SyRS-ARCH-03** (TOTP-basierte Zwei-Faktor-Authentifizierung): Kein Beleg gefunden, ob TOTP-2FA erzwingend (Pflicht) oder optional ist.
- **SyRS-ARCH-04** (Entwickler-Schutz vor Kunden-E-Mail-Versand, DEBUG): Nur aus Dokumentation belegt, Quellcode `DeveloperSecurity.cs` nicht gegengelesen.
- **SyRS-ARCH-12** (Anwendungsweite Command Palette): Bedeutung/Priorität aus Endnutzersicht nicht belegt, keine Nutzungsstatistik verfügbar.
- **SyRS-ARCH-13** (Lizenz- und benutzerbezogene Nutzungstelemetrie): Opt-out-/Einwilligungsmechanismus (Consent-Handling) nicht verifiziert.
- **SyRS-ARCH-17** (RDP-/Terminalserver-Reconnect-Behandlung, Workaround): Unklar, ob RDP-Betrieb weiterhin offizielle Systemvoraussetzung ist oder nur Altlast (Mechanismus im Code aktuell deaktiviert).
### Sicherheit & Berechtigungen (SEC)
- **SyRS-SEC-10** (Serverseitige Validierung des Microsoft-ID-Tokens): Details zu erlaubten Signaturalgorithmen/Clock-Skew-Toleranz nicht verifiziert (`CentronHost.cs` nicht gelesen, nur Dokumentation ausgewertet).
- **SyRS-SEC-12** (Zugriffsprotokollierung im Passwort-Manager): Unklar, ob es im aktuell aktiven Passwort-Manager-Modul (`PasswordManagerBL.cs`) ein Äquivalent zum dokumentierten Zugriffsprotokoll gibt; nur `PasswordManagerLog` für andere Zwecke gefunden.
### Stammdaten: Geschäftspartner, Kunden, Mitarbeiter (CRM)
- **SwRS-CRM-04** (Automatische Vervollständigung von Kunde, Adresse, Ansprechpartner und Kundennummer): Kundennummernvergabe per `MAX(I3D)+1` ohne erkennbare Sperre/Transaktion — Nebenläufigkeitssicherheit gegen Race Conditions im gesichteten Code nicht erkennbar.
### Externe Integrationen & Schnittstellen (INT)
- **StRS-INT-03** (Webservice-Schnittstelle für Partnersysteme): Authentifizierungsdetails des Ticket-Mechanismus (Lebensdauer, Erneuerung) im gesichteten Code nicht verifiziert.
- **SwRS-INT-01** (FTP/FTPS/SFTP-Dateiübertragung mit ungeprüftem FTPS-Zertifikat): Keine Begründung im Code für die Zertifikatsausnahme (`ValidateAnyCertificate=true`) gefunden.
- **SwRS-INT-04** (AES-Verschlüsselung gespeicherter EDI-Zugangsdaten): Speicherort/Rotation des AES-Schlüssels im gesichteten Code nicht ersichtlich.
- **SwRS-INT-13** (Produktdatenabfrage über COP-SOAP-Schnittstelle): Aufrufzeitpunkt/Turnus (Trigger) nicht ermittelbar.
- **SwRS-INT-16** (Live-Verfügbarkeitsabfrage bei Komsa): Unklare Feldsemantik — Feld "Additional" wirkt wie ein Passwortfeld, aber Datenmodell inkonsistent.
- **SwRS-INT-17** (Generischer WebHook-Client für ausgehende Benachrichtigungen): Kein Wiederholungsmechanismus (Retry) im gesichteten Code erkennbar.
- **SyRS-INT-07** (PSD2-Bankanbindung über finAPI): Kein Token-Refresh-Mechanismus im gesichteten Code gefunden, ggf. an anderer Stelle implementiert.
- **SyRS-INT-08** (Verfügbarkeit und Betriebssicherheit der Webservice-Schnittstelle): Kein Beleg für einen zum Linux-Watchdog äquivalenten Mechanismus unter Windows gefunden.
---
## Nachträglich reklassifiziert: Abrechnungsanforderungen ohne PRIMÄR-Beleg
Diese vier Anforderungen waren im Rohbefund des Clusters BILL mit Status `belegt` markiert, obwohl nur ein `SEKUNDÄR`-Beleg (Dokumentation, nicht im Quellcode gegengelesen) vorlag. Da Abrechnungs-/Fakturierungslogik gemäß Auftragsstellung eine strengere Evidenzanforderung (mindestens ein `PRIMÄR`-Beleg, sonst zwingend `HYPOTHESE`) unterliegt, wurden sie im Rahmen des Konsistenzchecks auf Status `HYPOTHESE` korrigiert (siehe SyRS.md/SwRS.md).
- **SyRS-BILL-10** (Behandlung negativer Preise im E-Rechnungsexport): Vorzeichenbehandlung negativer Einzelpreise nur über Dokumentation und einen thematisch verwandten Code-Kommentar zur Rabattlogik indirekt gestützt; die tatsächliche Umsetzung selbst wurde nicht im Quellcode gegengelesen.
- **SyRS-BILL-17** (Hierarchische Bankauswahl für E-Rechnungsexport): Bankauswahl-Hierarchie nur über Dokumentation belegt, Settlement-Bereich in `InvoiceZugferdBL.cs` nicht zeilengenau verifiziert.
- **SwRS-BILL-03** (Gültigkeitsfilter für Aktionspreise in der Preismatrix): Filterlogik nur über Dokumentation mit Code-Referenz belegt, `PriceMatrixViewModel.cs` selbst nicht gegengelesen.
- **SwRS-BILL-05** (AnlageLog-Audit-Eintrag für Vertragsereignisse, AnlageArt=22): Tabellenschema/AnlageArt=22 nur über Dokumentation belegt, korrespondierender Enum-/Konstantenwert nicht separat im Code verifiziert.
@@ -0,0 +1,868 @@
# Stakeholder Requirements Specification (StRS) — CentronERP
Reverse Requirements Engineering — CentronERP. Erstellt am 2026-08-25 (Versuch 01, Iteration 01).
**ID-Konvention:** `StRS-<CLUSTER>-<laufende Nummer>`, wobei CLUSTER das fachliche Analysecluster kennzeichnet (siehe Cluster-Liste unten). Die Nummerierung ist je Cluster und Ebene fortlaufend, nicht global — Eindeutigkeit ist durch die Cluster-Präfixe gewährleistet.
**Cluster-Übersicht:**
- `ARCH` — Anwendungsarchitektur & Systemrahmen
- `SEC` — Sicherheit & Berechtigungen
- `CRM` — Stammdaten: Geschäftspartner, Kunden, Mitarbeiter
- `SALES` — Vertrieb & Einkauf
- `BILL` — Abrechnung, Fakturierung & Verträge
- `TIME` — Zeiterfassung, Projekte & Tickets (intern)
- `LOG` — Lager, Logistik & Produktion
- `ADM` — Administration, Systemkonfiguration & Kommunikation
- `DOC` — Dokumente & Reporting
- `INT` — Externe Integrationen & Schnittstellen
- `NEX` — CentronNexus (Ticket-/Helpdesk-System)
---
## Anwendungsarchitektur & Systemrahmen (ARCH)
ID: StRS-ARCH-01
Titel: GUID-basiertes Lizenzmodell
Ebene: StRS
Typ: funktional / Lizenzierung
Akteur: c-entron-Vertrieb, Kunde, Systemadministrator
Vorbedingung: Kunde hat einen Lizenzvertrag
Fakt: Lizenzen sind GUID-basierte Merkmale mit optionalem `count`, `valid until date`, `valid until version`. Es wird zwischen `Applications` (dürfen sich am Web-Service anmelden, Liste in `ApplicationKind.cs`, ca. 40 Einträge z.B. Centron, ServiceBoard, WebCart, PasswordManager, Outlook Add-In) und reinen Einzel-Feature-Lizenzen (`LicenseGuids.cs`) unterschieden. Single Source of Truth ist ein zentraler Lizenzserver.
Aussage: Das System soll ein zentrales, GUID-basiertes Lizenzmodell mit Zähler-, Ablaufdatum- und Versionsbindung besitzen, das sowohl den Zugang ganzer Anwendungen als auch einzelner Features steuert.
Ergebnis: Feingranulare kommerzielle Steuerung von Funktionsumfang und Zugriff; zentrale Voraussetzung für Feature-Gating in einer SaaS-Variante (z.B. Tarif-/Paketmodell).
Belege:
- [PRIMÄR] docs/reference/security/licensing-system.md:1-44 - Beschreibung GUID/count/valid until date/valid until version, Applications vs. Only Licenses
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs:11-53 - ca. 40 ApplicationKind-Einträge mit LicenseGuids, teils mit `licenseUsageKind: LicenseUsageKind.PerUser`, `expirationKind`
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 - ILicenseManager Interface (HasLicense, GetLicenseCount, CheckLicense)
Prüfidee: Klären, ob Lizenzprüfung offline (Dongle/Cache) funktionsfähig bleibt und wie oft synchronisiert wird (`FileLicenseCache`, `UpdateLicenseInterval`).
Tracelinks: SyRS-ARCH-02, SyRS-ARCH-13, SyRS-ARCH-15
Konsolidierung: nein
Status: belegt
---
ID: StRS-ARCH-02
Titel: Windows-Desktop-Systemvoraussetzung
Ebene: StRS
Typ: nicht-funktional (ISO25010: Kompatibilität / Systemumgebung)
Akteur: IT-Administrator, Endanwender
Vorbedingung: -
Fakt: Der Client (`Centron.WPF.UI.csproj`) zielt auf `net10.0-windows`, ist ein `WinExe` (WPF, WinForms-Abhängigkeiten wie `System.Windows.Forms.Screen`), bindet COM-Interop zu Microsoft Outlook (`Microsoft.Office.Interop.Outlook`) sowie ein modifiziertes Drittanbieter-TAPI-Modul (`Traysoft.AddTapi.dll`) ein. `global.json` fixiert die .NET-SDK-Version auf 10.0.100.
Aussage: Das System (c-entron.NET) soll als natives Windows-Desktop-Programm mit lokalen Windows-/Outlook-/TAPI-Abhängigkeiten betrieben werden und ist somit nicht plattformunabhängig.
Ergebnis: Klare Systemvoraussetzung "Windows + .NET 10 Runtime + ggf. Outlook/TAPI-Hardware" für den Bestandsclient; zentrale Motivation für die geplante Web-/SaaS-Neuimplementierung (Plattformunabhängigkeit als Ziel).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Centron.WPF.UI.csproj:1-24 - TargetFramework net10.0-windows, WinExe, COM-Interop-Referenzen
- [PRIMÄR] global.json:1-6 - SDK-Version 10.0.100
- [SEKUNDÄR] docs/reference/architecture/tapi.md:1-10 - TAPI-Integration nur für Windows-Produkte (c-entron.NET, Outlook Add-In, ServiceBoard)
Prüfidee: Abgleich mit Kunden-Systemvoraussetzungsdokument (falls vorhanden) auf weitere Hardware-/Software-Voraussetzungen (z.B. Terminalserver-Freigabe).
Tracelinks: SyRS-ARCH-08, SyRS-ARCH-11, SyRS-ARCH-14, SyRS-ARCH-17
Konsolidierung: nein
Status: belegt
---
ID: StRS-ARCH-03
Titel: Eingeschränkte Sprachauswahl im Produktivbetrieb
Ebene: StRS
Typ: nicht-funktional (ISO25010: Internationalisierbarkeit) — Abweichung/Workaround
Akteur: Endanwender
Vorbedingung: LoginDialog wird angezeigt
Fakt: Im `LoginDialogViewModel` wird die Sprachliste initial nur mit `de-DE` befüllt; `en-US` wird nur hinzugefügt, wenn `IsDevBuild` (Compile-Symbol `DEV_BUILD`) aktiv ist. Standardsprache ist explizit "German is the default language" (Kommentar im Code). Produktivbenutzer können in der UI somit i.d.R. nur Deutsch wählen, obwohl englische Ressourcendateien im Code existieren.
Aussage: Das System soll (Soll-Zustand im Ist offen) die im Backend vorhandene Mehrsprachigkeit (Deutsch/Englisch) auch produktiv über die Login-/Spracheinstellung zugänglich machen.
Ergebnis: Diskrepanz zwischen technischer Lokalisierungs-Infrastruktur (SyRS-ARCH-09) und tatsächlich für Endanwender nutzbarer Sprachauswahl; für SaaS-Zielbild zu klären, ob Mehrsprachigkeit ein echtes Geschäftsziel ist oder nur Entwickler-/Testzweck.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:93-98 - Languages.Add(en-US) nur `if (IsDevBuild)`
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:197-206 - IsDevBuild liest Compile-Symbol DEV_BUILD
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:239 - Kommentar "German is the default language."
Prüfidee: Produktentscheidung/Product Owner befragen, ob Englisch-Support als Geschäftsziel für die Web-Neuimplementierung gilt (aktuell nur "verstecktes" Dev-Feature).
Tracelinks: SyRS-ARCH-09
Konsolidierung: nein
Status: belegt (Soll-Zustand/Produktentscheidung zu Mehrsprachigkeit offen; HYPOTHESE: fehlende Produktentscheidung, ob Mehrsprachigkeit für Endkunden freigeschaltet werden soll)
---
ID: StRS-ARCH-04
Titel: Mandanten- und Filialverwaltung
Ebene: StRS
Typ: funktional
Akteur: Kunde mit mehreren Gesellschaften/Niederlassungen, Administrator
Vorbedingung: Lizenz "branch functionality" vorhanden (laut licensing-system.md Beispiel)
Fakt: Es existiert ein Modul "Mandantenverwaltung" (`MandatorManagementAppModuleController`, ID `{717AD6A2-...}`, Kategorie Administration) sowie ein separates "BranchManagement" (Filialverwaltung, Nummernkreise) unter demselben Namensraum `Administration.MandatorManagement`.
Aussage: Das System soll die Verwaltung mehrerer Mandanten/Gesellschaften bzw. Filialen (Niederlassungen) innerhalb einer c-entron-Instanz unterstützen, inklusive eigener Nummernkreise je Filiale.
Ergebnis: Mehrmandantenfähigkeit auf Ebene "mehrere Unternehmenseinheiten in einer Datenbank" (kein Hinweis auf Datenbank-pro-Kunde-Mandantentrennung im Sinne von SaaS-Multi-Tenancy); wichtig für SyRS-Datenmodell-Entscheidung bei Neuimplementierung.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/MandatorManagementAppModuleController.cs:9-45 - Modul "Mandanten Verwaltung"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/BranchManagement/* - BranchManagementView/ViewModel, NumberGroupsViewModel (Dateiliste)
- [KONTEXT] CentronRights.md:14-26 - Rechte mit Filial-Einschränkung ("nur eigene Filiale") als Beleg für aktive fachliche Nutzung von Filialen/Mandanten in Rechten
Prüfidee: Klären, ob "Mandant" hier = rechtlich eigenständige Gesellschaft (mit eigener Buchhaltung) oder nur Organisationseinheit ist; Datenmodell (MandantI3D-Spalten) verifizieren.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (Abgrenzung "Mandant" vs. "Filiale" nicht abschließend verifiziert; HYPOTHESE: Begriffsdefinition nur aus Namensgebung/Icon abgeleitet, keine Fachdoku gelesen)
---
ID: StRS-ARCH-05
Titel: WebCart als Kundenweb-Kanal
Ebene: StRS
Typ: funktional
Akteur: Kunde des Kunden (Web-Account-Benutzer)
Vorbedingung: Web-Account wurde in c-entron.NET Adressstamm angelegt, Sonderpreise hinterlegt
Fakt: README.md beschreibt "WebCart" als Feature primär für Kunden der Kunden: Login als Web-Account bei "c-entron Nexus" (separate Web-Anwendung, "c-entron Web"), Artikelanzeige basiert auf hinterlegten "Sonderpreisen" im c-entron.NET Adressstamm, Zugriff über Menüpunkt "Shop".
Aussage: Das System soll einen webbasierten Bestellkanal (WebCart) für Endkunden der c-entron-Kunden bereitstellen, dessen Sortiment/Preise zentral im ERP (c-entron.NET) gepflegt werden.
Ergebnis: Bereits vorhandener Web-Kanal (c-entron Nexus) als Blaupause/Vorstufe für die geplante SaaS-Neuimplementierung — zeigt, dass Teile des Systems bereits heute web-basiert sind und mit dem ERP-Kern über Web-Accounts/Sonderpreise integriert sind.
Belege:
- [PRIMÄR] README.md:1,29-35 - Beschreibung WebCart, Web-Account-Login, Sonderpreise, "Shop"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/WebCart (Namensraum in ModuleRegistration.cs Zeile 40) - zugehöriges WPF-Verwaltungsmodul
Prüfidee: Architektur von "c-entron Nexus" (separates Blazor-Projekt laut README-Kontext "azure-blazor") im Detail untersuchen — ggf. eigener Cluster/Repository-Bereich außerhalb des hier untersuchten Scopes.
Tracelinks: SyRS-ARCH-16
Konsolidierung: nein
Status: belegt (Detailarchitektur von c-entron Nexus außerhalb des recherchierten Bereichs; HYPOTHESE: Nexus/Blazor-Code nicht gelesen, nur README)
---
ID: StRS-ARCH-06
Titel: Breites Produkt-/Anwendungsportfolio
Ebene: StRS
Typ: funktional
Akteur: Produktmanagement, Entwickler
Vorbedingung: -
Fakt: `ApplicationKind.cs` listet neben dem Kern-ERP ("NEXOWARE c-entron ERP") ca. 40 weitere, separat lizenzierte Anwendungen/Produkte im selben Ökosystem (u.a. Service-Board, Service-Board Online, c-entron Nexus, Outlook Add-In, PasswordManager, WebCart, WebSuitePro, DocumentSync, Riversuite-Familie [Inventory/Compliance/Monitoring/Mobile/Online/Pro/N13/RFlow/SupRemo], TAPI-Server, Communicator, MailScanner/MailScannerNET, diverse ExternalApp-Connectoren zu Drittsystemen wie c-pra, DocBee, Visoma, WOASI).
Aussage: Das System ist Teil eines breiten Produkt-/Anwendungsportfolios (nicht nur ein einzelnes ERP), das über ein gemeinsames Lizenz- und Authentifizierungssystem am zentralen Web-Service andockt.
Ergebnis: Wichtige Erkenntnis für den StRS-Systemüberblick: Die Web-/SaaS-Neuimplementierung des ERP-Kerns muss die Schnittstellen zu diesem breiteren Produktportfolio (mind. Authentifizierung/Lizenzierung) weiterhin bedienen können, auch wenn die Einzelprodukte selbst außerhalb des Scopes liegen.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs:11-53 - vollständige Liste der ApplicationKind-Instanzen
Prüfidee: Mit Produktmanagement klären, welche dieser Anwendungen im Rahmen der SaaS-Neuimplementierung migriert/integriert werden müssen vs. weiterhin als separate Legacy-Clients bestehen bleiben.
Tracelinks: SyRS-ARCH-01
Konsolidierung: nein
Status: belegt
## Sicherheit & Berechtigungen (SEC)
ID: StRS-SEC-01
Titel: Getrennte Identitätsklassen für Mitarbeiter und Kunden
Ebene: StRS
Typ: Stakeholder-Ziel
Akteur: c-entron Mitarbeiter (interner Benutzer, "AppUser"), Kunde (Web-Account)
Vorbedingung: -
Fakt: Das System unterscheidet technisch zwei vollständig getrennte Benutzerarten mit eigenen Tabellen/Entities und eigenen Authentifizierungspfaden: interne Mitarbeiter (`AppUser`/Tabelle `Sichbenu`) und Kunden-Zugänge (`WebAccount`). Beide durchlaufen unterschiedliche Authenticator-Klassen (`BasicAuthenticator`/`ActiveDirectoryAuthenticator` vs. `WebAccountAuthenticator`).
Aussage: Das System soll interne Mitarbeiterkonten und externe Kundenzugänge als getrennte Identitätsklassen mit eigenen Rechte- und Authentifizierungsregeln führen.
Ergebnis: Zwei unabhängige Benutzer-/Rechtemodelle (App-Rechte über `Sichrech`/`Sichtrus`/`Sichmemb` für Mitarbeiter, `WebRights`/`WebAccountsRights` für Kunden).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs (AuthenticatorFactory.GetMainAuthenticator, Zeilen 88-95) - Begründung: Routing anhand des konkreten `AuthObject`-Typs (BasicAuthObject/WebAccountAuthObject/OpenIdConnectAuthObject) belegt getrennte Codepfade.
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/WebAccountAuthenticator.cs (Zeile 20-83) - Begründung: Eigene Authentifizierungsklasse nur für Kundenzugänge.
Prüfidee: Prüfen, ob im Zielsystem beide Identitätsklassen (Mitarbeiter, Kunde) weiterhin getrennt modelliert werden müssen oder ob ein einheitliches Identity-Modell mit Rollenattribut ausreicht.
Tracelinks: SyRS-SEC-01, SyRS-SEC-02, SyRS-SEC-03, SyRS-SEC-04, SyRS-SEC-13, SyRS-SEC-14
Konsolidierung: nein
Status: belegt
---
ID: StRS-SEC-02
Titel: Gruppenbasierte Rechtevergabe (RBAC)
Ebene: StRS
Typ: Stakeholder-Ziel
Akteur: Administrator (Rechteverwaltung)
Vorbedingung: -
Fakt: Rechte werden nicht direkt an Benutzer, sondern an Gruppen (`AppGroup`) vergeben; Benutzer werden Gruppen zugeordnet (`AppUserMember`), Gruppen erhalten Rechte (`AppGroupRightAssignment`). Das Modul "Rechteverwaltung" (`Rechteverwaltung`) verwaltet dies laut Doku.
Aussage: Das System soll Zugriffsrechte gruppenbasiert (rollenbasiert) statt benutzerindividuell vergeben, um Verwaltungsaufwand und Fehlerquote bei der Rechtevergabe zu reduzieren.
Ergebnis: Ein Benutzer erhält die Vereinigungsmenge aller Rechte seiner zugeordneten Gruppen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (GetRightsFromCurrentUser, Zeilen 63-87; CheckRightsFromUser, Zeilen 95-111) - Begründung: SQL-Join über `Sichtrus`/`Sichmemb` aggregiert Rechte ausschließlich über Gruppenmitgliedschaft.
- [KONTEXT] docs/guides/development/check-userrights.md (Zeile 3) - Begründung: "Rights and groups can be managed in the Rechteverwaltung module."
Prüfidee: Klären, ob im SaaS-Zielsystem weiterhin Gruppen als einzige Rechteträger dienen sollen oder zusätzlich direkte Nutzer-Overrides (Allow/Deny) benötigt werden.
Tracelinks: SyRS-SEC-04, SwRS-SEC-01, SwRS-SEC-02
Konsolidierung: nein
Status: belegt
---
ID: StRS-SEC-03
Titel: Einschränkende Rechte für Datensparsamkeit
Ebene: StRS
Typ: Stakeholder-Ziel
Akteur: Administrator, Mitarbeiter (eingeschränkter Sichtbereich)
Vorbedingung: -
Fakt: Neben "Vollrechten" existiert die dokumentierte Kategorie "einschränkendes Recht" (restricting right), z. B. `SHOW_HELPDESK_ONLY_OWN`, `SHOW_HELPDESK_ONLY_OWN_BRANCH`, `MANAGE_RIGHTS_ONLY_OWN_BRANCH`. Diese Rechte schränken eine bereits gewährte Sichtbarkeit weiter ein (z. B. nur eigene Filiale).
Aussage: Das System soll eine Datensparsamkeit nach Bedarfsprinzip ("need-to-know") über kombinierbare einschränkende Rechte (nur eigene Datensätze / nur eigene Filiale) umsetzen können.
Ergebnis: Ein Benutzer mit Grundrecht + einschränkendem Recht sieht nur eine Teilmenge der Datensätze, die er ohne das einschränkende Recht sehen würde.
Belege:
- [PRIMÄR] CentronRights.md (Abschnitte 1.1, 1.2, 2.1, Zeilen 9-26) - Begründung: Explizite Dokumentation als "restricting right" mit fachlicher Wirkung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (SaveRightGroup, Zeilen 391-393; DeleteRightGroup, Zeilen 355-357) - Begründung: `MANAGE_RIGHTS_ONLY_OWN_BRANCH` wird serverseitig ausgewertet und verweigert filialübergreifende Aktionen.
Prüfidee: Ermitteln, wie viele "nur eigene"/"nur eigene Filiale"-Rechte insgesamt existieren (Sichrech-Auswertung) und ob dieses Muster generisch (z. B. Row-Level-Security/Policy Engine) statt Recht-für-Recht abgebildet werden kann.
Tracelinks: SwRS-SEC-01, SwRS-SEC-02
Konsolidierung: nein
Status: belegt
---
ID: StRS-SEC-04
Titel: Schutz der Administratorengruppe
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator
Vorbedingung: -
Fakt: Die Gruppe mit `I3D == 6` bzw. Name "Administratoren" ist im Code hart gegen Löschung geschützt (`DeleteRightGroup`) und nur eine explizite Whitelist von ca. 30 Rechten darf dieser Gruppe hinzugefügt/entzogen werden (`GetAssignableAdminRightI3Ds`).
Aussage: Das System soll die Administratorengruppe strukturell vor versehentlicher Löschung und vor Entzug sicherheitskritischer Rechte schützen.
Ergebnis: Löschversuch der Administratorengruppe liefert Fehlermeldung "Die Adminstratoren Gruppe darf nicht gelöscht werden"; Rechteänderungen an dieser Gruppe außerhalb der Whitelist werden abgelehnt (Rückgabe `false`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (DeleteRightGroup, Zeilen 348-374; SaveAndAssignGroupToRight/RemoveAssignGroupToRight, Zeilen 261-299; GetAssignableAdminRightI3Ds, Zeilen 714-759) - Begründung: Serverseitige Schutzlogik unabhängig vom UI, harte Prüfung `group.I3D == 6`.
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppUserGroupBL.cs (IsAdministratorGroup/IsAdministratorGroupI3D, Zeilen 78-89) - Begründung: Zentrale Definition "Administratorengruppe = I3D 6 ODER Name = 'Administratoren'".
Prüfidee: Verifizieren, ob Namensvergleich ("Administratoren") als Sicherheitskriterium zuverlässig ist (Umbenennungsrisiko) oder nur der I3D-Vergleich sicherheitsrelevant sein sollte.
Tracelinks: SwRS-SEC-01, SwRS-SEC-02
Konsolidierung: nein
Status: belegt
---
ID: StRS-SEC-05
Titel: Zwei-Faktor-Authentifizierung als Sicherheitsstufe
Ebene: StRS
Typ: Sicherheit
Akteur: Mitarbeiter, Kunde (Web-Account)
Vorbedingung: -
Fakt: Zusätzlich zu Benutzername/Passwort existiert eine konfigurierbare Zwei-Faktor-Authentifizierung mit zwei austauschbaren Verfahren: RADIUS-Server (`RadiusTwoFactorValidator`) und E-Mail-Link (`EmailTwoFactorValidator`), gesteuert über `WebServiceConfigHelper.Current.TwoFactorAuthType`.
Aussage: Das System soll eine zusätzliche Authentifizierungsstufe (2FA) als organisatorisch konfigurierbare Sicherheitsmaßnahme anbieten.
Ergebnis: Login schlägt fehl, wenn 2FA aktiviert, aber nicht erfolgreich validiert wurde ("Die Zwei-Faktor-Authentifizierung ist fehlgeschlagen.").
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorAuthBL.cs (GetTwoFactorValidator, Zeilen 181-194; ValidateTwoFactor, Zeilen 33-80) - Begründung: Zentrale Weiche für 2FA-Verfahren, in allen drei Authenticator-Klassen (Basic/AD/WebAccount) eingebunden.
Prüfidee: Klären, ob im Zielsystem TOTP/App-basierte 2FA (wie im separaten Passwort-Manager-Verfahren, siehe SwRS-SEC-05) als drittes gleichwertiges Verfahren für den Login ergänzt werden soll.
Tracelinks: SyRS-SEC-07, SyRS-SEC-08, SyRS-SEC-09, SwRS-SEC-05
Konsolidierung: nein
Status: belegt
---
ID: StRS-SEC-06
Titel: Single Sign-On über Microsoft Entra ID
Ebene: StRS
Typ: Schnittstelle
Akteur: Mitarbeiter (Unternehmens-Konto)
Vorbedingung: Azure AD App Registration vorhanden, Lizenz `OpenIDConnectAuthentication`
Fakt: Die Funktion "Anmelden mit Microsoft" ist als vollständiger OpenID-Connect-Flow über MSAL dokumentiert und implementiert (`/config/jwt`, `/jwt/login`, `/jwt/connect_accounts`).
Aussage: Das System soll Single-Sign-On über Microsoft Entra ID als alternativen, konfigurierbaren Anmeldeweg unterstützen.
Ergebnis: Erfolgreiche Anmeldung liefert ein c-entron-Ticket (Session) ohne c-entron-eigenes Passwort.
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md (gesamt, insb. Zeilen 126-146, 386-403) - Begründung: Vollständige technische Dokumentation inkl. Dateipfaden.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs (GetFromOpenIdConnectAuth, Zeilen 129-145) - Begründung: Lizenzprüfung `LicenseGuids.OpenIDConnectAuthentication` und Aktivierungs-Flag `JwtEnabled` als Vorbedingung bestätigt.
Prüfidee: Prüfen, ob Redirect-/Consent-Flow und Token-Validierung 1:1 in eine Web-/SaaS-Neuimplementierung (z. B. mit Standard-OIDC-Middleware) übernommen werden können.
Tracelinks: SyRS-SEC-10
Konsolidierung: nein
Status: belegt
---
ID: StRS-SEC-07
Titel: Lizenzpflichtiger Zugriff auf den Passwort-Manager
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator, Vertriebsmitarbeiter mit Zugriff auf Kundenzugangsdaten
Vorbedingung: Lizenz "Passwort-Manager" vorhanden
Fakt: Der Zugriff auf das gesamte Passwort-Manager-Modul (Kundenzugänge/Passwörter) ist zusätzlich zur Rechteprüfung an eine kommerzielle Lizenz gekoppelt (`LicenseManager.Instance.HasLicense(LicenseGuids.PasswordManager)`), die in praktisch jeder öffentlichen Methode von `PasswordManagerBL` geprüft wird.
Aussage: Das System soll den Zugriff auf sicherheitskritische Zusatzmodule (z. B. Passwort-Manager) sowohl über Lizenz als auch über Benutzerrechte absichern (zweistufige Zugriffskontrolle).
Ergebnis: Ohne Lizenz: Fehlermeldung "Sie besitzen keine Lizenz für den Passwort-Manager." (`DefaultMessageCodes.LicenseNotFound`), unabhängig von vorhandenen Rechten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/PasswordManager/PasswordManagerBL.cs (z. B. Zeilen 94-95, 243-244, 263-264, 331-332, 349-350, 896-897, 932-933) - Begründung: Wiederkehrendes Muster in mind. 8 Methoden.
- [KONTEXT] docs/reference/security/licensing-system.md (Zeilen 50-63) - Begründung: Allgemeines Lizenzkonzept (`LicenseManager.Instance.HasLicense`) bestätigt als Standardmuster.
Prüfidee: Klären, ob Lizenzprüfung im SaaS-Modell durch Tenant-/Subscription-Feature-Flags ersetzt wird und ob die doppelte Prüfung (Lizenz UND Recht) beibehalten werden soll.
Tracelinks: SyRS-SEC-11, SyRS-SEC-12
Konsolidierung: nein
Status: belegt
## Stammdaten: Geschäftspartner, Kunden, Mitarbeiter (CRM)
ID: StRS-CRM-01
Titel: Statusmodell für Geschäftspartner
Ebene: StRS
Typ: Daten
Akteur: Vertrieb, Buchhaltung
Vorbedingung: -
Fakt: Der Kundenstatus wird über zwei getrennte, unabhängig setzbare Attribute abgebildet: `State` (int, wirkt wie "aktiv/inaktiv", Vergleich `== 1`) und `Locked` (bool, "gesperrt"). Es existiert kein enumeriertes Statusmodell mit benannten Zuständen (z. B. "gelöscht", "archiviert", "Bonitätssperre") im gesichteten BL-Code.
Aussage: Das System soll den Lebenszyklus-Status eines Kunden (aktiv/inaktiv, gesperrt/entsperrt) als eigenständiges fachliches Konzept abbilden, das im Zielsystem klar benannte, erweiterbare Zustände (z. B. Enum statt Rohint) unterstützt.
Ergebnis: Migrationsrelevanter Fakt: Legacy-Datenmodell nutzt zwei binäre/int-Felder statt eines State-Machine-Modells.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:15,30 (`State`, `Locked`) - Begründung: Felddefinition.
- [KONTEXT] src/backend/Centron.Entities/Entities/Businesspartner/Supplier.cs:8-9 - Begründung: Lieferant besitzt nur `State`, kein `Locked`-Äquivalent – Asymmetrie zwischen Kunden- und Lieferanten-Stammdatenmodell.
Prüfidee: Klärung mit Fachbereich, ob Lieferanten je gesperrt werden können und wie das aktuell (ohne `Locked`-Feld) gehandhabt wird.
Tracelinks: SyRS-CRM-03
Konsolidierung: nein
Status: HYPOTHESE (fehlende Information: ob Lieferanten-Sperre über anderes Feld/Modul realisiert wird – im gesichteten `Supplier`-Entity nicht vorhanden)
---
ID: StRS-CRM-02
Titel: DSGVO-konforme Löschung von Kontaktpersonen
Ebene: StRS
Typ: Sicherheit / Compliance
Akteur: Buchhaltung, Vertrieb, Datenschutzbeauftragter
Vorbedingung: Löschantrag zu einer Kontaktperson (DSGVO/Art. 17 DSGVO)
Fakt: `DataSecurityBL` implementiert eine "DSGVO löschen"-Funktion für `ContactPerson`: personenbezogene Felder (Geburtsdatum, Beruf, Telefon 1-5, Fax 1-2, E-Mail 1-2, Mailing-Flags, Kommentarfelder, Abteilung, Bild, Active-Directory-SID, Website, Web-Zugangsdaten) werden geleert bzw. mit dem Platzhaltertext "DSGVO: Auf Anfrage gelöscht. (Durchgeführt von {ShortSign} am {Datum} um {Uhrzeit} Uhr)" überschrieben; jeder gelöschte Wert wird vor dem Löschen in ein Lösch-Protokoll (`deleteProtocol`) geschrieben; die Kontaktperson erhält `IsDsgvoDeleted=true`, `DsgvoDeletedEmployeeI3D`, `DsgvoDeletedDate` und wird (außer bei `Standard`-Kontakt) deaktiviert (`Status=0`).
Aussage: Das System soll auf Anfrage die personenbezogenen Daten einer Kontaktperson DSGVO-konform anonymisieren, den Vorgang inkl. verantwortlichem Mitarbeiter und Zeitpunkt nachvollziehbar protokollieren und die vorherigen Werte für Nachweiszwecke in einem Löschprotokoll festhalten.
Ergebnis: Kontaktperson ist nach Ausführung anonymisiert, als DSGVO-gelöscht markiert und (i. d. R.) deaktiviert; ein Audit-Trail bleibt erhalten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:1152-1276 - Begründung: Vollständige Feld-für-Feld-Anonymisierungslogik inkl. Protokollierung und Statusmarkierung.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:26-27 - Begründung: Konstanten für den Lösch-Kommentartext.
Prüfidee: DSGVO-Löschung einer Testkontaktperson auslösen; prüfen, dass alle genannten Felder geleert sind, `IsDsgvoDeleted=true` gesetzt ist und ein lesbares Protokoll erzeugt wird.
Tracelinks: SwRS-CRM-08 (kein SyRS-Zwischenschritt im Cluster vorhanden – Lücke auf SyRS-Ebene)
Konsolidierung: Kandidat: SwRS-CRM-08, StRS-CRM-03 (gemeinsames Thema DSGVO-Datenlöschung/-bereinigung)
Status: belegt
---
ID: StRS-CRM-03
Titel: Übersicht löschrelevanter Altdatenbestände (DSGVO)
Ebene: StRS
Typ: Compliance / Sicherheit
Akteur: Datenschutzbeauftragter
Vorbedingung: Durchführung einer DSGVO-Datenbereinigung
Fakt: `DataSecurityBL.GetDataSecurityCleanUpStats` liefert Statistiken zu löschrelevanten Datenbeständen (Kunden mit letzter Aktion älter als Datum X, bereits gelöschte Kunden, CRM-Aktivitäten älter als Datum X, Belege [Angebote/Aufträge/Lieferscheine/Abholscheine/Rechnungen/Gutschriften] älter als Datum X, mit Filter nach Kundenart/Objektart/Abschlussstatus). Zugriff ist an das Recht `UserRightsConst.DsgvoModule.ACCESS_CLEANUP_DATABASE` UND ein Feature-Flag `ModuleFeatures.IsDsgvoDatabaseCleanupAvailable` gekoppelt.
Aussage: Das System soll autorisierten Benutzern eine Übersicht über lösch-/archivierungsrelevante Alt-Datenbestände (Kunden, CRM-Aktivitäten, Belege) auf Basis konfigurierbarer Aufbewahrungsfristen bereitstellen, bevor eine Bereinigung ausgeführt wird.
Ergebnis: Statistik-Report vor Ausführung der eigentlichen Löschung; feature-geflaggt und rechtebeschränkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:34-62 (`GetDataSecurityCleanUpStats`) - Begründung: Zeigt Filter- und Rechtekombination.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:64-70 (`DataSecurityExecuteCleanUp`) - Begründung: Ausführungsmethode ist rechtegeschützt, der eigentliche Bereinigungsvorgang liefert im gesichteten Ausschnitt nur `Result.AsSuccess()` ohne sichtbare Löschlogik an dieser Stelle (weitere Implementierung evtl. in nicht gelesenen Codeteilen der 1900-Zeilen-Datei).
Prüfidee: Statistikabruf mit und ohne Recht `ACCESS_CLEANUP_DATABASE` testen; Feature-Flag deaktivieren und Verhalten prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: StRS-CRM-02, SwRS-CRM-08 (gemeinsames Thema DSGVO-Datenlöschung/-bereinigung)
Status: belegt (Ausführungslogik nur teilweise gesichtet – Datei hat 1900 Zeilen, nicht vollständig gelesen)
---
ID: StRS-CRM-04
Titel: Dubletten-Erkennung und Zusammenführung von Geschäftspartnern
Ebene: StRS
Typ: nicht-funktional (Datenqualität)
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Anlage/Pflege von Kunden- und Lieferanten-Stammdaten über die Zeit
Fakt: Im gesamten gesichteten `Centron.BL`-Code (Customer-, Address-, ContactPerson-, Supplier-Bereich) wurde keine Dubletten-Erkennung (z. B. Ähnlichkeitssuche über Name/Adresse/USt-IdNr.) und keine Merge-Funktion für zwei Geschäftspartner-Datensätze gefunden; die einzige Unterstützung ist die Freitext-Suche nach Matchcode/Name/I3D vor manueller Neuanlage (`SearchCustomerBL`, `SearchCustomerBySearchText`).
Aussage: Das System soll Vertriebs- und Buchhaltungsmitarbeiter bei der Neuanlage von Geschäftspartnern durch eine aktive Dubletten-Prüfung (z. B. Ähnlichkeitssuche) unterstützen und eine Funktion zum Zusammenführen (Merge) versehentlich doppelt angelegter Datensätze bereitstellen.
Ergebnis: Fehlende Funktionalität im Ist-System; Dublettenvermeidung liegt vollständig in der manuellen Sorgfalt des Sachbearbeiters.
Belege:
- [KONTEXT] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99 (`SearchCustomerBySearchText`) - Begründung: Zeigt, dass nur eine einfache Textsuche als Vorab-Prüfung existiert.
- [KONTEXT] Negativbefund aus gezielter Suche (`grep -rniE "dublette|duplicate|merge"` über `Sales/Customers`, `EmployeeArea`, `CountryArea`, `BusinessPartner`) - Begründung: Keine Treffer zu fachlicher Dubletten-/Merge-Logik für Geschäftspartner (nur technische Login-Duplikatsprüfungen, siehe SyRS-CRM-05).
Prüfidee: Fachbereich befragen, ob Dublettenbereinigung ggf. über ein separates, hier nicht durchsuchtes Modul (z. B. externes Datenqualitäts-Tool) erfolgt, das nicht Teil von `Centron.BL` ist.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein (explizit abgegrenzt von SyRS-CRM-05: dort nur technische Login-Namen-Eindeutigkeit, keine fachliche Geschäftspartner-Dublette)
Status: HYPOTHESE (fehlende Information: Negativbefund – Abwesenheit von Funktionalität kann nicht abschließend über Quellcode-Grep bewiesen werden, ggf. existiert Logik in einem nicht durchsuchten Modul oder als externes Tool)
## Vertrieb & Einkauf (SALES)
ID: StRS-SALES-01
Titel: CRM-Klassifizierung von Angeboten
Ebene: StRS
Typ: funktional (Geschäftsziel CRM/Vertriebssteuerung)
Akteur: Vertrieb, Vertriebsleitung
Vorbedingung: Ein Beleg implementiert `IReceiptWithClassifications` (u.a. Angebote).
Fakt: `ReceiptBL.CheckIfClassificationIsNeeded()` verlangt drei Felder als Pflichtfelder für die
CRM-Klassifizierung: `ProjectEnd` (Projektende), `ProductGroupClassificationI3D` (Produktgruppe),
`ProbabilityClassificationI3D` (Abschlusswahrscheinlichkeit), sofern `data.IgnoreCallbacks==false`.
Ergänzend liefert `OfferSpecificLogic.ShouldBeSetCrmProjectByThreshold()=true`.
Aussage: Das System soll bei Angeboten eine CRM-Klassifizierung (Produktgruppe, Abschlusswahrscheinlichkeit, geplantes
Projektende) als verpflichtende Angaben zur Vertriebssteuerung/Forecasting erzwingen.
Ergebnis: Strukturierte Vertriebs-Pipeline-Daten (Sales-Funnel) als Basis für Umsatzprognosen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9415-9440 - CheckIfClassificationIsNeeded() - Begründung: erzwingt die drei Pflichtfelder beim Speichern eines klassifizierbaren Belegs.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:631 - ShouldBeSetCrmProjectByThreshold() => true - Begründung: bestätigt, dass Angebote diese Klassifizierung fachlich nutzen.
Prüfidee: Angebot ohne Klassifizierung speichern → Fehler zu fehlenden Feldern ProjectEnd/ProductGroupClassification/ProbabilityClassification.
Tracelinks: keine direkte Verknüpfung (Lücke) - keine eigenständige SyRS-/SwRS-Anforderung in diesem Cluster elaboriert die technische Umsetzung separat.
Konsolidierung: nein
Status: belegt
---
ID: StRS-SALES-02
Titel: Bestellvorschlagsliste (BVL) für Einkauf
Ebene: StRS
Typ: funktional (Bedarfsermittlung/Dispo)
Akteur: Einkauf
Vorbedingung: Artikel mit Lagerabbuchung (`Abbuchung='J'`) oder Pflichtbuchung (`IsObligatoryBooking`) sind in offenen
Aufträgen/Beständen unterbestellt.
Fakt: `OrderSuggestionListBL` liefert mehrere Bestellvorschlagslisten (BVL): `GetOrderSuggestionArticle`
(artikelbasiert inkl. Sonderartikel/Spezialvereinbarungen), `GetOrderSuggestionOrder`
(auftragsbasiert, filterbar nach Direktlieferung `Direktlieferung=1` und Mietportal-Sonderfall `isMietPortal`),
`GetOrderSuggestionWH` (lagerbasiert). `StoreSuggestionInfo()`/`RemoveDirectDelivery()` erlauben manuelle
Bearbeitung einzelner Auftragspositionen (Infotext, Direktlieferungs-Flag) direkt aus der BVL heraus.
Aussage: Das System soll dem Einkauf eine mehrdimensionale Bestellvorschlagsliste (je Artikel, je Auftrag, je Lager)
bereitstellen, die offene Bedarfe inklusive Direktlieferungs- und Mietportal-Sonderfällen konsolidiert und
eine direkte Bearbeitung einzelner Auftragspositionen (Infotext, Direktlieferung entfernen) ermöglicht.
Ergebnis: Zentrales Werkzeug zur Bedarfsbündelung/Disposition vor der eigentlichen Bestellauslösung an Lieferanten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:589-733 - GetOrderSuggestionArticle(), GetArticlePerItems(), GetOrderSuggestionOrder() - Begründung: implementiert die drei Kernsichten der Bestellvorschlagsliste.
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:1039-1067 - StoreSuggestionInfo(), RemoveDirectDelivery() - Begründung: belegt direkte Bearbeitbarkeit von Auftragspositionen aus der BVL.
- [KONTEXT] git log -- src/backend/Centron.BL/Purchasing: "2fbbe1561e Ticket 148592: Mindestbestellmenge in BVL", "4e8dca6f3e Ticket 147996: BVL mit Teil-Direktlieferung", "f54e265bff Ticket 155192: Neue Artikeleigenschaft 'Bei BVL berücksichtigen'", "78e1854f60 BVL: CRMProjekt für Aufträge" - Begründung: belegt kontinuierliche fachliche Weiterentwicklung als Kern-Einkaufswerkzeug.
Prüfidee: BVL für Artikel mit offenem Bedarf aus mehreren Aufträgen aufrufen, Direktlieferungs-Flag einer Position entfernen und Persistenz prüfen.
Tracelinks: SyRS-SALES-12 - Begründung: SyRS-SALES-12 (Rückspiegelung Liefertermin bei Direktlieferung) konkretisiert den Direktlieferungs-Sonderfall, den die BVL filtert/bearbeitet.
Konsolidierung: nein
Status: belegt
## Abrechnung, Fakturierung & Verträge (BILL)
ID: StRS-BILL-01
Titel: E-Rechnungserzeugung (ZUGFeRD/XRechnung) rechtssicher automatisieren
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung / Finanzbuchhaltung
Vorbedingung: Rechnung/Gutschrift ist im System erfasst und soll elektronisch versendet werden
Fakt: c-entron generiert beim Rechnungs-/Gutschriftexport automatisiert ZUGFeRD- bzw. XRechnung-konforme XML-Dateien (Versionen 1.0 bis 2.1/XRechnung 3.0.1), implementiert in `InvoiceZugferdBL.cs`. Die Formatwahl (ZUGFeRD Comfort vs. XRechnung) erfolgt automatisch anhand des Vorhandenseins einer Leitweg-ID.
Aussage: Das System soll rechtssichere elektronische Rechnungen (ZUGFeRD/XRechnung) automatisiert aus den erfassten Rechnungs- und Gutschriftdaten erzeugen können, ohne manuelle Nacharbeit der Anwenderin.
Ergebnis: Verkäufer kann gesetzeskonforme E-Rechnungen (auch für öffentliche Auftraggeber) versenden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156 (GenerateZugferdFile, Formatwahl anhand leitwegID) - Begründung: Kernmechanik der automatisierten E-Rechnungserzeugung im Code nachgewiesen
- [SEKUNDÄR] docs/reference/zugferd-feldzuordnung-anwender.md:9-14 - Begründung: Anwenderdokumentation bestätigt unterstützte Versionen
Prüfidee: Export einer Rechnung ohne und mit Leitweg-ID durchführen, resultierendes Dateiformat/-schema prüfen (KOSIT-Validator)
Tracelinks: SyRS-BILL-06, SyRS-BILL-07, SyRS-BILL-08, SyRS-BILL-09, SyRS-BILL-10, SyRS-BILL-11, SyRS-BILL-12, SyRS-BILL-17, SyRS-BILL-19
Konsolidierung: nein
Status: belegt
---
ID: StRS-BILL-02
Titel: Automatisierte wiederkehrende Vertragsabrechnung (Contract-Billing)
Ebene: StRS
Typ: funktional
Akteur: Vertriebsinnendienst / Vertragsmanagement
Vorbedingung: Kunde hat einen laufenden Wartungs-/Servicevertrag mit wiederkehrender Abrechnung
Fakt: c-entron bietet ein eigenständiges Contract-Billing-Subsystem (`ReceiptContract`, `AutomaticFacturaBL.Contracts`), das Verträge nach konfigurierbaren Intervallen (Daily/Monthly/Quarterly/Yearly) automatisiert abrechnet, inkl. Integration externer RMM-Nutzungsdaten (Riverbird) und Kontingentverwaltung.
Aussage: Das System soll wiederkehrende Vertragsleistungen automatisiert, nach konfigurierbarem Abrechnungsintervall und unter Berücksichtigung von Nutzungsdaten/Kontingenten korrekt fakturieren.
Ergebnis: Reduzierter manueller Aufwand bei der Abrechnung von Wartungs-/MSP-Verträgen, korrekte periodengerechte Rechnungsstellung.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs (Felder BillingIntervalKind, BillingIntervalDuration, AutomatedBilling) - Begründung: Entität trägt Konfigurationsfelder für automatisierte Intervallabrechnung
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:721-802 (CheckRMMArticle) - Begründung: Ausführbare Logik zur automatisierten RMM-basierten Rechnungspositionserzeugung
Prüfidee: Testvertrag mit monatlichem Intervall anlegen, automatische Abrechnung anstoßen, Rechnungsperiode/-betrag verifizieren
Tracelinks: SyRS-BILL-13, SyRS-BILL-14, SyRS-BILL-15
Konsolidierung: nein
Status: belegt
---
ID: StRS-BILL-03
Titel: Mahnstufenbasierte Beleg-/Auftragssperre zur Kreditrisikobegrenzung
Ebene: StRS
Typ: funktional
Akteur: Finanzbuchhaltung / Mahnwesen
Vorbedingung: Kunde hat offene, überfällige Forderungen
Fakt: Das System führt ein Mahnstufen-Modell (`DunningLevel1Fees/2/3`, `DunningLetterAfterDays1-3`) je Kunde und kann konfigurierbar ab einer bestimmten Mahnstufe die Neuanlage von Belegen (z.B. Aufträgen) sperren (`LockOrderAfterDunningLevel`, durchgesetzt in `ReceiptBL.CanUserCreateNewReceiptsAtCustomerOrSupplier`).
Aussage: Das System soll säumige Kunden anhand eines Mahnstufenmodells identifizieren und optional automatisch von der Neuanlage weiterer Belege ausschließen, um das Ausfallrisiko zu begrenzen.
Ergebnis: Kreditrisikobegrenzung; Vertrieb kann keine neuen Aufträge/Belege für gesperrte Kunden anlegen, solange die Mahnstufe nicht sinkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 (CanUserCreateNewReceiptsAtCustomerOrSupplier, exakte Fehlermeldung "Aufgrund der Mahnstufe darf kein neuer Beleg ... angelegt werden.") - Begründung: Durchgesetzte Regel im Code, inkl. Fehlermeldungstext
- [PRIMÄR] src/backend/Centron.Entities/Entities/Accounts/AccountCustomer.cs:25 (LockOrderAfterDunningLevel) - Begründung: Persistiertes Feld je Kunde als Datengrundlage der Regel
Prüfidee: Kunde mit LockOrderAfterDunningLevel=2 und aktueller Mahnstufe 2 anlegen, Versuch neuen Auftrag zu erstellen -> erwartete Fehlermeldung
Tracelinks: SyRS-BILL-16, SwRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: StRS-BILL-04
Titel: Rechtssichere Rechnungsstornierung ohne Bruch der Buchhaltungsintegrität
Ebene: StRS
Typ: nicht-funktional (Compliance/Datenintegrität)
Akteur: Buchhaltung / Wirtschaftsprüfung
Vorbedingung: Eine Rechnung wurde bereits weiterverarbeitet (z.B. exportiert, in Buchhaltung übernommen) oder ist eine Barrechnung
Fakt: `ReceiptInvoiceBL.CancelInvoice` verweigert die Stornierung, wenn die Rechnung bereits storniert ist, es sich um eine Barrechnung handelt, sie bereits weiterverarbeitet oder bereits an die Buchhaltung exportiert wurde, oder es sich bei einer Vertragsrechnung nicht um die zuletzt erstellte handelt.
Aussage: Das System soll die Stornierung von Rechnungen nur zulassen, solange keine downstream-Verarbeitung (Export, Weiterverarbeitung) stattgefunden hat, um Inkonsistenzen mit Buchhaltung/Finanzamt zu vermeiden.
Ergebnis: Verhinderung nachträglicher Inkonsistenzen zwischen ERP und exportierten/gebuchten Finanzdaten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:143-206 (CancelInvoice, komplette Prüfkette) - Begründung: Vollständige, im Code durchgesetzte Vorbedingungskette mit exakten Fehlermeldungen
Prüfidee: Testrechnung exportieren (BookKeepingExportBL) und danach Stornoversuch -> Fehlermeldung "...bereits exportiert wurde." erwarten
Tracelinks: SyRS-BILL-01, SyRS-BILL-02, SyRS-BILL-03, SyRS-BILL-04, SyRS-BILL-05, SyRS-BILL-18, SyRS-BILL-20, SwRS-BILL-02, SwRS-BILL-05
Konsolidierung: nein
Status: belegt
## Zeiterfassung, Projekte & Tickets (intern) (TIME)
ID: StRS-TIME-01
Titel: Konfigurierbares Regelwerk für die Timer-Abrechnung
Ebene: StRS
Typ: Daten
Akteur: Buchhaltung
Vorbedingung: Die Abrechnung von Ticketzeiten zu Belegen soll konfiguriert werden.
Fakt: `TimerBillingSettingsDTO`/`HelpdeskSettings` bilden ein umfangreiches Regelwerk ab, u. a.: Gruppierung nach Zeittyp (`GroupTimersByType`) und gleichem Artikel (`GroupEqualArticles`), Rundung vor/nach Summierung (`RoundTimersBeforeGrouping`), Sortierung (`ChronologicalUp/Down/ByEmployee`), Einfügen von Ticket-Kurzbeschreibung/-Beschreibung, Sonderartikel am Ende oder direkt bei der Position, Übernahme der Ticketzeit als Leistungszeitraum (`UseTicketTimeAsServicePeriod`), Übertragung in Stücklisten (`TransferAllTimesToPartsList`/`TransferTimesWithSamePriceToPartsList`), Standard-Stücklistenkopf, Ersetzen von Stücklistenartikeln/-text, Sortierung der Stückliste nach Ticket.
Aussage: Das System soll der Buchhaltung ein umfangreiches, granular konfigurierbares Regelwerk zur Steuerung bereitstellen, wie Ticketzeiten zu Belegpositionen (inkl. Stücklisten) zusammengefasst, sortiert und dargestellt werden.
Ergebnis: Breites Konfigurationsmodell für die Timer-Abrechnung bestätigt.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingSettingsPageViewModel.cs:440-483 - Begründung: 1:1-Mapping der UI-Einstellungen auf die persistierten HelpdeskSettings-Felder.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:89-173,521-568 - Begründung: Verarbeitung dieser Einstellungen beim Erzeugen der Belegpositionen.
Prüfidee: Einstellung GroupTimersByType aktivieren -> Zeiten werden mit Titel-Trennzeile je Zeittyp gruppiert (Text aus AppSetting-Vorlage mit Platzhalter @@Typ@@).
Tracelinks: SyRS-TIME-03, SyRS-TIME-04, SyRS-TIME-05, SyRS-TIME-06, SyRS-TIME-09
Konsolidierung: nein
Status: belegt
---
ID: StRS-TIME-02
Titel: Terminanfrage-Workflow mit Kundenauswahl (Exchange-Integration)
Ebene: StRS
Typ: funktional
Akteur: Kunde, Mitarbeiter
Vorbedingung: Ein Mitarbeiter schickt einem Kunden Terminvorschläge zur Auswahl (z. B. für einen Service-Einsatz).
Fakt: `AppointmentRequestState` beschreibt einen linearen Workflow: `RequestOpen`(1) → `AppointmentProposalsSent`(2) → `AppointmentProposalAccepted`(3) ODER `AppointmentProposalsRejected`(4) → `Done`(5). `AppointmentRequestBL.HandleAppointmentRequestReply` verarbeitet die Kundenantwort über Microsoft Exchange (EWS): bei Ablehnung werden alle vorgeschlagenen Exchange-Termine gelöscht und `RequestState = AppointmentProposalsRejected` gesetzt; bei Annahme wird der akzeptierte Termin im Exchange-Kalender als "(Akzeptiert)" markiert, der Kunde als Pflichtteilnehmer ergänzt, die Kategorie von "Terminvereinbarung (offen)" auf "...(akzeptiert)" umgestellt und alle übrigen Vorschläge werden entfernt.
Aussage: Das System soll Terminanfragen an Kunden mit mehreren Terminvorschlägen unterstützen, deren Antwort (Annahme/Ablehnung) automatisiert im Exchange-Kalender nachvollziehen und den Anfragestatus entsprechend fortschreiben.
Ergebnis: Terminanfrage-Workflow mit Exchange-Integration bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/AppointmentRequests/AppointmentRequestBL.cs:29-114 - Begründung: vollständige Antwortverarbeitung inkl. Exchange-Aktionen.
- [SEKUNDÄR] src/backend/Centron.Interfaces/AppointmentRequests/AppointmentRequestState.cs:9-16 - Begründung: Statusdefinition.
Prüfidee: Kunde akzeptiert einen von drei Terminvorschlägen -> akzeptierter Termin bleibt mit Zusatz "(Akzeptiert)" bestehen, die anderen zwei werden entfernt, Status wechselt auf AppointmentProposalAccepted.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: StRS-TIME-03
Titel: Aktives Vertriebsprojektmanagement (CrmProject)
Ebene: StRS
Typ: funktional
Akteur: Projektleiter, Vertrieb
Vorbedingung: Ein CRM-/Vertriebsprojekt (CrmProject, z. B. Kundenprojekt mit Umsatzprognose) wird angelegt oder ausgewertet.
Fakt: `CrmProject` verwaltet u. a. bis zu vier Berater- (`Adviser1-4I3D`) und Kontaktperson-Slots, `ProjectStateI3D`/`ProjectKindI3D`/`ProjectProbabilityI3D` (jeweils eigene Stammdaten-Entität statt Enum), Umsatz-/Margenwerte (auch monatlich), `DecisionDate`, `CloseProjectReason`. `CrmProjectBL.SaveCrmProject` erzwingt `Name` als Pflichtfeld, vergibt bei Neuanlage automatisch Nummer (`NumberGroupEnum.CRMProject`) und setzt `State = 1` (aktiv) fest. Das Recht `UserRightsConst.RIGHT_CRMPROJEKTONLYOWN` erzwingt bei fehlendem Vollzugriff eine Filterung auf Projekte, in denen der Mitarbeiter als Berater, Verantwortlicher oder Ersteller eingetragen ist.
Aussage: Das System soll Vertriebsprojekte mit mehreren Beratern/Kontaktpersonen, konfigurierbaren Status-/Art-/Wahrscheinlichkeits-Stammdaten sowie Umsatz-/Margenprognose verwalten und den Zugriff darauf optional auf eigene bzw. zugeordnete Projekte einschränken.
Ergebnis: Aktives Projektmanagement-Datenmodell (CrmProject, nicht das Legacy-„Project") mit Zugriffsbeschränkung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Customers/CrmProjects/CrmProject.cs (lt. Sub-Recherche) - Begründung: vollständige Feldliste.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CrmProjects/CrmProjectBL.cs:105-174,469-541 (lt. Sub-Recherche) - Begründung: Anlage-Validierung, automatische Nummernvergabe, Rechtefilterung `RIGHT_CRMPROJEKTONLYOWN`.
Prüfidee: Mitarbeiter ohne RIGHT_CRMPROJEKTONLYOWN-Ausnahme ruft Projektliste ab -> nur Projekte mit ihm als Berater/Verantwortlichem/Ersteller werden geliefert.
Tracelinks: SwRS-TIME-13
Konsolidierung: nein
Status: belegt
## Lager, Logistik & Produktion (LOG)
ID: StRS-LOG-01
Titel: Warnung bei Lieferschein-Erstellung trotz aktiver Teil-Kommissionierung
Ebene: StRS
Typ: funktional
Akteur: Vertrieb/Lager (Auftragsabwicklung)
Vorbedingung: Ein Auftrag mit aktiven Teil-Kommissionierungssätzen wird in einen Lieferschein überführt
Fakt: `PartialCommissionOrderBL.HasPartialCommissionOrdersForItems` prüft, ob mindestens eine der zu liefernden Auftragspositionen zu einem aktiven (weder gelöschten noch gelieferten) Teil-Kommissionierungssatz gehört — laut Code-Kommentar zur Warnung des Anwenders, dass Teil-Kommissionierungssätze beim direkten Umwandeln eines Auftrags in einen Lieferschein ignoriert werden (Ticket 165243).
Aussage: Das System soll den Anwender warnen, wenn beim Erzeugen eines Lieferscheins aus einem Auftrag aktive Teil-Kommissionierungssätze für betroffene Positionen bestehen, die dabei ignoriert würden.
Ergebnis: Vermeidung von Fehllieferungen bzw. inkonsistenter Kommissionsdaten durch Umgehung des Teil-Kommissionierungs-Workflows.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/Commissions/PartialCommissionOrderBL.cs:100-129 (HasPartialCommissionOrdersForItems, inkl. XML-Doc-Kommentar mit Ticketreferenz)
Prüfidee: Auftrag mit aktivem Teil-Kommissionierungssatz direkt in Lieferschein umwandeln und auf Warnhinweis prüfen.
Tracelinks: SyRS-LOG-08
Konsolidierung: nein
Status: belegt
---
ID: StRS-LOG-02
Titel: Produktionsmanagement als lizenzpflichtiges Zusatzmodul
Ebene: StRS
Typ: funktional / Lizenzierung
Akteur: Produktionsplaner
Vorbedingung: Zugriff auf jegliche Produktionsfunktion (Maschinen, Stücklisten, Fertigungsaufträge)
Fakt: Praktisch jede Methode in `ProductionBL`, `ProductionOrderBL` und `ArticleProductionBL` prüft zu Beginn `LicenseManager.Instance.HasLicense(LicenseGuids.ProductionManagement)`; bei fehlender Lizenz wird je nach Methode entweder eine `Exception` mit der Meldung "Sie besitzen nicht die Lizenz für das Produktionsmanagement" geworfen oder (bei einigen Lesemethoden in `ArticleProductionBL`) stillschweigend ein leeres Objekt/eine leere Liste zurückgegeben.
Aussage: Das System soll sämtliche Produktionsmanagement-Funktionen (Maschinen, Maschinenarten, Standorte, Stücklisten, Fertigungsschritte, Fertigungsaufträge) an eine separate Lizenz binden.
Ergebnis: Produktionsmanagement als optional lizenzierbares Modul, klar abgegrenzt von der Basis-Warenwirtschaft.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Production/ProductionBL.cs:29-30,39-40,49-50,105-106,115-116,126-127,166-167,177-178,185-186,226-227,236-237,246-247,256-257 (wiederholte Lizenzprüfung)
- [SEKUNDÄR] src/backend/Centron.BL/Warehousing/ArticleProduction/ArticleProductionBL.cs:34-35,44-45,55-56,75-76 (uneinheitliches Verhalten: teils Exception, teils leeres Ergebnis)
Prüfidee: Produktionsfunktionen ohne gültige ProductionManagement-Lizenz aufrufen und Verhalten (Exception vs. leeres Ergebnis) je Methode dokumentieren.
Tracelinks: SyRS-LOG-11, SwRS-LOG-09, SwRS-LOG-10
Konsolidierung: nein
Status: belegt (Detailaspekt als Hypothese offen: uneinheitliches Fehlerverhalten bei fehlender Lizenz (Exception vs. leere Liste) wirkt wie technische Inkonsistenz statt bewusster fachlicher Anforderung, für Web-Neuimplementierung zu klären)
---
ID: StRS-LOG-03
Titel: Automatisierte Bestellvorschläge bei Mindestbestand-Unterschreitung
Ebene: StRS
Typ: funktional
Akteur: Einkauf/Disposition
Vorbedingung: Artikelbestand unterschreitet den konfigurierten Mindestbestand in Haupt- oder Nebenlager
Fakt: `OrderSuggestionListBL` ermittelt per SQL Bestellvorschläge, indem der aktuelle Bestand (`cvw_ArticleCount.cnt`) je Artikel/Lager mit `Mindestbestand` (+ Bestellungen in Zulieferung, `IsNull(ab.duration,0)`) verglichen wird — getrennt für Hauptlager (`WarehouseI3D = -1`, Quelle `ARTIK.Mindestbestand`) und Nebenlager (Quelle `NebenlagerArtikel.Mindestbestand`). Artikel müssen zusätzlich `Abbuchung = 'J'` (Bestandsführung aktiv) oder `IsObligatoryBooking = 1` erfüllen.
Aussage: Das System soll automatisch Bestellvorschläge generieren, wenn der Lagerbestand (Haupt- oder Nebenlager) unter den je Lager konfigurierbaren Mindestbestand fällt, unter Berücksichtigung bereits laufender Zulieferungen.
Ergebnis: Automatisierte Nachbestellung zur Vermeidung von Fehlbeständen (Basis für Beschaffungsprozess).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:139-158,425-436,860-870 (SQL-Logik Mindestbestand vs. cvw_ArticleCount, getrennt Haupt-/Nebenlager)
Prüfidee: Artikel mit Mindestbestand 10 auf Bestand 5 senken, Bestellvorschlagsliste generieren und Aufnahme des Artikels prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
## Administration, Systemkonfiguration & Kommunikation (ADM)
ID: StRS-ADM-01
Titel: Zentrale, clientunabhängige Konfigurationsverwaltung
Ebene: StRS
Typ: nicht-funktional (Architekturprinzip)
Akteur: Systemadministrator, IT-Verantwortlicher
Vorbedingung: Client-Anwendung möchte Einstellungen lesen/schreiben.
Fakt: Laut Entwicklerdokumentation greift der Client "nie direkt" auf die Settings-Tabellen zu; stattdessen existieren pro fachlichem Bereich "Group Setting Classes", die Settings laden, typisiert kapseln und über dedizierte REST-API-Methoden (POST) bereitstellen (Beispiel `ReceiptWebServiceBL.GetReceiptInvoiceSettings`/`SaveReceiptInvoiceSettings`).
Aussage: Das System soll Systemkonfiguration ausschließlich über eine serverseitige Business-Logic-Schicht mit klar definierten, fachlich gruppierten DTOs bereitstellen und den direkten Tabellenzugriff durch Clients unterbinden.
Ergebnis: Zentrale, versionierbare Konfigurationsschnittstelle als Grundlage für eine künftige Web-/SaaS-API.
Belege:
- [SEKUNDÄR] docs/guides/development/settings-management.md:63-114 - Begründung: Beschreibt explizit "The client never accesses settings tables directly" sowie Group-Setting-Class-Pattern mit Beispielcode.
- [KONTEXT] src/backend/Centron.BL/Administration/Settings/AppSettingsGroupBL.cs:1864-1887 - Begründung: Konkretes Beispiel eines Group-Setting-Zugriffs (CentronNotifications).
Prüfidee: Architekturreview: Prüfen, ob WPF-Client tatsächlich nur über WebService-DTOs auf Settings zugreift (keine direkten SQL/DAO-Aufrufe aus UI-Schicht).
Tracelinks: SyRS-ADM-01; SwRS-ADM-01, SwRS-ADM-02, SwRS-ADM-03, SwRS-ADM-04
Konsolidierung: nein
Status: belegt
---
ID: StRS-ADM-02
Titel: Personalisierte Modulfavoriten je Mitarbeiter
Ebene: StRS
Typ: funktional
Akteur: Sachbearbeiter/Endbenutzer
Vorbedingung: Benutzer ist angemeldet und möchte häufig genutzte Module schnell erreichen.
Fakt: Benutzer können Module individuell als Favoriten markieren (`ModuleFavorite` verknüpft `Employee` und `Module`); die Anzeige erfolgt gruppiert nach Modulkategorie (`GetModuleFavoritesGroupedByCategory`). Beim Speichern der Favoriten wird bei technischem Fehler die Meldung "Die Favoriten konnten nicht gespeichert werden." zurückgegeben, beim Umschalten eines einzelnen Favoriten "Der Favorite konnte nicht geändert werden.".
Aussage: Das System soll es jedem Benutzer ermöglichen, Module individuell als Favoriten zu markieren und diese nach Kategorie gruppiert anzuzeigen; Fehler beim Speichern sollen dem Benutzer mit einer verständlichen Meldung angezeigt werden.
Ergebnis: Personalisierte, schnellere Navigation im Modulmenü je Mitarbeiter.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleBL.cs:44-81 (GetModuleFavorites, SaveModuleFavorites, UpdateModuleFavorite) - Begründung: Zeigt Favoriten-Datenmodell (pro Employee) und Fehlermeldungstexte.
- [SEKUNDÄR] src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:88-113 (GetModuleFavoritesGroupedByCategory) - Begründung: Zeigt Gruppierungslogik nach Kategorie für die Anzeige.
Prüfidee: UI-/API-Test: Favorit setzen, Session neu laden, prüfen ob Favorit weiterhin gruppiert nach Kategorie erscheint; Fehlerfall (DB nicht erreichbar) prüfen auf Fehlermeldungstext.
Tracelinks: SwRS-ADM-05, SwRS-ADM-06 (Modul-/Kategoriesynchronisation als technische Grundlage); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: StRS-ADM-03
Titel: Konfigurierbares E-Mail-Transportprotokoll
Ebene: StRS
Typ: Schnittstelle
Akteur: IT-Verantwortlicher
Vorbedingung: Das System soll E-Mails im Namen des Unternehmens versenden/empfangen.
Fakt: Der zu verwendende Mail-Client wird zentral über die Einstellung `CentronWebserviceMailType` gesteuert und kann zwischen SMTP (Default), Microsoft Exchange (EWS) und Microsoft Graph umgeschaltet werden (`CentronMailFactory.GetMail`). Zusätzlich existiert ein globaler Testmail-Modus (`TestMails.IsEnabled`), der bei aktiven Subscribern jede reale Mail-Versendung durch einen In-Memory-Mock ersetzt.
Aussage: Das System soll die Wahl des E-Mail-Transportprotokolls (SMTP/Exchange/Microsoft Graph) als zentrale, administrierbare Einstellung anbieten und einen von der Konfiguration unabhängigen Test-/Simulationsmodus für den Mailversand unterstützen.
Ergebnis: Flexible Integration in unterschiedliche Kunden-Mailinfrastrukturen; sichere Testbarkeit ohne reale Mailversendung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/CentronMailFactory.cs:26-53 (GetMail) - Begründung: Zeigt Protokollauswahl per Setting und TestMail-Vorrang.
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 - Begründung: Zeigt Subscriber-Pattern für Testmail-Abfang.
Prüfidee: Konfigurationstest: CentronWebserviceMailType nacheinander auf 0/Exchange/Graph setzen und prüfen, dass jeweils die korrekte Implementierungsklasse instanziiert wird.
Tracelinks: SyRS-ADM-03; SwRS-ADM-09, SwRS-ADM-10, SwRS-ADM-11, SwRS-ADM-12, SwRS-ADM-17, SwRS-ADM-18
Konsolidierung: nein
Status: belegt
---
ID: StRS-ADM-04
Titel: Kontextabhängige E-Mail-Signaturen
Ebene: StRS
Typ: funktional
Akteur: Systemadministrator/Sachbearbeiter
Vorbedingung: Ausgehende Mails (allgemein, Helpdesk intern, Helpdesk extern) sollen eine Signatur erhalten.
Fakt: `MailSignatureBL` unterscheidet drei unabhängig konfigurierbare Signaturkontexte (Standard `MailSignatureKind`, `HelpdeskInternalMailSignatureKind`, `HelpdeskExternalMailSignatureKind`) und je Kontext eine Signaturquelle (`MailSignatureKind`-Enum: None/Outlook/Centron). Bei Quelle "Outlook" wird die Signatur aus lokalen Outlook-RTF-Dateien plus Windows-Registry-Konfiguration (`HKCU\...\Outlook\Profiles\...`) gelesen; bei Quelle "Centron" aus einer in der Datenbank hinterlegten Signatur (`AppSettingData`, Encoding 1252).
Aussage: Das System soll pro Mail-Kontext (Standard, Helpdesk intern, Helpdesk extern) eine unabhängig konfigurierbare Signaturquelle unterstützen, wahlweise aus lokalem Outlook-Profil oder zentral in der Datenbank gepflegter Signatur.
Ergebnis: Fachlich getrennte, kontextabhängige Signaturgestaltung; Outlook-Quelle ist jedoch an lokale Windows-Umgebung/Registry gebunden (Client-seitige Abhängigkeit).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSignatureBL.cs:111-182 (GetHelpdeskExternalSignature, GetHelpdeskInternalSignature, GetDefaultSignature, GetSignature) - Begründung: Drei parallele, strukturell identische Methoden für die drei Kontexte.
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSignatureBL.cs:41-96 (GetDefaultOutlookSignature) - Begründung: Zeigt Registry-/Dateisystem-Abhängigkeit der Outlook-Signaturquelle inkl. `OperatingSystem.IsWindows()`-Prüfung mit Fehler "Outlook default signature can only be loaded on windows".
Prüfidee: Für Web-/SaaS-Migration klären: Outlook-Signaturquelle ist im Web-/SaaS-Kontext (kein lokales Windows-Client-Profil) nicht sinnvoll übertragbar - Anforderung an Nachfolgesystem prüfen (nur noch zentrale Signaturverwaltung?).
Tracelinks: StRS-ADM-03 (gemeinsamer Kommunikations-/Mail-Kontext); SyRS/SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; HYPOTHESE bzgl. Weiterverwendung der Outlook-Quelle im Web/SaaS-Kontext (technische Prämisse "lokaler Windows-Client mit Outlook" entfällt vermutlich in einer SaaS-Architektur - im Code nicht explizit als Migrationsentscheidung dokumentiert)
---
ID: StRS-ADM-05
Titel: Mandantenstammdaten mit Logos und Bankverbindungen
Ebene: StRS
Typ: Daten
Akteur: Systemadministrator
Vorbedingung: Unternehmensstammdaten (Mandant) sollen gepflegt und für Belegdruck/Kommunikation verwendet werden.
Fakt: `MandatorBL` erwartet genau einen als Standard markierten Mandanten (`Default == 1`, `GetDefaultMandator`/`GetDefaultMandatorExtended`); ein Mandant kann bis zu acht unterschiedliche Logo-/Bildvarianten hinterlegen (`PictureOne` … `PictureEight`, Zugriff über `GetMandatorLogoByIndex` mit Index 1-8, sonst Fehler "image index was out of range (index can be between 1 and 8)"). Für ESR/QR-Zahlungsreferenzen kann eines von vier hinterlegten Bankkonten je Mandant als aktiv markiert werden (`UseBankForEsr` 1-4, `GetEsrBankIndex`/`GetIBANFromEsrIndex`).
Aussage: Das System soll pro Mandant genau einen als Standard gekennzeichneten Datensatz mit bis zu acht wählbaren Firmenlogos sowie bis zu vier hinterlegten Bankverbindungen verwalten, von denen eine für ESR/QR-Referenzen aktiv gewählt werden kann.
Ergebnis: Mandantenfähige Stammdatenverwaltung als Grundlage für Corporate-Design (Logo) und Zahlungsverkehr je Mandant.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:19-27 (GetDefaultMandator, GetDefaultMandatorExtended) - Begründung: Zeigt Default-Flag-Semantik.
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:90-125 (GetMandatorLogoByIndex) - Begründung: Zeigt Acht-Bilder-Struktur inkl. Fehlermeldung bei ungültigem Index.
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:54-88 (GetEsrBankIndex, GetIBANFromEsrIndex) - Begründung: Zeigt Vier-Konten-Struktur mit wählbarem Referenzkonto.
Prüfidee: Datenmodelltest: Mehrere Mandanten mit Default=1 in Testdaten anlegen und prüfen, welches Verhalten GetDefaultMandator zeigt (GetEntity liefert vermutlich undefiniertes Verhalten bei Mehrfachtreffern - Eindeutigkeit als Datenintegritätsregel prüfen/erzwingen).
Tracelinks: SyRS/SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
## Dokumente & Reporting (DOC)
ID: StRS-DOC-01
Titel: Zentrale Dokumentenablage in Ordnerstruktur
Ebene: StRS
Typ: funktional (Geschäftsziel)
Akteur: Sachbearbeiter (Vertrieb/Verwaltung), Administrator
Vorbedingung: Benutzer ist an c-entron angemeldet und besitzt Zugriff auf einen Ordner (Directory)
Fakt: `DocumentBL.AddFileToDirectory` legt Dokumente in einer Ordnerstruktur (`Directory`) ab, verknüpft Metainformationen (`DocumentMetaInformation`), setzt einen Dokumenttyp-abhängigen Icon-Index (`GetImageIndexForDocumentType`) und aktualisiert die Trefferanzahl des Ordners (`NumDocuments`). Bei Helpdesk-Ordnern wird zusätzlich ein Historieneintrag erzeugt (`HelpdeskHistoryBL.CreateHistoryForDocument`).
Aussage: Das System soll es Sachbearbeitern ermöglichen, beliebige Dateien in einer hierarchischen Ordnerstruktur abzulegen, automatisch nach Dateityp zu kategorisieren (Icon/Typ) und bei fachlichem Bezug (z. B. Helpdesk-Vorgang) automatisch eine Historie zu führen.
Ergebnis: Zentrale, typisierte Dokumentenablage mit Prozessanbindung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:587-648 - Begründung: `AddFileToDirectory` Implementierung inkl. MetaInformations, ImageIndex, Historie.
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/Administration/FileManagement/Document.cs:17-54 - Begründung: Entity-Felder bestätigen Typ/Version/Directory-Modell.
Prüfidee: UI-Test: Datei in Kundenordner hochladen, prüfen ob Icon nach Dateityp korrekt vergeben wird und `NumDocuments` im Elternordner steigt.
Tracelinks: SyRS-DOC-01, SyRS-DOC-02, SyRS-DOC-03, SyRS-DOC-04
Konsolidierung: nein
Status: belegt
---
ID: StRS-DOC-02
Titel: Trennung öffentliche/interne Dokumentation
Ebene: StRS
Typ: funktional (Geschäftsziel)
Akteur: Sachbearbeiter (interne Dokumentation/Wissensdatenbank), Management
Vorbedingung: Benutzer hat Recht `READ_DOCUMENTATION` bzw. `READ_INTERNAL_DOCUMENTATION`
Fakt: `DocumentationBL` verwaltet fachliche „Dokumentationen" (z. B. zu Helpdesk-Vorgängen) mit zwei getrennten Sichtbarkeitsstufen: `PublicDocumentation` (immer sichtbar) und `InternalDocumentation` (wird aus dem Ergebnis entfernt, falls der Benutzer nicht das Recht `READ_INTERNAL_DOCUMENTATION` besitzt — in allen Get-Methoden konsequent per Schleife `documentation.InternalDocumentation = null`).
Aussage: Das System soll bei Wissens-/Vorgangsdokumentationen zwischen einer öffentlichen und einer nur intern sichtbaren Textkomponente unterscheiden und die interne Komponente rechteabhängig aus der Antwort entfernen (nicht nur UI-seitig ausblenden).
Ergebnis: Informationstrennung zwischen kundenseitig sichtbaren und internen Vermerken.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs:27-95 - Begründung: Mehrere GetDocumentation*-Methoden mit identischem Muster (Rechteprüfung + Entfernen von InternalDocumentation).
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/DocumentationArea/Documentation.cs:19-23 - Begründung: Entity-Felder PublicDocumentation/InternalDocumentation.
Prüfidee: Dokumentation mit beiden Feldern anlegen, mit Benutzer ohne READ_INTERNAL_DOCUMENTATION abrufen → InternalDocumentation muss `null` sein, nicht nur UI-verborgen.
Tracelinks: keine direkte SyRS-Verknüpfung (Lücke - im Kandidatenset wurde keine SyRS-Ebene zur Dokumentations-Sichtbarkeit erhoben); fachlich direkt umgesetzt durch SwRS-DOC-05
Konsolidierung: nein
Status: belegt
## Externe Integrationen & Schnittstellen (INT)
ID: StRS-INT-01
Titel: Automatisierter EDI-Belegaustausch mit Distributoren
Ebene: StRS
Typ: funktional
Akteur: Distributoren/Lieferanten (ALSO, Alltron, Komsa, Herweck, ITScope, EGIS), Einkaufsabteilung
Vorbedingung: Lieferant unterstützt elektronischen Belegaustausch (EDI)
Fakt: Das System automatisiert den Austausch von Bestellungen, Auftragsbestätigungen, Lieferscheinen und Rechnungen mit mehreren Distributoren über unterschiedliche EDI-Formate (OpenTrans 2.1, ALSO, ALSO CH, Herweck, Komsa, Alltron, ZUGFeRD).
Aussage: Das System soll den automatisierten, bidirektionalen elektronischen Belegaustausch (Bestellung, Auftragsbestätigung, Lieferschein, Rechnung) mit angebundenen Distributoren unterstützen, unabhängig vom jeweiligen lieferantenspezifischen Datenformat.
Ergebnis: Reduzierter manueller Erfassungsaufwand im Einkauf, schnellere Verfügbarkeit von Bestell- und Lieferstatus.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:754-829 (DownloadStartAsync) - Begründung: zentrale Einstiegsmethode, dispatcht je Lieferantenkonfiguration.
- [SEKUNDÄR] docs/reference/edi/edi-architecture.md:20,108-122 - Begründung: Architekturübersicht inkl. Formattabelle je Lieferant.
Prüfidee: Prüfen, ob für jeden aktiven Lieferanten-EDI-Vertrag ein vollständiger Order→Response→Delivery→Invoice-Zyklus im System nachvollziehbar ist.
Tracelinks: SyRS-INT-01, SyRS-INT-02, SyRS-INT-03, SyRS-INT-04, SyRS-INT-09
Konsolidierung: nein
Status: belegt
---
ID: StRS-INT-02
Titel: Lizenzsteuerung der EDI-Integrationen
Ebene: StRS
Typ: funktional (Lizenzsteuerung)
Akteur: Vertrieb/Lizenzierung, Einkaufsabteilung
Vorbedingung: Kundenvertrag mit entsprechendem Lizenzmodul
Fakt: EDI-Funktionalität ist über drei getrennte Lizenz-GUIDs steuerbar: `EDI_General` (klassische Lieferanten-EDI), `EDI_ITScope`, `EDI_EGIS`. Ohne aktive Lizenz wird der jeweilige Verarbeitungszweig übersprungen.
Aussage: Das System soll die Nutzung der EDI-Anbindung (klassisches EDI, ITScope-Marktplatz, EGIS) getrennt lizenzierbar und pro Mandant aktivierbar/deaktivierbar machen.
Ergebnis: Differenzierte Vermarktung/Paketierung der Integrationsfunktionen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:777,978,1003,1115 - Begründung: `LicenseManager.Instance.HasLicense(LicenseGuids.EDI_*)`-Prüfungen an mehreren Verzweigungspunkten.
Prüfidee: Prüfen, ob in einer SaaS-Neuimplementierung ein äquivalentes Feature-Flag-/Tarifmodell für Integrationen vorgesehen werden soll.
Tracelinks: SyRS-INT-01, SyRS-INT-04
Konsolidierung: nein
Status: belegt
---
ID: StRS-INT-03
Titel: Webservice-Schnittstelle für Partnersysteme
Ebene: StRS
Typ: Schnittstelle
Akteur: Partner-/Drittsysteme, externe Anwendungen
Vorbedingung: Partnersystem verfügt über gültiges Ticket/Zugangsdaten
Fakt: C-ENTRON stellt selbst eine REST-artige Webservice-Schicht bereit (`CentronRestService`/`ICentronRestService`), über die externe Anwendungen per `Request<T>`/`Response<T>`-Konvention (ausschließlich POST, `[Authenticate]`-Attribut, ticketbasierte Anmeldung via `GetLoggedInUserByTicket`) auf Geschäftsobjekte zugreifen können; laut Entwicklerdokumentation auch per WSDL-Service-Reference nutzbar.
Aussage: Das System soll externen Anwendungen/Partnersystemen eine dokumentierte, authentifizierte Webservice-Schnittstelle (Request/Response-Kontrakt) zum lesenden und schreibenden Zugriff auf Geschäftsobjekte bereitstellen.
Ergebnis: C-ENTRON fungiert selbst als Integrationsplattform für Drittsysteme (nicht nur Konsument externer APIs).
Belege:
- [PRIMÄR] docs/guides/services/add-webservice-methods.md:32-66 - Begründung: dokumentierter, im Code verbindlich vorgeschriebener Webservice-Kontrakt (Namenskonvention, Attribute, Signatur).
Prüfidee: Prüfen, welche Authentifizierungsmechanismen (Ticket-Lebensdauer, Rotation) hinter `GetLoggedInUserByTicket` stehen und ob dies für eine SaaS-Neuimplementierung durch OAuth2/OIDC ersetzt werden soll.
Tracelinks: SyRS-INT-08
Konsolidierung: nein
Status: belegt; Authentifizierungsdetails [HYPOTHESE: Ticket-Mechanismus (Lebensdauer, Erneuerung) nicht im gesichteten Code verifiziert]
## CentronNexus (Ticket-/Helpdesk-System) (NEX)
ID: StRS-NEX-01
Titel: Kunden-Ticketerstellung mit optionalem internen Freigabeverfahren
Ebene: StRS
Typ: funktional
Akteur: Kunde (Web-Account), Support-Mitarbeiter
Vorbedingung: Kunde erstellt Ticket über CentronNexus-Weboberfläche (Web-Account-Login).
Fakt: `HelpdeskCustomerBL.SaveNewSimpleTicketWebAccount()` prüft für den Kundenaccount, ob "Freigabewesen" (`CustomerData.CustomerApprovalEnabledSBO`) aktiv ist. Ist es aktiv und der Benutzer kein `CUSTOMERADMINISTRATOR`, wird `ticket.HelpdeskState = null` gesetzt ("make sure the state is reseted, to have a normal flow of rejecting or accepting ticket"); ist Freigabewesen deaktiviert oder der Benutzer Administrator, wird sofort der konfigurierte Default-Status (`AppSettingsConst.HelpdeskAfterOpenDefaultState`) gesetzt. Ein Ticket mit `HelpdeskState == null` erscheint laut Code-Kommentar in `HelpdeskCustomerBL.SaveNewSimpleTicket` (Zeile 128-131) NICHT in der regulären Ticketliste, sondern gilt als rein interne Kundennotiz, bis ein Kunden-IT-Admin sie eskaliert.
Aussage: Das System soll es Kunden ermöglichen, neue Tickets über ein Kundenportal zu erstellen; ist für den Kunden ein internes Freigabeverfahren (Freigabewesen) aktiviert, soll ein neu erstelltes Ticket zunächst ohne sichtbaren Status (interne Vorstufe) angelegt und erst nach interner Freigabe für den Support sichtbar geschaltet werden.
Ergebnis: Zweistufiger Kunden-Ticket-Erstellungsprozess mit optionalem internen Freigabe-Gate.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:466-493 - Freigabewesen-Prüfung in `SaveNewSimpleTicketWebAccount`
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:126-141 - Kommentar/Logik zu HelpdeskState==null in `SaveNewSimpleTicket`
Prüfidee: Kundenkonto mit aktivem Freigabewesen ein Ticket anlegen lassen und prüfen, dass es nicht im Standard-Ticket-Board erscheint, bis ein interner Nutzer es freigibt (Statuszuweisung).
Tracelinks: SyRS-NEX-01
Konsolidierung: nein (clusterübergreifender Hinweis: konkreter Freigabe-Workflow-Schritt evtl. Teil des CRM/Sales-Clusters, dort Rechercheergebnis abgleichen)
Status: belegt; Freigabe-Zielaktion nicht vollständig lokalisiert (siehe HYPOTHESEN-Abschnitt)
---
ID: StRS-NEX-02
Titel: Auslastungsbasierte Ticket-Weiterleitung im Outlook-Add-In
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Outlook-Add-In zeigt Kontakt-/E-Mail-Kontext eines Kunden; Mitarbeiter-Favoritenliste ist gepflegt.
Fakt: `EmployeeFavorites.razor` erlaubt das Markieren von Mitarbeitern als Favoriten (`CentronService.CreateEmployeeFavorits`) und zeigt für jeden (Favoriten-)Mitarbeiter Live-Statistiken (`GetHelpdeskStatisticFromEmployee`: `AllOpenHelpdesks`, `HelpdesksInWork`, `HelpdesksClosedToday`, `NewHelpdesksFromToday`) als gestapelten Fortschrittsbalken an. Über den Button "Weiterleiten" wird das aktuelle Ticket per `CentronService.ForwardHelpdeskV3` an den gewählten Mitarbeiter weitergeleitet, inkl. optionalem Statuswechsel (`NewHelpdeskStateI3D`) gemäß konfigurierten Weiterleitungs-Einstellungen (`HelpdeskAfterForwardDefaultStateI3D`).
Aussage: Das System soll dem Support-Mitarbeiter im Outlook-Add-In eine Übersicht favorisierter Kollegen mit deren aktueller Ticket-Auslastung anzeigen und die direkte Weiterleitung des aktuellen Tickets inkl. automatischem Statuswechsel an einen ausgewählten Kollegen ermöglichen.
Ergebnis: Auslastungsbasierte, komfortable Ticket-Weiterleitung direkt aus Outlook.
Belege:
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/EmployeeFavorites.razor:280-323 - Statistikanzeige (`GetHelpdeskPercentage`, `OnExpandEmployeeAccordianItem`)
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/EmployeeFavorites.razor:366-416 - `ForwardNow` mit `ForwardHelpdeskRequestV3DTO`, `NewHelpdeskStateI3D`
Prüfidee: Ticket an favorisierten Mitarbeiter weiterleiten und prüfen, dass (a) Editorenliste den neuen Mitarbeiter enthält (siehe SwRS-NEX-02/SyRS-NEX-02), (b) Status gemäß konfiguriertem `HelpdeskAfterForwardDefaultStateI3D` gesetzt wird, (c) Outlook-Mail-Entwurf mit Ticketinhalt vorbereitet wird.
Tracelinks: SyRS-NEX-02, SyRS-NEX-05, SyRS-NEX-06, SyRS-NEX-07, SyRS-NEX-11
Konsolidierung: Kandidat: SwRS-NEX-02 (Editor-Zuweisung), SyRS-NEX-02 (Notification), SyRS-NEX-01 und SwRS-NEX-01 (Statuswechsel) - kombiniert in einem UI-Workflow.
Status: belegt
---
ID: StRS-NEX-03
Titel: Annahme-/Ablehnungsworkflow für neue Tickets
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket-Board (ServiceBoard) im Kanban-Modus, neues Ticket wird geöffnet/bearbeitet.
Fakt: Der Enum `HelpdeskAfterOpenAction { Reject, Accept }` im CachedTicketList-Modul deutet auf einen Annahme-/Ablehnungs-Workflow beim Öffnen neuer Tickets im ServiceBoard hin (analog zum in StRS-NEX-01 beschriebenen kundenseitigen Freigabewesen, hier vermutlich support-seitig).
Aussage: Das System soll es dem Support-Mitarbeiter ermöglichen, ein neu eingegangenes Ticket im ServiceBoard explizit anzunehmen oder abzulehnen.
Ergebnis: Annahme-/Ablehnungsschritt als Teil des Ticket-Eingangs-Workflows im Web-Board.
Belege:
- [PRIMÄR] src/nexus/CentronNexus/ServiceBoard/CachedTicketList/Enums/HelpdeskAfterOpenAction.cs:1-7 - Enum-Definition
Prüfidee: Neues Ticket im ServiceBoard öffnen, "Annehmen"/"Ablehnen"-Aktion ausführen und Auswirkung auf Status/Editorenliste dokumentieren.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: HYPOTHESE (nur Enum-Fund, Verwendungskontext nicht verifiziert)
---
ID: StRS-NEX-04
Titel: CentronNexus als eigenständig konfigurierbare Webkomponente
Ebene: StRS
Typ: nicht-funktional
Akteur: Support-Mitarbeiter, Systemadministrator
Vorbedingung: CentronNexus-Web-Anwendung wird betrieben (separater Host `CentronNexus.Host`, konfigurierbar über `CentronNexusSettingsDTO`).
Fakt: `CentronNexusBL` verwaltet zentrale Betriebseinstellungen: `CentronNexusUrl` (Basis-URL der Nexus-Instanz), `ServiceBoardOnlineUrl` (separate URL für das Web-Board, referenziert auch im Outlook-Add-In als Ziel-Link, siehe SyRS-NEX-05/StRS-NEX-02-Kontext `serviceboard/ticket/{I3D}`), sowie `UseNexusForPublicWebForms` (Umschalter, ob öffentliche Webformulare über CentronNexus statt eines Altsystems bedient werden).
Aussage: Das System soll CentronNexus als eigenständig konfigurierbare Web-Anwendung mit eigener Basis-URL betreiben, wobei Systemadministratoren zentral festlegen können, ob öffentliche Web-Formulare (Kundenanfragen) über CentronNexus abgewickelt werden.
Ergebnis: CentronNexus als austauschbare, eigenständig adressierbare Webkomponente im Gesamtsystem CentronERP.
Belege:
- [PRIMÄR] src/backend/Centron.BL/CentronNexus/CentronNexusBL.cs:19-54 - `GetCentronNexusSettings`/`UpdateCentronNexusSettings`
Prüfidee: `UseNexusForPublicWebForms` umschalten und prüfen, dass öffentliche Formulare (z.B. Kontaktformular) danach tatsächlich CentronNexus statt Altsystem ansprechen.
Tracelinks: SyRS-NEX-06
Konsolidierung: nein (clusterübergreifender Hinweis: ggf. mit Web-Konfigurations-Cluster/WebAccountConfig/HostConfig konsolidieren)
Status: belegt
@@ -0,0 +1,331 @@
# Traceability-Tabelle — CentronERP
Konsolidierte Forward-/Backward-Traceability zwischen StRS, SyRS und SwRS, gruppiert nach Analysecluster. Leere Zellen bedeuten: auf dieser Ebene existiert für die Kette keine eigenständig extrahierte Anforderung (dokumentierte Lücke, siehe auch Analysebericht.md).
## Anwendungsarchitektur & Systemrahmen (ARCH)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-ARCH-01 | SyRS-ARCH-02 | SwRS-ARCH-01 | docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md |
| StRS-ARCH-06 | SyRS-ARCH-01 | SwRS-ARCH-02 | docs/reference/architecture/dtos-and-entities.md |
| StRS-ARCH-06 | SyRS-ARCH-01 | SwRS-ARCH-03 | docs/reference/architecture/results-and-responses.md |
| | SyRS-ARCH-10 | SwRS-ARCH-03 | src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs |
| | SyRS-ARCH-05 | SwRS-ARCH-05 | docs/guides/ui/create-module.md |
| | | SwRS-ARCH-04 | src/centron/Centron.WPF.UI/Layout/GridControlLayoutSerializer.cs |
| | | SwRS-ARCH-06 | docs/reference/architecture/stanislaus-secret-api-documentation.md |
| StRS-ARCH-02 | SyRS-ARCH-08 | | src/centron/Centron.WPF.UI/StartupArgs/StartupArgSynchronizer.cs |
| StRS-ARCH-02 | SyRS-ARCH-11 | | src/centron/Centron.WPF.UI/App.xaml.cs |
| StRS-ARCH-02 | SyRS-ARCH-14 | | docs/reference/architecture/tapi.md |
| StRS-ARCH-02 | SyRS-ARCH-17 | | src/centron/Centron.WPF.UI/App.xaml.cs |
| StRS-ARCH-01 | SyRS-ARCH-13 | | src/centron/Centron.WPF.UI/Managers/CentronAnalyticsManager.cs |
| StRS-ARCH-01 | SyRS-ARCH-15 | | docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md |
| StRS-ARCH-03 | SyRS-ARCH-09 | | docs/guides/ui/localization.md |
| StRS-ARCH-05 | SyRS-ARCH-16 | | src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs |
## Sicherheit & Berechtigungen (SEC)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-SEC-01 | SyRS-SEC-01 | SwRS-SEC-03 | src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs |
| StRS-SEC-01 | SyRS-SEC-02 | | src/backend/Centron.BL/Administration/Logins/Auth/ActiveDirectoryAuthenticator.cs |
| StRS-SEC-01 | SyRS-SEC-03 | | src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs |
| StRS-SEC-01 | SyRS-SEC-04 | SwRS-SEC-01 | src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs |
| StRS-SEC-01 | SyRS-SEC-13 | SwRS-SEC-04 | src/backend/Centron.BL/Administration/Logins/WebAccountBL.cs |
| StRS-SEC-01 | SyRS-SEC-14 | SwRS-SEC-03 | src/backend/Centron.BL/Administration/Logins/UsersBL.cs |
| StRS-SEC-01 | SyRS-SEC-15 | | src/backend/Centron.BL/Administration/Logins/UsersBL.cs |
| StRS-SEC-01 | SyRS-SEC-16 | | Negativrecherche (Grep) über src/backend/Centron.BL |
| StRS-SEC-02 | SyRS-SEC-04 | SwRS-SEC-01 | src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs |
| StRS-SEC-02 | | SwRS-SEC-02 | src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/Administration/Rights/UserRightsConst.cs |
| StRS-SEC-03 | | SwRS-SEC-01 | src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (SaveRightGroup/DeleteRightGroup) |
| StRS-SEC-04 | | SwRS-SEC-01 | src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (DeleteRightGroup) |
| StRS-SEC-04 | | SwRS-SEC-02 | src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (GetAssignableAdminRightI3Ds) |
| StRS-SEC-05 | SyRS-SEC-07 | SwRS-SEC-05 | src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorAuthBL.cs |
| StRS-SEC-05 | SyRS-SEC-08 | | src/backend/Centron.BL/Administration/Logins/TwoFactor/EmailTwoFactorValidator.cs |
| StRS-SEC-05 | SyRS-SEC-09 | | src/backend/Centron.BL/Administration/Logins/TwoFactor/RadiusTwoFactorValidator.cs |
| StRS-SEC-06 | SyRS-SEC-10 | | docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md |
| StRS-SEC-07 | SyRS-SEC-11 | | src/backend/Centron.BL/PasswordManager/PasswordManagerBL.cs (GetCustomerAccessDataForExport) |
| StRS-SEC-07 | SyRS-SEC-12 | SwRS-SEC-06 | src/backend/Centron.BL/PasswordManagementArea/PasswordManagementKeywordBL.cs |
| | SyRS-SEC-05 | SwRS-SEC-07 | src/backend/Centron.BL/Administration/Logins/TicketBL.cs |
| | SyRS-SEC-06 | | src/backend/Centron.BL/Administration/Logins/TicketBL.cs (RefreshTicketExpireDate) |
## Stammdaten: Geschäftspartner, Kunden, Mitarbeiter (CRM)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-CRM-01 | SyRS-CRM-03 | SwRS-CRM-02 | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:382-391 |
| StRS-CRM-02 | | SwRS-CRM-08 | src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:856-858 |
| StRS-CRM-02 | | | src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:1152-1276 |
| StRS-CRM-03 | | | src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:34-62 |
| StRS-CRM-04 | | | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99 |
| | SyRS-CRM-01 | SwRS-CRM-03 | src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:225-238 |
| | SyRS-CRM-01 | SwRS-CRM-04 | src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:53-106 |
| | SyRS-CRM-02 | SwRS-CRM-04 | src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:190-220 |
| | SyRS-CRM-04 | | src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs:128-131 |
| | SyRS-CRM-05 | | src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:136-186 |
| | SyRS-CRM-06 | SwRS-CRM-06 | src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:38-55 |
| | SyRS-CRM-07 | | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:234-240 |
| | SyRS-CRM-08 | | src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:134-146 |
| | SyRS-CRM-09 | | src/centron/Centron.WPF.UI/Modules/Finances/Crm/Finance/CrmFinanceView.xaml.cs:30-39 |
| | SyRS-CRM-10 | | src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:310-411 |
| | SyRS-CRM-11 | | src/backend/Centron.BL/CountryArea/CountryBL.cs:190-207 |
| | SyRS-CRM-12 | | src/backend/Centron.BL/BusinessPartner/SearchSupplierBL.cs:84-121 |
| | | SwRS-CRM-01 | src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:39-51 |
| | | SwRS-CRM-05 | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:438-597 |
| | | SwRS-CRM-07 | src/backend/Centron.Entities/Entities/CustomerArea/Address.cs:30 |
| | | SwRS-CRM-09 | src/backend/Centron.BL/Sales/Customers/CustomerDetails/CustomerAncestryBL.cs:33-43 |
| | | SwRS-CRM-10 | src/backend/Centron.BL/EmployeeArea/EmployeeRfidTokenBL.cs:39-57 |
| | | SwRS-CRM-11 | src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:19-24 |
| | | SwRS-CRM-12 | src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:48 |
## Vertrieb & Einkauf (SALES)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-SALES-01 | | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9415-9440 (CheckIfClassificationIsNeeded) |
| StRS-SALES-02 | SyRS-SALES-12 | | src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:589-733,1039-1067 |
| | SyRS-SALES-01 | | src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 |
| | SyRS-SALES-01 | SwRS-SALES-01 | src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:245-281 |
| | SyRS-SALES-01 | SwRS-SALES-02 | src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:233-240 |
| | SyRS-SALES-01 | SwRS-SALES-05 | src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:262-322 |
| | SyRS-SALES-01 | SwRS-SALES-10 | src/backend/Centron.BL/Sales/Receipts/ReceiptCompleteReasonBL.cs:63-76 |
| | SyRS-SALES-01 | SwRS-SALES-13 | src/backend/Centron.BL/Sales/CustomerAssets/Offers/OfferBL.cs:66-81 |
| | SyRS-SALES-02 | | src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:313-314 |
| | SyRS-SALES-02 | SwRS-SALES-04 | src/backend/Centron.BL/Sales/Receipts/DownPayment/DownPaymentBL.cs:82-120 |
| | SyRS-SALES-02 | SwRS-SALES-12 | src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:440-484 |
| | SyRS-SALES-03 | | src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:296-298 |
| | SyRS-SALES-04 | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9258-9276 |
| | SyRS-SALES-05 | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10802-10844 |
| | SyRS-SALES-06 | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:8636-8690 |
| | SyRS-SALES-07 | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9036-9124 |
| | SyRS-SALES-08 | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9393-9413 |
| | SyRS-SALES-09 | SwRS-SALES-03 | src/backend/Centron.BL/Sales/Receipts/ReceiptCartReleaseSystemBL.cs:65-298 |
| | SyRS-SALES-10 | SwRS-SALES-03 | src/backend/Centron.BL/Sales/Receipts/ReceiptCartReleaseSystemBL.cs:193-198,356-381 |
| | SyRS-SALES-11 | | src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderBL.cs:35-140 |
| | SyRS-SALES-13 | | src/backend/Centron.BL/TradePool/TradePoolBL.cs:28-101 |
| | SyRS-SALES-14 | | src/backend/Centron.BL/TradePool/TradePoolBL.cs:147-183 |
| | SyRS-SALES-15 | | src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:480-501 |
| | SyRS-SALES-16 | | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10205-10216 |
| | SyRS-SALES-17 | | src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:549-551 |
| | | SwRS-SALES-06 | src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:513-548 |
| | | SwRS-SALES-07 | src/backend/Centron.BL/Purchasing/SupplierOrderPerBranchBL.cs:24-116 |
| | | SwRS-SALES-08 | src/backend/Centron.BL/ProductMatrix/ProductMatrixBL.cs:165-192 |
| | | SwRS-SALES-09 | src/backend/Centron.BL/Sales/CustomerAssets/Orders/OrderBalanceBL.cs:81-193 |
| | | SwRS-SALES-11 | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:3763-3765 |
## Abrechnung, Fakturierung & Verträge (BILL)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-BILL-01 | SyRS-BILL-06 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156 |
| StRS-BILL-01 | SyRS-BILL-07 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2092-2107 |
| StRS-BILL-01 | SyRS-BILL-08 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2109-2122 |
| StRS-BILL-01 | SyRS-BILL-09 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:64,1033-1043 |
| StRS-BILL-01 | SyRS-BILL-10 | | docs/reference/zugferd-field-mapping.md:355-359 (nur SEKUNDÄR, kein Primärbeleg vorhanden) |
| StRS-BILL-01 | SyRS-BILL-11 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:938-953 |
| StRS-BILL-01 | SyRS-BILL-12 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:803-811,1873-1878 |
| StRS-BILL-01 | SyRS-BILL-17 | | docs/reference/zugferd-field-mapping.md:157-160 (nur SEKUNDÄR, kein Primärbeleg vorhanden) |
| StRS-BILL-01 | SyRS-BILL-19 | | docs/reference/zugferd-feldzuordnung-anwender.md:331 (nur SEKUNDÄR, kein Primärbeleg vorhanden) |
| StRS-BILL-02 | SyRS-BILL-13 | | src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:790-802,2412-2415 |
| StRS-BILL-02 | SyRS-BILL-14 | | src/backend/Centron.Entities/Entities/Sales/CustomerAssets/Contracts/ContractArticleReferenzes.cs:27-39 |
| StRS-BILL-02 | SyRS-BILL-15 | | src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs:149-221 |
| StRS-BILL-03 | SyRS-BILL-16 | SwRS-BILL-01 | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 |
| StRS-BILL-04 | SyRS-BILL-01 | | src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 |
| StRS-BILL-04 | SyRS-BILL-02 | | src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:157-186 |
| StRS-BILL-04 | SyRS-BILL-03 | | src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:86-141 |
| StRS-BILL-04 | SyRS-BILL-04 | SwRS-BILL-02 | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:4936-4951 |
| StRS-BILL-04 | SyRS-BILL-05 | | src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs:62-134 |
| StRS-BILL-04 | SyRS-BILL-18 | SwRS-BILL-05 | docs/reference/receipts/receipts-backend-architecture.md:147-204 |
| StRS-BILL-04 | SyRS-BILL-20 | | src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:170-172,236-251 |
| | | SwRS-BILL-03 | docs/reference/receipts/actionprice-system.md:196-212,306-312 |
| | | SwRS-BILL-04 | src/centron/Centron.WPF.UI/Modules/Warehousing/ArticleManagement/OpenDialog/ActionPrice/AddActionPriceViewModel.cs:69-79 |
| | | SwRS-BILL-06 | docs/reference/receipts/receipt-search-architecture.md:154-190 |
## Zeiterfassung, Projekte & Tickets (intern) (TIME)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-TIME-01 | SyRS-TIME-03 | | Commit baa9e7bd9b; src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingSettingsPageViewModel.cs:195-243,440-467,563-587 |
| StRS-TIME-01 | SyRS-TIME-04 | | src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:734-758,775-776,984-990 |
| StRS-TIME-01 | SyRS-TIME-05 | SwRS-TIME-08 | src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:173-341 |
| StRS-TIME-01 | SyRS-TIME-06 | | src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:390-461 |
| StRS-TIME-01 | SyRS-TIME-09 | | src/backend/Centron.BL/Sales/Support/HelpdeskTimerArticleBookingBL.cs:105-173,314-356 |
| | SyRS-TIME-01 | SwRS-TIME-01 | src/backend/Centron.Entities/Entities/Sales/Support/HelpdeskTimerArea/HelpdeskTimer.cs:11-62 |
| | SyRS-TIME-01 | SwRS-TIME-02 | src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:353-407 |
| | SyRS-TIME-01 | SwRS-TIME-03 | src/backend/Centron.BL/WebServices/Sales/Support/HelpdeskTimerWebServiceBL.cs:327-346 |
| | SyRS-TIME-01 | SwRS-TIME-04 | src/backend/Centron.BL/Sales/CustomerAssets/TimerBilling/TimerBillingBL.cs:482-483 |
| | SyRS-TIME-02 | | src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:554-602 |
| | SyRS-TIME-07 | | src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:421-466 |
| | SyRS-TIME-08 | SwRS-TIME-07 | src/backend/Centron.BL/DataExchange/Connectors/DocBeeTicketTimerBL.cs:70-145,111-177,411-550 |
| | SyRS-TIME-10 | SwRS-TIME-15 | src/backend/Centron.BL/MyDay/MyDayBL.cs:417-468 |
| | SyRS-TIME-11 | | src/backend/Centron.BL/Sales/Calendar/ScheduleBL.cs:2379-2508 |
| | SyRS-TIME-12 | | src/backend/Centron.BL/Sales/Calendar/ScheduleBL.cs:362-417 |
| | SyRS-TIME-13 | | src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskState.cs:6-15 |
| | SyRS-TIME-14 | | src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs:120-157,200-362 |
| | SyRS-TIME-15 | SwRS-TIME-14 | src/backend/Centron.BL/TaskManager/TaskManagementTaskBL.cs:673-715 |
| | SyRS-TIME-16 | | src/backend/Centron.BL/TaskManager/ActionHandler/TaskManagementHelpdeskActionHandler.cs:50-58 |
| | SyRS-TIME-17 | SwRS-TIME-15 | src/backend/Centron.BL/MyDay/MyDayNotificationsBL.cs:39-280 |
| | | SwRS-TIME-05 | src/backend/Centron.BL/Sales/Support/HelpdeskTimerSignatureBL.cs:31-65,132-206 |
| | | SwRS-TIME-06 | src/backend/Centron.BL/Sales/Support/HelpdeskTimerLogBL.cs:23-237 |
| | | SwRS-TIME-09 | src/backend/Centron.Entities/Entities/TicketProjects/TicketProject.cs:5-19 |
| | | SwRS-TIME-10 | src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:79-105,225-237 |
| | | SwRS-TIME-11 | src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:38-58 |
| | | SwRS-TIME-12 | src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:122-135,193-223 |
| StRS-TIME-02 | | | src/backend/Centron.BL/AppointmentRequests/AppointmentRequestBL.cs:29-114 |
| StRS-TIME-03 | | SwRS-TIME-13 | src/backend/Centron.BL/Projects/ProjectBL.cs:1-36 |
## Lager, Logistik & Produktion (LOG)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-LOG-01 | SyRS-LOG-08 | | src/backend/Centron.BL/Warehousing/Commissions/PartialCommissionOrderBL.cs:304-324 |
| StRS-LOG-02 | SyRS-LOG-11 | SwRS-LOG-09 | src/backend/Centron.BL/Warehousing/ArticleProduction/ArticleProductionBL.cs:457-506 |
| StRS-LOG-02 | | SwRS-LOG-10 | src/backend/Centron.BL/Production/ProductionBL.cs:23-301 |
| StRS-LOG-03 | | | src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:139-158 |
| | SyRS-LOG-01 | | src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:55-75 |
| | SyRS-LOG-02 | | src/webservice/Centron.WebServices.Core/Entities/Warehousing/InventoryManagement/InventoryState.cs:6-18 |
| | SyRS-LOG-03 | | src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:75-109 |
| | SyRS-LOG-04 | SwRS-LOG-01 | src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:379-399 |
| | SyRS-LOG-04 | SwRS-LOG-06 | src/backend/Centron.BL/Warehousing/ArticleBL.cs:1536-1549 |
| | SyRS-LOG-04 | SwRS-LOG-07 | src/backend/Centron.BL/Warehousing/ArticleBL.cs:1553-1559 |
| | SyRS-LOG-05 | SwRS-LOG-05 | src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:797-944 |
| | SyRS-LOG-06 | | src/backend/Centron.BL/Warehousing/ArticleBL.cs:108-121 |
| | SyRS-LOG-07 | SwRS-LOG-04 | src/backend/Centron.Interfaces/Warehousing/BarcodeState.cs:6-35 |
| | SyRS-LOG-07 | SwRS-LOG-08 | src/backend/Centron.BL/Warehousing/BarcodeBL.cs:73-120 |
| | SyRS-LOG-09 | | src/backend/Centron.BL/Warehousing/Commissions/OrderCommissionBL.cs:202-385 |
| | SyRS-LOG-10 | | src/backend/Centron.BL/Warehousing/Commissions/OrderCommissionBL.cs:429-441 |
| | SyRS-LOG-12 | | src/backend/Centron.BL/Devices/AccountDeviceBL.cs:42-107 |
| | SyRS-LOG-13 | | src/backend/Centron.BL/Devices/AccountDeviceBL.cs:109-174 |
| | SyRS-LOG-14 | | src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:133-151 |
| | SyRS-LOG-15 | | src/apis/Centron.Api.Gls (Projektverzeichnis) |
| | | SwRS-LOG-02 | src/backend/Centron.BL/Warehousing/StockManagement/ArticleStockBL.cs:74-149 |
| | | SwRS-LOG-03 | src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:82-110 |
| | | SwRS-LOG-11 | src/backend/Centron.BL/Warehousing/StockManagement/StoragePlaceBL.cs:35-59 |
| | | SwRS-LOG-12 | src/backend/Centron.BL/Warehousing/BarcodeConditionBL.cs:20-80 |
## Administration, Systemkonfiguration & Kommunikation (ADM)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-01 | src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:47-65 |
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-02 | src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs:14 |
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-03 | src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:106-152 |
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-04 | src/backend/Centron.BL/Administration/Settings/SettingsCollection.cs:106-123 |
| StRS-ADM-02 | | SwRS-ADM-05 | src/backend/Centron.BL/Modules/ModuleBL.cs:22-42 |
| StRS-ADM-02 | | SwRS-ADM-06 | src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:26-83 |
| | SyRS-ADM-02 | SwRS-ADM-07 | src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs:79-121 |
| | SyRS-ADM-02 | SwRS-ADM-08 | src/backend/Centron.BL/Notifications/UserNotificationBL.cs:41-117 |
| StRS-ADM-03 | SyRS-ADM-03 | SwRS-ADM-09 | src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:160 |
| StRS-ADM-03 | | SwRS-ADM-10 | src/backend/Centron.BL/Mail/MailSettingsBL.cs:110-227 |
| StRS-ADM-03 | | SwRS-ADM-11 | src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:218-266 |
| StRS-ADM-03 | | SwRS-ADM-12 | src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:151-159 |
| StRS-ADM-03 | SyRS-ADM-03 | | src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 |
| StRS-ADM-03 | | SwRS-ADM-17 | src/backend/Centron.BL/Mail/Blacklist/DomainBlacklistBL.cs:15-36 |
| StRS-ADM-03 | | SwRS-ADM-18 | src/backend/Centron.BL/Mail/MailSettingsBL.cs:233-270 |
| StRS-ADM-04 | | | src/backend/Centron.BL/Mail/MailSignatureBL.cs:111-182 |
| StRS-ADM-05 | | | src/backend/Centron.BL/Administration/Company/MandatorBL.cs:19-125 |
| | | SwRS-ADM-13 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:248-317 |
| | | SwRS-ADM-14 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:133-156 |
| | | SwRS-ADM-15 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:531-1037 |
| | | SwRS-ADM-16 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:1049-1061 |
| | SyRS-ADM-04 | SwRS-ADM-19 | src/backend/Centron.BL/MailScanner/MailScannerBL.cs:57-72 |
| | SyRS-ADM-04 | SwRS-ADM-10 | src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:78-110 |
| | SyRS-ADM-05 | | src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:20-33 |
| | SyRS-ADM-06 | | src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 |
## Dokumente & Reporting (DOC)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-DOC-01 | SyRS-DOC-01 | SwRS-DOC-01 | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:538-585 |
| | SyRS-DOC-05 | SwRS-DOC-02 | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:74-92 |
| StRS-DOC-01 | | SwRS-DOC-03 | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:196-234 |
| StRS-DOC-01 | | SwRS-DOC-04 | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:680-686 |
| StRS-DOC-02 | | SwRS-DOC-05 | src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs:317-347 |
| | SyRS-DOC-05 | SwRS-DOC-06 | src/backend/Centron.BL/ReportEngine/PdfStategy/PdfStrategies.cs:23-157 |
| | SyRS-DOC-06 | SwRS-DOC-06 | src/backend/Centron.BL/ReportEngine/PdfStategy/PdfStrategies.cs:23-157 |
| | SyRS-DOC-05 | SwRS-DOC-07 | src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:969-985 |
| | SyRS-DOC-09 | SwRS-DOC-08 | src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1172-1249 |
| | SyRS-DOC-07 | SwRS-DOC-09 | src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:75-155 |
| | SyRS-DOC-07 | SwRS-DOC-10 | src/backend/Centron.BL/Core/ReplacementBL.cs:39-96 |
| | SyRS-DOC-07 | SwRS-DOC-11 | src/backend/Centron.BL/TextModuleArea/SalutationAndAgreementReplacementBL.cs:40-215 |
| | SyRS-DOC-07 | SwRS-DOC-12 | src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:510-529 |
| | SyRS-DOC-05 | SwRS-DOC-13 | src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1055-1075 |
| StRS-DOC-01 | SyRS-DOC-02 | | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:425-536 |
| StRS-DOC-01 | SyRS-DOC-03 | | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:1122-1199 |
| StRS-DOC-01 | SyRS-DOC-04 | | src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:953-1118 |
| | SyRS-DOC-08 | | Centron.Api.docuFORM/DocuFormRestApiClient.cs:1-131 |
## Externe Integrationen & Schnittstellen (INT)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-INT-01 | SyRS-INT-01 | SwRS-INT-01 | src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:56-77,177-228 |
| StRS-INT-01 | SyRS-INT-01 | SwRS-INT-02 | docs/reference/edi/edi-import-rules.md:125-143 |
| StRS-INT-01 | SyRS-INT-01 | SwRS-INT-03 | docs/reference/edi/edi-import-rules.md:67-91 |
| StRS-INT-01 | SyRS-INT-01 | SwRS-INT-04 | src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:716-725 |
| StRS-INT-01 | SyRS-INT-01 | SwRS-INT-18 | src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:305-361 |
| StRS-INT-02 | SyRS-INT-01 | | src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:777 |
| StRS-INT-01 | SyRS-INT-02 | | src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:786,797,801,894-917 |
| StRS-INT-01 | SyRS-INT-03 | | src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.Also.cs:38 |
| StRS-INT-01 | SyRS-INT-04 | SwRS-INT-05 | src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:374-402 |
| StRS-INT-02 | SyRS-INT-04 | SwRS-INT-14 | src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs:36-49 |
| | SyRS-INT-05 | | src/backend/Centron.BL/DataExchange/PaymentTransactions/PaymentTransactionBL.cs:56-66 |
| | SyRS-INT-06 | | src/backend/Centron.BL/DataExchange/PaymentTransactions/PaymentTransactionBL.cs:233-288 |
| | SyRS-INT-07 | SwRS-INT-09 | src/apis/Centron.APIs.FinAPI/FinApiClient.cs:266-292,332-367 |
| StRS-INT-03 | SyRS-INT-08 | | docs/guides/services/web-service-on-linux.md:15-16,39-58,66-80 |
| StRS-INT-01 | SyRS-INT-09 | SwRS-INT-06 | src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:413-435,492-524 |
| StRS-INT-01 | | SwRS-INT-07 | src/backend/Centron.BL/EDI/Zugferd/ZUGFeRD_BL.cs:38-59 |
| StRS-INT-01 | | SwRS-INT-08 | src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs:20-77 |
| StRS-INT-01 | | SwRS-INT-16 | src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:563-579 |
| StRS-INT-03 | | SwRS-INT-17 | src/backend/Centron.BL/DataExchange/Connectors/WebHookClient.cs:15-37,47-106 |
| | | SwRS-INT-10 | src/apis/Centron.Api.Gls/CentronGlsConsts.cs:5-17 |
| | | SwRS-INT-11 | src/apis/Centron.Api.Gls/CentronGlsLogic.cs:60-91 |
| | | SwRS-INT-12 | src/apis/Centron.Api.Shipcloud/CentronShipcloudLogic.cs:14-28,66-106 |
| | | SwRS-INT-13 | src/apis/Centron.APIs.CopDataAccess/CopApi.cs:32-81,109-138,170-200 |
| | | SwRS-INT-15 | src/apis/Centron.APIs.IcecatDataAccess/IcecatApi.cs:14-33 |
| | | SwRS-INT-19 | src/backend/Centron.BL/DataExchange/GfkExport/GfkExportBL.cs:1-60 |
## CentronNexus (Ticket-/Helpdesk-System) (NEX)
| StRS-ID | SyRS-ID | SwRS-ID | Artefaktbeleg |
|---|---|---|---|
| StRS-NEX-01 | SyRS-NEX-01 | SwRS-NEX-09 | src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:466-493 |
| StRS-NEX-01 | SyRS-NEX-01 | SwRS-NEX-01 | src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:558-609 |
| StRS-NEX-01 | SyRS-NEX-08 | SwRS-NEX-08 | src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:140-231 |
| StRS-NEX-02 | SyRS-NEX-02 | SwRS-NEX-02 | src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:133-174 |
| StRS-NEX-02 | SyRS-NEX-02 | SwRS-NEX-03 | src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:253-318 |
| StRS-NEX-02 | SyRS-NEX-05 | | src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:311-337,368-411 |
| StRS-NEX-02 | SyRS-NEX-06 | | src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:450-550 |
| StRS-NEX-02 | SyRS-NEX-07 | | src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:766-787 |
| StRS-NEX-02 | SyRS-NEX-11 | | src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:50-57,218-225,844-847 |
| StRS-NEX-04 | SyRS-NEX-06 | | src/backend/Centron.BL/CentronNexus/CentronNexusBL.cs:19-54 |
| StRS-NEX-03 | | | src/nexus/CentronNexus/ServiceBoard/CachedTicketList/Enums/HelpdeskAfterOpenAction.cs:1-7 |
| | SyRS-NEX-02 | SwRS-NEX-04 | src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:320-383 |
| | SyRS-NEX-02 | SwRS-NEX-06 | src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:109-111,238-256 |
| | SyRS-NEX-04 | SwRS-NEX-05 | src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:780-827 |
| | SyRS-NEX-04 | SwRS-NEX-01 | src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:558-609 |
| | SyRS-NEX-03 | | src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:385-393 |
| | SyRS-NEX-09 | | src/backend/Centron.Entities/Entities/ExternalHelpdesk/ExternalHelpdeskConfiguration.cs:1-11 |
| | SyRS-NEX-10 | | src/backend/Centron.BL/NexusTicketViews/NexusTicketViewBL.cs:121-235 |
| | | SwRS-NEX-07 | docs/features/automatic-helpdesk-creation-templates.md:159-172 |
| | | SwRS-NEX-10 | src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:966-1004 |
@@ -0,0 +1,564 @@
# RRE Rohbefunde - Cluster ADM (Administration, Systemkonfiguration & Kommunikation)
Projekt: CentronERP (c-entron ERP-Suite)
Cluster-Scope: Systemeinstellungen, Mandanten-/Systemverwaltung, Customizing, Modulverwaltung, Mail/Mailings/MailScanner, Benachrichtigungen
Agent: RRE-Recherche-Agent ADM
Hinweis: Rohbefunde für Konsolidierung, keine finalen Anforderungs-IDs.
---
### Kandidat ADM-01
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator
Vorbedingung: Ein Setting soll gelesen oder geschrieben werden.
Fakt: Das System verwaltet Anwendungseinstellungen in zwei getrennten Tabellen/Enum-Familien: der Legacy-Tabelle `Stammdat` (Zugriff über `AppSettingsConst`) und der aktuellen Tabelle `ApplicationSettings` (Zugriff über `ApplicationSettingID`). `AppSettingsBL.GetSettings`/`GetSettingsForUpdate` akzeptieren ausschließlich Werte dieser beiden Enum-Typen und werfen sonst eine Exception ("Invalid settings type").
Aussage: Das System soll Konfigurationswerte konsistent über genau zwei unterscheidbare Einstellungs-Namensräume (Legacy und aktuell) referenzieren und beim Zugriff typsicher zwischen beiden unterscheiden.
Ergebnis: Zugriff auf eine unbekannte/fremde Einstellungs-ID führt zu einer Exception statt eines stillen Fehlers.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:47-65 (GetSettings) - Begründung: Zeigt Typprüfung und Exception "Invalid settings type".
- [SEKUNDÄR] docs/guides/development/settings-management.md:7-31 - Begründung: Beschreibt explizit die Dual-Table-Architektur und dass neue Einstellungen nur in ApplicationSettings angelegt werden sollen.
Prüfidee: Unit-Test: GetSettings mit gemischter Liste aus AppSettingsConst und ApplicationSettingID prüfen; GetSettings mit anderem Objekttyp muss Exception werfen.
Konsolidierungshinweis: Basis für ADM-02, ADM-03, ADM-04.
Status: belegt
---
### Kandidat ADM-02
Ebene: SwRS
Typ: funktional
Akteur: Entwickler/Systemadministrator (Customizing)
Vorbedingung: Eine neue Systemeinstellung soll eingeführt werden.
Fakt: Neue Einstellungen erhalten eine fortlaufende numerische ID aus einem im Quellcode gepflegten Kommentar ("Next Centron Settings ID"), aktuell Wert 10471 in `ApplicationSettingID.cs` Zeile 14. IDs ab 50000 ("Riverbird") sind für ein anderes Produkt reserviert und werden von c-entron.NET nicht verwendet.
Aussage: Das System soll für jede Systemeinstellung eine eindeutige, fortlaufend vergebene numerische Kennung besitzen, die produktübergreifende ID-Bereiche (c-entron vs. Riverbird) getrennt hält.
Ergebnis: Eindeutige Zuordnung Setting-ID zu Bedeutung; Namensraum-Trennung zwischen Produktlinien.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs:14 - Begründung: Aktueller Zähler "Next Centron Settings ID : 10471".
- [SEKUNDÄR] docs/guides/development/settings-management.md:33-47 - Begründung: Beschreibt Ablaufprozess für ID-Vergabe und Riverbird-Reservierung.
Prüfidee: Prüfen ob je vergebener ID genau eine Beschreibung in ApplicationSettingDefinitions existiert (Konsistenzcheck als Build-Test denkbar).
Konsolidierungshinweis: Ergänzt ADM-01.
Status: belegt
---
### Kandidat ADM-03
Ebene: SwRS
Typ: funktional
Akteur: System (technisch)
Vorbedingung: Eine ApplicationSetting-ID wird erstmals angefragt, aber es existiert noch kein Datensatz.
Fakt: `AppSettingsBL.LoadNewSettingsOptimized` legt für angefragte `ApplicationSettingID`-Werte, die weder im Session-Cache noch in der DB vorhanden sind, automatisch einen neuen `ApplicationSetting`-Datensatz mit leerer Beschreibung aus `ApplicationSettingDefinitions.Instance.GetApplicationSettingDescription(...)` an und speichert ihn in der Session.
Aussage: Das System soll beim ersten Zugriff auf eine noch nicht existierende Einstellung automatisch einen Standard-Datensatz mit Beschreibungstext anlegen, ohne dass ein expliziter Administrations-Schritt nötig ist.
Ergebnis: Keine Null-Referenzfehler bei neu eingeführten Settings; Selbstheilung des Datenbestands.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:106-152 (LoadNewSettingsOptimized, GetDefaultEmptyInstance) - Begründung: Zeigt Anlage-auf-Anfrage-Logik inkl. Session-Cache-Optimierung.
Prüfidee: Test: GetSettings mit einer neuen, noch nie gespeicherten ApplicationSettingID aufrufen und prüfen, dass ein Datensatz mit Default-Werten entsteht.
Konsolidierungshinweis: Ergänzt ADM-01.
Status: belegt
---
### Kandidat ADM-04
Ebene: SwRS
Typ: funktional
Akteur: Entwickler (API-Konsument)
Vorbedingung: Ein Setting-Wert soll gelesen werden, evtl. ohne dass ein Datensatz existiert.
Fakt: `SettingsCollection` bietet typisierte Getter (`GetBool`, `GetString`, `GetInt`, `GetLargeString`, `GetDecimal`, `GetDouble`, `GetDateTime`, `GetEnum<T>`) mit optionalem Default-Wert; bei Enum-Werten wird geprüft, ob der gespeicherte Int-Wert überhaupt im Enum definiert ist (`Enum.IsDefined`), sonst wird der übergebene Default zurückgegeben statt eines ungültigen Enum-Werts.
Aussage: Das System soll beim Lesen von Einstellungen stets einen typsicheren Wert mit definiertem Fallback liefern und ungültige/undefinierte Enum-Rohwerte automatisch auf den Standardwert abbilden.
Ergebnis: Robuste Konfigurationsauswertung auch bei inkonsistenten/veralteten Datenbankwerten (z. B. nach Enum-Änderungen).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/SettingsCollection.cs:106-123 (GetEnum<T>, GetEnumOrDefault) - Begründung: Zeigt Validierung per Enum.IsDefined mit Fallback auf Default.
Prüfidee: Test: In DB einen Enum-Setting-Wert außerhalb des gültigen Bereichs speichern (z.B. -1) und prüfen, dass GetEnum<T> den übergebenen Default zurückgibt statt zu werfen.
Konsolidierungshinweis: Ergänzt ADM-01.
Status: belegt
---
### Kandidat ADM-05
Ebene: StRS
Typ: nicht-funktional (Architekturprinzip)
Akteur: Systemadministrator, IT-Verantwortlicher
Vorbedingung: Client-Anwendung möchte Einstellungen lesen/schreiben.
Fakt: Laut Entwicklerdokumentation greift der Client "nie direkt" auf die Settings-Tabellen zu; stattdessen existieren pro fachlichem Bereich "Group Setting Classes", die Settings laden, typisiert kapseln und über dedizierte REST-API-Methoden (POST) bereitstellen (Beispiel `ReceiptWebServiceBL.GetReceiptInvoiceSettings`/`SaveReceiptInvoiceSettings`).
Aussage: Das System soll Systemkonfiguration ausschließlich über eine serverseitige Business-Logic-Schicht mit klar definierten, fachlich gruppierten DTOs bereitstellen und den direkten Tabellenzugriff durch Clients unterbinden.
Ergebnis: Zentrale, versionierbare Konfigurationsschnittstelle als Grundlage für eine künftige Web-/SaaS-API.
Belege:
- [SEKUNDÄR] docs/guides/development/settings-management.md:63-114 - Begründung: Beschreibt explizit "The client never accesses settings tables directly" sowie Group-Setting-Class-Pattern mit Beispielcode.
- [KONTEXT] src/backend/Centron.BL/Administration/Settings/AppSettingsGroupBL.cs:1864-1887 - Begründung: Konkretes Beispiel eines Group-Setting-Zugriffs (CentronNotifications).
Prüfidee: Architekturreview: Prüfen, ob WPF-Client tatsächlich nur über WebService-DTOs auf Settings zugreift (keine direkten SQL/DAO-Aufrufe aus UI-Schicht).
Konsolidierungshinweis: Grundprinzip für die SaaS-Neuimplementierung (Config-Service-Schnitt).
Status: belegt
---
### Kandidat ADM-06
Ebene: SyRS
Typ: Schnittstelle
Akteur: Client-Anwendung (WPF, Web, Add-Ins)
Vorbedingung: Einstellungen sollen über die Web-Service-Schnittstelle abgerufen/gespeichert werden.
Fakt: Laut Konvention müssen alle Setting-bezogenen API-Methoden HTTP POST verwenden (`[WebInvoke(Method = "POST", ...)]`); Get-Methoden liefern ein Settings-DTO, Save-Methoden nehmen ein DTO entgegen.
Aussage: Das System soll für sämtliche Konfigurationsabfragen und -änderungen ausschließlich POST-basierte Endpunkte mit strukturierten DTOs anbieten (keine GET-Query-Parameter für Konfigurationsdaten).
Ergebnis: Einheitliches, erweiterbares API-Muster für Konfigurationsdaten.
Belege:
- [SEKUNDÄR] docs/guides/development/settings-management.md:116-135 - Begründung: Explizite API-Pattern-Vorgabe inkl. Codebeispiel.
Prüfidee: Stichprobenprüfung der ICentronRestService.Administration.cs Interface-Definitionen auf WebInvoke-Method-Attribute.
Konsolidierungshinweis: Ergänzt ADM-05.
Status: belegt
---
### Kandidat ADM-07
Ebene: SwRS
Typ: funktional
Akteur: System (Startup/Migration)
Vorbedingung: Anwendung startet oder Modulliste wird synchronisiert.
Fakt: `ModuleBL.DoCreateMissingInternalModulesInDB` gleicht eine im Code definierte Liste von `ModuleClass` (ModuleGuid, ModuleName, Category) gegen als „intern" markierte `Module`-Datensätze in der DB ab (Vergleich der GUID case-insensitive) und legt für jedes im Code aber nicht in der DB vorhandene Modul automatisch einen neuen `Module`-Datensatz mit zugehöriger Kategorie an.
Aussage: Das System soll interne Anwendungsmodule anhand einer im Code gepflegten Modulliste automatisch mit der Datenbank synchronisieren, sodass neue Module ohne manuellen Administrationsschritt sichtbar werden.
Ergebnis: Modulverwaltung bleibt auch nach Software-Updates konsistent ohne manuelle DB-Pflege.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleBL.cs:22-42 (DoCreateMissingInternalModulesInDB) - Begründung: Zeigt GUID-basierten Abgleich und automatisches Anlegen fehlender Module.
Prüfidee: Test: Neues ModuleClass-Objekt mit unbekannter GUID übergeben, prüfen dass genau ein neuer Module-Datensatz inkl. Kategorie entsteht.
Konsolidierungshinweis: Zusammenhang mit ADM-08 (Kategorien).
Status: belegt
---
### Kandidat ADM-08
Ebene: SwRS
Typ: funktional
Akteur: System (Startup/Migration)
Vorbedingung: Interne Modulkategorien müssen in der DB existieren.
Fakt: `ModuleCategoryBL.CreateInternalCategories` definiert eine feste Liste interner `CentronModuleCategory`-Werte (u. a. Purchasing, Sales, Billing, Administration, BaseData, DataExchange, Controlling, Logistic, MyCentron, PasswordManager, NexowareConnect) und legt fehlende Kategorien mit deutschem Anzeigetext an (z. B. "Einkauf", "Vertrieb", "Abrechnung"). `DoGetDisplayTextForCategory` wirft eine `ArgumentOutOfRangeException`, falls für eine Kategorie kein Anzeigetext hinterlegt ist.
Aussage: Das System soll eine feste Menge interner Modulkategorien mit lokalisiertem Anzeigetext verwalten und beim Fehlen eines Anzeigetexts einen harten Fehler erzeugen statt eine leere/inkonsistente Kategorie anzulegen.
Ergebnis: Konsistente, vollständig übersetzte Kategorie-Struktur; Entwicklerfehler (vergessene Übersetzung) werden früh sichtbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:26-83 (CreateInternalCategories, DoGetDisplayTextForCategory) - Begründung: Enthält vollständige Kategorienliste, deutsche Anzeigetexte und Exception bei fehlender Zuordnung.
Prüfidee: Testfall: Neue CentronModuleCategory ohne case in DoGetDisplayTextForCategory hinzufügen, prüfen dass ArgumentOutOfRangeException geworfen wird ("Unknown category: ...").
Konsolidierungshinweis: Ergänzt ADM-07.
Status: belegt
---
### Kandidat ADM-09
Ebene: StRS
Typ: funktional
Akteur: Sachbearbeiter/Endbenutzer
Vorbedingung: Benutzer ist angemeldet und möchte häufig genutzte Module schnell erreichen.
Fakt: Benutzer können Module individuell als Favoriten markieren (`ModuleFavorite` verknüpft `Employee` und `Module`); die Anzeige erfolgt gruppiert nach Modulkategorie (`GetModuleFavoritesGroupedByCategory`). Beim Speichern der Favoriten wird bei technischem Fehler die Meldung "Die Favoriten konnten nicht gespeichert werden." zurückgegeben, beim Umschalten eines einzelnen Favoriten "Der Favorite konnte nicht geändert werden.".
Aussage: Das System soll es jedem Benutzer ermöglichen, Module individuell als Favoriten zu markieren und diese nach Kategorie gruppiert anzuzeigen; Fehler beim Speichern sollen dem Benutzer mit einer verständlichen Meldung angezeigt werden.
Ergebnis: Personalisierte, schnellere Navigation im Modulmenü je Mitarbeiter.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleBL.cs:44-81 (GetModuleFavorites, SaveModuleFavorites, UpdateModuleFavorite) - Begründung: Zeigt Favoriten-Datenmodell (pro Employee) und Fehlermeldungstexte.
- [SEKUNDÄR] src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:88-113 (GetModuleFavoritesGroupedByCategory) - Begründung: Zeigt Gruppierungslogik nach Kategorie für die Anzeige.
Prüfidee: UI-/API-Test: Favorit setzen, Session neu laden, prüfen ob Favorit weiterhin gruppiert nach Kategorie erscheint; Fehlerfall (DB nicht erreichbar) prüfen auf Fehlermeldungstext.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-10
Ebene: SyRS
Typ: nicht-funktional (Betrieb/Datenhaltung)
Akteur: Systemadministrator
Vorbedingung: Systembenachrichtigungen (CentronNotification, z. B. Batch-/Schnittstellenprotokolle) sammeln sich über Zeit an.
Fakt: `CentronNotificationsBL.CleanupCentronNotifications` löscht Benachrichtigungen automatisch, sofern die Einstellung `CentronNotificationsDeleteAutomatically` aktiv ist; die Aufbewahrungsdauer wird über `CentronNotificationsDeleteAfterXTime` (Default 14 Tage, DTO-Feld `DeleteAfterDays`) konfiguriert. Der Löschzeitpunkt wird als `DateTime.Now.AddDays(-DeleteAfterDays)` berechnet.
Aussage: Das System soll automatisiertes, konfigurierbares Aufräumen von Systembenachrichtigungen nach einer administrierbaren Aufbewahrungsfrist unterstützen, mit einem sinnvollen Standardwert (14 Tage), falls kein Wert gepflegt ist.
Ergebnis: Begrenztes Datenwachstum im Benachrichtigungs-/Protokollbestand ohne manuelle Administration.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs:53-68 (CleanupCentronNotifications) - Begründung: Zeigt bedingte automatische Löschung und Datumsberechnung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/AppSettingsGroupBL.cs:1864-1887 (GetCentronNotificationsSettings/UpdateCentronNotifications) - Begründung: Zeigt Default-Wert 14 Tage und die konkreten ApplicationSettingID-Felder.
Prüfidee: Integrationstest: DeleteAutomatically=true, DeleteAfterDays=5 setzen, Notification mit CreatedDate vor 6 Tagen anlegen, Cleanup ausführen, prüfen dass Eintrag gelöscht wird und neuere Einträge erhalten bleiben.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-11
Ebene: SwRS
Typ: funktional
Akteur: Systemadministrator
Vorbedingung: Systembenachrichtigungen sollen gefiltert/durchsucht werden (z. B. Fehleranalyse).
Fakt: `CentronNotificationsBL.CreateFilterExpression` erlaubt Filterung nach: nur Fehler (`LogKind.Error`/`LogKind.PartlyError`), Datum-von/-bis, konkretem `LogKind`, `ObjectKind`, `ShortSign` (Kurzzeichen) und `ObjectI3D`. `LogKind` kennt die Werte Successful, PartlyError, Error.
Aussage: Das System soll Systembenachrichtigungen nach Status (erfolgreich/teilweise fehlerhaft/fehlerhaft), Zeitraum, Objektbezug und Bearbeiterkürzel filterbar machen.
Ergebnis: Gezielte Fehleranalyse und Auditing für Administratoren möglich.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs:79-121 (CreateFilterExpression) - Begründung: Vollständige Filterkriterien.
- [PRIMÄR] src/webservice/Centron.WebServices.Core/Entities/Notifications/LogKind.cs:1-9 - Begründung: Enum-Definition der drei Status.
Prüfidee: API-Test: Filter mit OnlyErrors=true setzen, prüfen dass nur Error/PartlyError-Einträge zurückkommen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-12
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator/Fachbereich
Vorbedingung: Ein Geschäftsobjekt (z. B. Workflow/Prozess) soll bei Ereignissen bestimmte Empfänger benachrichtigen.
Fakt: `NotificationUser` (Titel, Vor-/Nachname, Telefon, E-Mail) wird über eine m:n-Bindungstabelle `NotificationUsersToObject` (ObjectKind + ObjectI3D) einem beliebigen Geschäftsobjekt zugeordnet. Beim Speichern (`UpdateUsersFromObject`) wird ein Benutzer anhand der Kombination aus Vorname/Nachname/Titel/Telefon/E-Mail dedupliziert wiederverwendet; nicht mehr referenzierte Bindungen werden entfernt.
Aussage: Das System soll es erlauben, beliebige Kontaktpersonen (nicht zwingend Systembenutzer) objektbezogen als Benachrichtigungsempfänger zu hinterlegen, wobei identische Kontakte dedupliziert wiederverwendet werden.
Ergebnis: Wiederverwendbare Kontaktverwaltung für Benachrichtigungsempfänger je Objektinstanz.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Notifications/UserNotificationBL.cs:41-117 (UpdateUsersFromObject) - Begründung: Zeigt Bindungslogik, Deduplizierung und Bereinigung nicht mehr benötigter Bindungen.
Prüfidee: Test: Zwei Objekte mit identischem NotificationUser (gleiche Felder) verknüpfen, prüfen dass nur ein NotificationUser-Datensatz in der DB existiert.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-13
Ebene: StRS
Typ: Schnittstelle
Akteur: IT-Verantwortlicher
Vorbedingung: Das System soll E-Mails im Namen des Unternehmens versenden/empfangen.
Fakt: Der zu verwendende Mail-Client wird zentral über die Einstellung `CentronWebserviceMailType` gesteuert und kann zwischen SMTP (Default), Microsoft Exchange (EWS) und Microsoft Graph umgeschaltet werden (`CentronMailFactory.GetMail`). Zusätzlich existiert ein globaler Testmail-Modus (`TestMails.IsEnabled`), der bei aktiven Subscribern jede reale Mail-Versendung durch einen In-Memory-Mock ersetzt.
Aussage: Das System soll die Wahl des E-Mail-Transportprotokolls (SMTP/Exchange/Microsoft Graph) als zentrale, administrierbare Einstellung anbieten und einen von der Konfiguration unabhängigen Test-/Simulationsmodus für den Mailversand unterstützen.
Ergebnis: Flexible Integration in unterschiedliche Kunden-Mailinfrastrukturen; sichere Testbarkeit ohne reale Mailversendung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/CentronMailFactory.cs:26-53 (GetMail) - Begründung: Zeigt Protokollauswahl per Setting und TestMail-Vorrang.
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 - Begründung: Zeigt Subscriber-Pattern für Testmail-Abfang.
Prüfidee: Konfigurationstest: CentronWebserviceMailType nacheinander auf 0/Exchange/Graph setzen und prüfen, dass jeweils die korrekte Implementierungsklasse instanziiert wird.
Konsolidierungshinweis: Basis für ADM-14 bis ADM-18.
Status: belegt
---
### Kandidat ADM-14
Ebene: SwRS
Typ: funktional; Workaround
Akteur: System (technisch)
Vorbedingung: SMTP-Client wird für den Versand aufgebaut.
Fakt: `SMTPMail.CreateSmtpClient` aktiviert SSL zwingend (`client.EnableSsl = true`), wenn der konfigurierte Host exakt `"smtp.office365.com"` ist – unabhängig vom konfigurierten Wert der Einstellung `SmtpSslActive`. Für alle anderen Hosts gilt ausschließlich der konfigurierte Wert.
Aussage: Das System soll für den Sonderfall Office365-SMTP verschlüsselte Übertragung erzwingen, auch wenn die SSL-Einstellung deaktiviert konfiguriert wurde.
Ergebnis: Verhindert versehentlich unverschlüsselten Versand über Office365, führt aber zu inkonsistentem Verhalten der SSL-Einstellung zwischen Hosts (hartkodierter Sonderfall statt allgemeiner Regel).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:160 (`client.EnableSsl = client.Host == "smtp.office365.com" || settings.SmtpSslActive;`) - Begründung: Hartkodierte Sonderregel für einen konkreten Hostnamen.
Prüfidee: Konfigurationstest: Host=smtp.office365.com, SmtpSslActive=false setzen, prüfen dass EnableSsl dennoch true ist. Für Web-Neuimplementierung klären, ob dieser Sonderfall fachlich gewollt bleibt oder durch allgemeine Pflichtverschlüsselung ersetzt wird.
Konsolidierungshinweis: Ergänzt ADM-13.
Status: belegt; Workaround (hartkodierter Hostname als Sonderfall im Code)
---
### Kandidat ADM-15
Ebene: SwRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Zugangsdaten für Mailversand werden gespeichert.
Fakt: `MailSettingsBL` verschlüsselt `ExchangePassword` und `GraphAppSecret` mit `AESCryptoLogic` vor dem Speichern (`EncryptText`) bzw. entschlüsselt sie beim Laden (`DecryptText`). Für `SmtpPassword` (Einstellung `MailSmtpPassword`) erfolgt dagegen keinerlei Ver-/Entschlüsselung – der Wert wird als Klartext in `AppSettingsBL.GetSettingsForUpdate`/`UpdateString` gespeichert und gelesen.
Aussage: Das System soll alle im Klartext übertragbaren Zugangsgeheimnisse für den Mailversand (inkl. SMTP-Passwort) einheitlich verschlüsselt in der Konfigurationsdatenbank ablegen.
Ergebnis: Aktuell inkonsistenter Schutz von Zugangsdaten: Exchange/Graph-Geheimnisse sind verschlüsselt, SMTP-Passwort liegt im Klartext in der Datenbank vor.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSettingsBL.cs:110 (SmtpPassword = setting.GetString(AppSettingsConst.MailSmtpPassword)) vs. Zeile 117 (ExchangePassword = this._cryptoLogic.DecryptText(...)) und Zeile 133 (GraphAppSecret = this._cryptoLogic.DecryptText(...)) - Begründung: Direkter Codevergleich zeigt fehlende Verschlüsselung nur beim SMTP-Passwort.
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSettingsBL.cs:205 (UpdateString(AppSettingsConst.MailSmtpPassword, settings.SmtpPassword)) vs. Zeile 212/227 (EncryptText für Exchange/Graph) - Begründung: Bestätigt fehlende Verschlüsselung beim Speichern.
Prüfidee: Sicherheitsreview: DB-Inhalt der Stammdat-Zeile für MailSmtpPassword direkt inspizieren und mit ApplicationSetting für GraphAppSecret vergleichen (Klartext vs. Chiffrat).
Konsolidierungshinweis: Für SaaS-Neuimplementierung: einheitliches Secret-Handling (z. B. Vault/KMS) für alle Mailprotokoll-Zugangsdaten vorsehen; vgl. ADM-26/ADM-27 (Masterkey-Verschlüsselung bei MailScanner).
Status: belegt
---
### Kandidat ADM-16
Ebene: SwRS
Typ: funktional
Akteur: System (technisch)
Vorbedingung: E-Mail mit mehreren Empfängern (To/CC/BCC) wird versendet.
Fakt: `SMTPMail.CreateMailMessage` validiert jede Empfängeradresse einzeln über `DeveloperSecurity.Email.ValidateAddress`. Bei ungültiger Adresse wird diese von der jeweiligen Empfängerliste ausgeschlossen und der Ergebnisstatus auf `ResultStatus.Warning` gesetzt (mit Sammel-Meldungstext je ausgeschlossener Adresse), der Versand an die übrigen gültigen Adressen wird jedoch nicht abgebrochen.
Aussage: Das System soll beim Mailversand ungültige Einzeladressen tolerant behandeln: sie werden von der Zustellung ausgeschlossen und dem Absender als Warnung gemeldet, ohne den gesamten Versand an die übrigen validen Empfänger zu verhindern.
Ergebnis: Höhere Zustellzuverlässigkeit bei Massen-/Sammelmails trotz einzelner fehlerhafter Adressen; Nachvollziehbarkeit über Warnmeldung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:218-266 (CreateMailMessage, To/CC/BCC-Schleifen) - Begründung: Zeigt Try/Catch pro Adresse mit Warning-Sammlung statt Gesamtabbruch.
Prüfidee: Test: Mail mit einer gültigen und einer syntaktisch ungültigen To-Adresse versenden; erwartet ResultStatus.Warning und Zustellung an die gültige Adresse.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-17
Ebene: SwRS
Typ: funktional
Akteur: Systemadministrator
Vorbedingung: SMTP-Host ist in den Mailversand-Einstellungen nicht gepflegt.
Fakt: Wird beim Aufbau des `SmtpClient` ein leerer Host übergeben, fängt `SMTPMail.CreateSmtpClient` die resultierende `ArgumentException` ab und wirft stattdessen eine `ResultException` mit der benutzerorientierten deutschen Fehlermeldung "Der Host in den SMTP-Einstellungen ist nicht gesetzt.".
Aussage: Das System soll bei fehlender SMTP-Host-Konfiguration eine eindeutige, administratorverständliche Fehlermeldung liefern statt eines technischen Low-Level-Fehlers.
Ergebnis: Schnellere Fehlerdiagnose durch Administratoren bei unvollständiger Mailkonfiguration.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:151-159 - Begründung: Konkreter Meldungstext im Catch-Block.
Prüfidee: Test: MailSettingsDTO mit leerem SmtpHost übergeben, prüfen dass ResultException mit exaktem Meldungstext geworfen wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-18
Ebene: SyRS
Typ: nicht-funktional (Testbarkeit/Betrieb)
Akteur: IT-Verantwortlicher/QA
Vorbedingung: Automatisierte Tests oder Staging-Betrieb sollen keine echten E-Mails versenden.
Fakt: `TestMails` implementiert ein statisches Subscriber-Muster (`Start`/`AddMail`), über das während der Aktivierung sämtliche über `CentronMailFactory` erzeugten Mails als `TestMail`-Instanz behandelt werden, die E-Mails nur sammelt statt zu versenden bzw. optional als serialisierte `.eml`-Datei bereitstellt (`waitForMail`).
Aussage: Das System soll einen expliziten, laufzeitweit aktivierbaren Testmodus für den Mailversand bereitstellen, in dem E-Mails abgefangen und inspizierbar gemacht werden, statt real versendet zu werden.
Ergebnis: Sichere automatisierte Tests von mailauslösenden Geschäftsprozessen ohne Risiko echter Zustellung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 - Begründung: Vollständige Implementierung des Subscriber-Patterns.
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/TestMail.cs:1-82 - Begründung: Konkrete Mail-Implementierung, die nur sammelt/serialisiert statt versendet.
Prüfidee: Testinfrastruktur-Review: Prüfen, in welchen automatisierten Testsuiten `TestMails.Start` verwendet wird und ob Staging-Umgebungen dies standardmäßig aktivieren.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-19
Ebene: SwRS
Typ: funktional
Akteur: Sachbearbeiter/Systemadministrator
Vorbedingung: Für ein Geschäftsobjekt (z. B. Angebot, Helpdesk-Ticket) soll eine passende Mailvorlage ermittelt werden.
Fakt: `MailTemplateBL.MailTemplate` (private Methode) löst die zu verwendende Mailvorlage über eine fest dokumentierte Prioritätskette auf: 1. Konto/Kunde (Account), 2. persönlich (Mitarbeiter), 3. Niederlassung (Branch), 4. global, 5. hartkodierter Fallback (leere Vorlage mit Referenzwerten). Eine Vorlage wird nur akzeptiert, wenn sowohl Betreff als auch Klartext-Body nicht leer sind (`CheckMailTemplate`); fehlt Betreff oder Body, wird der jeweilige Default-Text aus der `MailTemplateReference` (`DefaultSubject`/`DefaultBody`) eingesetzt.
Aussage: Das System soll bei der Ermittlung einer E-Mail-Vorlage eine mehrstufige Fallback-Kette (kundenspezifisch → personenspezifisch → niederlassungsspezifisch → global → Systemstandard) anwenden und dabei unvollständige Vorlagen (fehlender Betreff/Text) automatisch durch definierte Standardtexte ergänzen.
Ergebnis: Vorhersagbare, konfigurierbare Mailtexte je Kontext ohne Gefahr leerer Betreffs/Inhalte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:248-317 (MailTemplate-Methode inkl. XML-Doc-Kommentar "MailTemplate priority fallback order") - Begründung: Enthält sowohl expliziten Kommentar zur Reihenfolge als auch die Implementierung inkl. CheckMailTemplate/HandleIfSubjectOrBodyNotDefined.
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:319-361 (GetMailTemplate mit Logging pulledLocation) - Begründung: Zeigt, dass die tatsächlich verwendete Ebene ("customer"/"personal"/"branch"/"global"/"hardcoded default fallback") geloggt wird - starkes Indiz für bewusst gestaltete Fallback-Logik.
Prüfidee: Testmatrix: Für dieselbe MailTemplateReference gezielt nur Branch- und Global-Vorlage anlegen (keine Account-/Personal-Vorlage), erwartete Ergebnis-Ebene "branch" prüfen.
Konsolidierungshinweis: Zusammenhang mit ADM-20 (Identitätsschema) und ADM-22 (RTF-Konvertierung).
Status: belegt
---
### Kandidat ADM-20
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator/Entwickler
Vorbedingung: Eine Mailvorlage soll eindeutig einem fachlichen Anwendungsfall zugeordnet werden.
Fakt: Jede Mailvorlage wird laut Entwicklerdokumentation eindeutig über die Kombination der Felder `ObjectKind`, `ObjectI3D`, `SubObjectKind` und `TemplatePrio` identifiziert (Klasse `MailTemplateReference`); z. B. haben Angebots-Mails `ObjectKind=Offer` mit allen übrigen Feldern NULL, während `ObjectKind=Escalation` mehrere Vorlagen über unterschiedliche `SubObjectKind`-Werte unterscheidet, da kein Bezug zu einer anderen Datenbankzeile (`ObjectI3D`) existiert.
Aussage: Das System soll Mailvorlagen über ein generisches, viergliedriges Identitätsschema (Objektart, Objekt-ID, Unterobjektart, Priorität) eindeutig referenzieren, das sowohl global gültige als auch objekt- oder fallspezifische Vorlagen abbildet.
Ergebnis: Ein einheitliches, erweiterbares Datenmodell für beliebig viele fachliche Mailvorlagen-Typen ohne Schemaänderung je neuem Anwendungsfall.
Belege:
- [SEKUNDÄR] docs/guides/development/create-mail-templates.md:6-33 - Begründung: Erläutert explizit das Identitätsschema mit Beispielen (Offer, Escalation, HelpdeskType).
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:133-156 (CreateExpression) - Begründung: Konkrete Filterlogik nach ObjectKind/SubObjectKind/ObjectI3D/BranchI3D/AccountI3D/IsPersonalMailTemplate/IsActive bestätigt das Schema.
Prüfidee: Datenmodell-Review: Prüfen ob für jede fachliche Verwendung (Offer, Order, Helpdesk, Escalation, ...) eine eindeutige MailTemplateReference in `MailTemplateReferences` registriert ist ohne Kollisionen.
Konsolidierungshinweis: Ergänzt ADM-19.
Status: belegt
---
### Kandidat ADM-21
Ebene: SwRS
Typ: funktional
Akteur: Sachbearbeiter
Vorbedingung: Mailvorlage/Signatur enthält Platzhalter, die vor Versand ersetzt werden sollen.
Fakt: `MailTemplateBL.GenerateVariables` definiert für Outlook-Mailvorlagen benannte Variablen (`TextVariableWithReplacementStrategy`), gruppiert nach fachlichen Kategorien ("Allgemein", "Bearbeiter", "Kunde", "Adresse", "Ansprechpartner"), jeweils mit einer Lambda-Ersetzungsfunktion. Mehrere Variablen besitzen zusätzlich `AlternativeNames` (z. B. "KundenNummer" alternativ "KdNummer"), um Abwärtskompatibilität zu älteren Vorlagen-Platzhaltern sicherzustellen. Die Liste wird abschließend mit `EnsureValidVariableKeys()` validiert.
Aussage: Das System soll ein gruppiertes, benanntes Variablensystem für Mailvorlagen-Platzhalter bereitstellen, das für einzelne Variablen mehrere gültige (auch historische) Bezeichner unterstützt und die Variablendefinitionen beim Laden konsistenzprüft.
Ergebnis: Fachlich verständliche, kategorisierte Platzhalterliste im Vorlagen-Editor; Bestandsvorlagen mit alten Variablennamen bleiben funktionsfähig.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:531-1037 (GenerateVariables) - Begründung: Vollständige Liste der Variablengruppen inkl. AlternativeNames-Mechanismus.
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:1037 (`.EnsureValidVariableKeys()`) - Begründung: Zeigt explizite Validierungsroutine für Variablenschlüssel.
Prüfidee: Test: Vorlage mit historischem Platzhalter "KdNummer" gegen aktuelle Variable "KundenNummer" prüfen, ob beide Schreibweisen korrekt ersetzt werden.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-22
Ebene: SwRS
Typ: funktional
Akteur: System (technisch)
Vorbedingung: Eine Mailvorlage mit Klartext-Body oder leerem/platzhalterartigem Inhalt wird geladen.
Fakt: `MailTemplateBL.GetRichText` konvertiert Klartext automatisch in RTF anhand der globalen Mailschrift-Einstellungen (`MailSettingsDTO.FontFamily/FontSize/MailFontArt`), sofern der Text noch nicht im RTF-Format vorliegt (`text.IsRtf()`). Zusätzlich existiert ein dokumentierter Sonderfall: Enthält der (in Klartext umgewandelte) Body ausschließlich das Zeichen "-", wird der Body als leer behandelt ("special case when the customer wants to have an empty body").
Aussage: Das System soll Mailvorlagen-Inhalte unabhängig vom Ursprungsformat einheitlich als RTF mit den global konfigurierten Schrifteinstellungen bereitstellen und einen projektspezifischen Sonderfall für "bewusst leerer Body" (Platzhalterzeichen "-") unterstützen.
Ergebnis: Einheitliche Darstellung unabhängig vom Speicherformat; Kundenwunsch nach explizit leerem Mailbody wird technisch abgebildet (kein generisches, dokumentiertes Feature, sondern Einzelfall-Workaround).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:1049-1061 (GetRichText) - Begründung: Zeigt bedingte RTF-Konvertierung anhand globaler Mailschrift-Settings.
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:331-333 (bodyContainsDash) - Begründung: Codekommentar bestätigt Kundenspezifischen Sonderfall.
Prüfidee: Test: Vorlage mit Body-Inhalt "-" laden, prüfen dass der zurückgegebene Body leer ist statt des RTF-formatierten Bindestrichs.
Konsolidierungshinweis: Ergänzt ADM-19. Für Web-Neuimplementierung klären, ob RTF als internes Format beibehalten werden soll oder durch HTML/Markdown ersetzt wird (Formatentscheidung).
Status: belegt; Workaround (Bindestrich-Sonderfall wirkt als kundenspezifischer Einzelfall, nicht als generische Regel)
---
### Kandidat ADM-23
Ebene: StRS
Typ: funktional
Akteur: Systemadministrator/Sachbearbeiter
Vorbedingung: Ausgehende Mails (allgemein, Helpdesk intern, Helpdesk extern) sollen eine Signatur erhalten.
Fakt: `MailSignatureBL` unterscheidet drei unabhängig konfigurierbare Signaturkontexte (Standard `MailSignatureKind`, `HelpdeskInternalMailSignatureKind`, `HelpdeskExternalMailSignatureKind`) und je Kontext eine Signaturquelle (`MailSignatureKind`-Enum: None/Outlook/Centron). Bei Quelle "Outlook" wird die Signatur aus lokalen Outlook-RTF-Dateien plus Windows-Registry-Konfiguration (`HKCU\...\Outlook\Profiles\...`) gelesen; bei Quelle "Centron" aus einer in der Datenbank hinterlegten Signatur (`AppSettingData`, Encoding 1252).
Aussage: Das System soll pro Mail-Kontext (Standard, Helpdesk intern, Helpdesk extern) eine unabhängig konfigurierbare Signaturquelle unterstützen, wahlweise aus lokalem Outlook-Profil oder zentral in der Datenbank gepflegter Signatur.
Ergebnis: Fachlich getrennte, kontextabhängige Signaturgestaltung; Outlook-Quelle ist jedoch an lokale Windows-Umgebung/Registry gebunden (Client-seitige Abhängigkeit).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSignatureBL.cs:111-182 (GetHelpdeskExternalSignature, GetHelpdeskInternalSignature, GetDefaultSignature, GetSignature) - Begründung: Drei parallele, strukturell identische Methoden für die drei Kontexte.
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSignatureBL.cs:41-96 (GetDefaultOutlookSignature) - Begründung: Zeigt Registry-/Dateisystem-Abhängigkeit der Outlook-Signaturquelle inkl. `OperatingSystem.IsWindows()`-Prüfung mit Fehler "Outlook default signature can only be loaded on windows".
Prüfidee: Für Web-/SaaS-Migration klären: Outlook-Signaturquelle ist im Web-/SaaS-Kontext (kein lokales Windows-Client-Profil) nicht sinnvoll übertragbar - Anforderung an Nachfolgesystem prüfen (nur noch zentrale Signaturverwaltung?).
Konsolidierungshinweis: -
Status: belegt; HYPOTHESE bzgl. Weiterverwendung der Outlook-Quelle im Web/SaaS-Kontext (technische Prämisse "lokaler Windows-Client mit Outlook" entfällt vermutlich in einer SaaS-Architektur - im Code nicht explizit als Migrationsentscheidung dokumentiert)
---
### Kandidat ADM-24
Ebene: SwRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Eine E-Mail soll an eine bestimmte Domain versendet werden.
Fakt: `DomainBlacklistBL.IsBlacklisted` prüft die Ziel-Domain der E-Mail-Adresse gegen eine Liste von `DomainBlacklistItem`. Einträge, die mit "@" beginnen, werden als exakte Domain-Sperre behandelt (Exact-Match auf "@"+Domain); alle übrigen Einträge werden über eine dynamisch aus dem Domainstring generierte Regex geprüft (`Regex.Replace(f.Domain, "(.)", "[$1]")` erzeugt ein Zeichen-für-Zeichen-Zeichenklassen-Pattern, kombiniert mit Anker `[@.]`), wodurch Teilstring-/Wildcard-artige Sperren auf Sub-Domain-Ebene möglich sind. Bei nicht auswertbarer E-Mail-Adresse (keine Domain extrahierbar) wird ein Fehler "Malformed E-Mail address" zurückgegeben.
Aussage: Das System soll den Versand von E-Mails an domainbasierte Sperrlisten verhindern können, mit Unterstützung für exakte Domainsperren und musterbasierte (Teil-/Sub-Domain-)Sperren.
Ergebnis: Verhinderung von Mailversand an unerwünschte/gesperrte Empfängerdomains (z. B. Wettbewerber, bekannte Spam-Fallen).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Blacklist/DomainBlacklistBL.cs:15-36 (IsBlacklisted) - Begründung: Vollständige Implementierung inkl. beider Prüfmodi und Fehlerfall.
Prüfidee: Test: Blacklist-Eintrag "@spam.de" (exakt) und "test" (Muster) anlegen; prüfen dass "user@spam.de" gesperrt ist und "user@mytest.de" ebenfalls über Musterprüfung erkannt wird; ungültige Adresse ohne "@" liefert Fehler.
Konsolidierungshinweis: HYPOTHESE bzgl. genauer fachlicher Bedeutung des Nicht-"@"-Musters, da die Regex-Konstruktion technisch komplex/unklar dokumentiert ist (keine Kommentare im Code) - Klärung mit Fachbereich empfohlen, ob dies bewusst Sub-Domain-Wildcards abbilden soll.
Status: belegt; Detailverhalten der Musterprüfung als HYPOTHESE markiert (fehlende Dokumentation der Regex-Absicht im Code)
---
### Kandidat ADM-25
Ebene: SwRS
Typ: funktional
Akteur: Systemadministrator
Vorbedingung: Ausgehende Mails zu verschiedenen Geschäftsvorgängen sollen im Antworttext erkennbar sein (Tracking).
Fakt: `MailSettingsBL.GetMailTrackingSettings`/`UpdateMailTrackingSettings` verwalten pro Geschäftsobjekt-Typ ein eigenes Tracking-Schlüsselwort: Angebot (`MailTrackingOffer`), Auftrag (`MailTrackingOrder`), Lieferschein (`MailTrackingDeliveryList`), Rechnung (`MailTrackingInvoice`), Helpdesk (`MailTrackingHelpdesk`).
Aussage: Das System soll für die zentralen vertriebs-/serviceseitigen Mailvorgänge (Angebot, Auftrag, Lieferschein, Rechnung, Helpdesk) jeweils ein eigenständig konfigurierbares Tracking-Schlüsselwort unterstützen.
Ergebnis: Zuordenbarkeit eingehender Antwortmails zu ursprünglichen Geschäftsvorgängen anhand konfigurierbarer Schlüsselwörter.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSettingsBL.cs:233-270 (GetMailTrackingSettings, UpdateMailTrackingSettings) - Begründung: Vollständige DTO-Feldliste der fünf Tracking-Bereiche.
Prüfidee: Funktionstest: Tracking-Keyword für "Angebot" setzen, prüfen dass es korrekt persistiert und beim Laden zurückgegeben wird; Zusammenspiel mit MailScanner (Zuordnungslogik) als Anschlussfrage prüfen.
Konsolidierungshinweis: Zusammenhang mit MailScanner-Cluster (ADM-26 ff.) - technischer Verwendungszweck der Keywords in der Zuordnungslogik des MailScanners wurde in diesem Rechercheumfang nicht weiter verfolgt.
Status: belegt; HYPOTHESE bzgl. exakter Verwendung der Tracking-Keywords beim Mailempfang (Code der Auswertung nicht in diesem Rechercheumfang gelesen)
---
### Kandidat ADM-26
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: MailScanner-Profil mit Zugangsdaten (Passwort, OAuth-Client-Secret) für automatisiertes Postfach-Abholen wird gespeichert/gelesen.
Fakt: `MailScannerBL.EncryptProperties`/`DecryptProperties` verschlüsseln/entschlüsseln die Felder `Password` und `ClientSecret` eines `MailScannerProfile` über `CentronConfigurationDbBL.EncryptWithMasterKey`/`DecryptWithMasterKey`. Diese Methoden verwenden einen zentralen, separat verwalteten "Hotline-Masterkey" (`GetHotlineMasterKey`) für eine zusätzliche AES-Verschlüsselungsebene; ist kein Masterkey hinterlegt, liefert die Operation den Fehler "Es wurde kein Masterkey hinterlegt" statt eines unverschlüsselten Werts.
Aussage: Das System soll Zugangsgeheimnisse für automatisierte Postfachanbindungen (MailScanner-Profile) nur unter Verwendung eines zentral hinterlegten Masterkeys speichern/entschlüsseln können und die Operation bei fehlendem Masterkey mit einer definierten Fehlermeldung verweigern statt unverschlüsselt zu persistieren.
Ergebnis: Zusätzliche Schutzebene für hochsensible Postfach-Zugangsdaten (u. a. OAuth Client Secrets); "Fail-safe" bei fehlendem Masterkey statt stillem Klartext-Fallback.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MailScanner/MailScannerBL.cs:90-116 (DecryptProperties, EncryptProperties) - Begründung: Zeigt zwei verschlüsselte Felder und Fehlerweiterleitung bei Fehlschlag.
- [PRIMÄR] src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:78-110 (EncryptWithMasterKey, DecryptWithMasterKey) - Begründung: Zeigt exakte Fehlermeldung "Es wurde kein Masterkey hinterlegt" und AES-Verschlüsselung mit Masterkey als Parameter.
- [KONTEXT] src/backend/Centron.Entities/Entities/MailScanner/MailScannerProfile.cs:9-23 - Begründung: Zeigt betroffene Felder (Password, ClientSecret, ClientId, TenantId) im Datenmodell.
Prüfidee: Test: Masterkey aus Konfiguration entfernen, SaveProfile mit gesetztem Password aufrufen, erwarteter Fehler statt Speicherung im Klartext.
Konsolidierungshinweis: Vergleich mit ADM-15 (inkonsistentes Schutzniveau je Zugangsdaten-Typ im Gesamtsystem).
Status: belegt
---
### Kandidat ADM-27
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Der "Hotline-Masterkey" (siehe ADM-26) muss irgendwo persistiert werden.
Fakt: `CentronConfigurationDbBL` unterstützt zwei austauschbare Speicherorte für den Masterkey über das Strategy-Pattern `IMasterPasswordStorage`: `MasterPasswordConfigurationDatabaseStorage` (Konfigurationsdatenbank) und `MasterPasswordSecureFileStorage` (sichere Datei), gesteuert über die Einstellung `MasterPasswordSaveLocation` aus den Password-Manager-Einstellungen.
Aussage: Das System soll dem Administrator die Wahl lassen, den zentralen Masterkey wahlweise in der Konfigurationsdatenbank oder in einer separaten sicheren Datei außerhalb der Datenbank zu speichern.
Ergebnis: Flexibilität zwischen zentraler (datenbankgebundener) und dezentraler (dateibasierter) Schlüsselverwahrung je nach Sicherheitsanforderung des Kunden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:20-33,52-66 (Dictionary _masterPasswordStorages, IsHotlineMasterKeyAvailable, SetHotlineMasterKey) - Begründung: Zeigt zwei konkrete Storage-Implementierungen und settingsgesteuerte Auswahl.
Prüfidee: Konfigurationstest: MasterPasswordSaveLocation zwischen beiden Werten umschalten und prüfen, dass GetHotlineMasterKey konsistent aus dem jeweils aktiven Speicherort liest.
Konsolidierungshinweis: Ergänzt ADM-26. Für SaaS-Neuimplementierung: Datei-basierte Speicherung (SecureFile) ist in einer gehosteten Multi-Tenant-Umgebung ggf. nicht sinnvoll übertragbar (HYPOTHESE, da lokale Serverdatei voraussetzt) - Klärung mit Fachbereich empfohlen.
Status: belegt
---
### Kandidat ADM-28
Ebene: SwRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Ein Benutzer möchte MailScanner-Profile (Postfach-Abholkonfigurationen) einsehen.
Fakt: `MailScannerBL.GetProfiles` prüft vor dem Laden der Profile explizit das Recht `UserRightsConst.VirtualMailAssistant.ACCESS_VMA_MODULE` über `AppRightsBL.CheckRightsFromUser`; fehlt das Recht, wird ein Fehler "Fehlendes Recht VMA Profile zu laden" mit Code `DefaultMessageCodes.RightCheckFailed` zurückgegeben, ohne dass Profildaten (inkl. verschlüsselter Zugangsdaten) geladen werden. Andere Methoden derselben Klasse (`SaveProfile`, `DeleteProfile`, `SaveTasks`) enthalten keine sichtbare Rechteprüfung.
Aussage: Das System soll den lesenden Zugriff auf MailScanner-Profile an ein dediziertes Benutzerrecht ("Virtual Mail Assistant"-Modulzugriff) knüpfen.
Ergebnis: Eingeschränkte Sichtbarkeit sensibler Postfach-Konfigurationen auf berechtigte Benutzer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MailScanner/MailScannerBL.cs:57-72 (GetProfiles) - Begründung: Enthält konkrete Rechteprüfung und Fehlermeldungstext.
Prüfidee: Berechtigungstest: Benutzer ohne ACCESS_VMA_MODULE-Recht ruft GetProfiles auf, erwartet Fehlermeldung statt Daten. Ergänzend: Rechteprüfung für Save/Delete/SaveTasks im Code verifizieren (evtl. Lücke).
Konsolidierungshinweis: -
Status: belegt; HYPOTHESE bzgl. Vollständigkeit der Rechteprüfung (Save/Delete/SaveTasks zeigten im gelesenen Code keine erkennbare Rechteprüfung - ggf. an anderer Stelle z. B. WebService-Layer abgesichert, nicht abschließend verifiziert)
---
### Kandidat ADM-29
Ebene: StRS
Typ: Daten
Akteur: Systemadministrator
Vorbedingung: Unternehmensstammdaten (Mandant) sollen gepflegt und für Belegdruck/Kommunikation verwendet werden.
Fakt: `MandatorBL` erwartet genau einen als Standard markierten Mandanten (`Default == 1`, `GetDefaultMandator`/`GetDefaultMandatorExtended`); ein Mandant kann bis zu acht unterschiedliche Logo-/Bildvarianten hinterlegen (`PictureOne` … `PictureEight`, Zugriff über `GetMandatorLogoByIndex` mit Index 1-8, sonst Fehler "image index was out of range (index can be between 1 and 8)"). Für ESR/QR-Zahlungsreferenzen kann eines von vier hinterlegten Bankkonten je Mandant als aktiv markiert werden (`UseBankForEsr` 1-4, `GetEsrBankIndex`/`GetIBANFromEsrIndex`).
Aussage: Das System soll pro Mandant genau einen als Standard gekennzeichneten Datensatz mit bis zu acht wählbaren Firmenlogos sowie bis zu vier hinterlegten Bankverbindungen verwalten, von denen eine für ESR/QR-Referenzen aktiv gewählt werden kann.
Ergebnis: Mandantenfähige Stammdatenverwaltung als Grundlage für Corporate-Design (Logo) und Zahlungsverkehr je Mandant.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:19-27 (GetDefaultMandator, GetDefaultMandatorExtended) - Begründung: Zeigt Default-Flag-Semantik.
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:90-125 (GetMandatorLogoByIndex) - Begründung: Zeigt Acht-Bilder-Struktur inkl. Fehlermeldung bei ungültigem Index.
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:54-88 (GetEsrBankIndex, GetIBANFromEsrIndex) - Begründung: Zeigt Vier-Konten-Struktur mit wählbarem Referenzkonto.
Prüfidee: Datenmodelltest: Mehrere Mandanten mit Default=1 in Testdaten anlegen und prüfen, welches Verhalten GetDefaultMandator zeigt (GetEntity liefert vermutlich undefiniertes Verhalten bei Mehrfachtreffern - Eindeutigkeit als Datenintegritätsregel prüfen/erzwingen).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ADM-30
Ebene: SyRS
Typ: Schnittstelle
Akteur: IT-Verantwortlicher
Vorbedingung: Die Anwendung soll ihre Lizenzberechtigung prüfen.
Fakt: `LicenseManager` bezieht Lizenzinformationen über einen externen "c-entron Office"-Lizenzserver-Client (`OfficeClient`/`FakeOfficeClient`), wobei Zusatzdaten zur Lizenzbindung aus der Zieldatenbank stammen (`DatabaseId`, `DatabaseName`, `DatabaseCreatedDate`, `DatabaseOwnerSid` über `SQLManagementBL.GetDatabaseInfosForLicenseServer`) sowie Maschinenname und Windows-Dienstname. Für den Web-Service-Kontext wird statt eines direkten Office-Clients ein `FakeOfficeClient` verwendet, der die Lizenzdatei stattdessen über den eigenen Web-Service bezieht, mit deaktivierter Hardware-ID-Prüfung (`CheckIfLicenseIsValidForHardwareIDs = false`).
Aussage: Das System soll seine Nutzungsberechtigung über einen zentralen, produktübergreifenden Lizenzserver prüfen, wobei die Lizenz an eine konkrete Datenbankinstanz (nicht nur an Hardware) gebunden werden kann, und im mehrstufigen Web-Service-Betrieb einen alternativen Lizenzbezugsweg ohne Hardware-Bindung unterstützen.
Ergebnis: Zentral steuerbare Produktlizenzierung (Feature-/Anzahl-Gating je Lizenz), die für eine SaaS-Multi-Tenant-Architektur grundlegend überarbeitet werden müsste (Hardware-/Einzel-DB-Bindung passt nicht zu Multi-Tenant-SaaS).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 (ILicenseManager Interface: HasLicense, CheckLicense, GetLicenseCount, GetLicenseProducts) - Begründung: Zeigt Funktionsumfang der Lizenzprüfung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:47-115 (SettingsForWebService, GetAdditionalData) - Begründung: Zeigt Datenbank-/Maschinenbindung der Lizenz.
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:117-139 (SettingsForCentronNet, FakeOfficeClient, CheckIfLicenseIsValidForHardwareIDs=false) - Begründung: Zeigt alternativen Lizenzweg für Web-Service-Kontext.
Prüfidee: Architekturklärung mit Fachbereich: Wie soll Lizenzierung/Feature-Gating in einer Multi-Tenant-SaaS-Architektur erfolgen (aktuelles Modell ist On-Premise/Einzelinstallation-zentriert)?
Konsolidierungshinweis: Zentrale, potenziell größte Architekturänderung für SaaS-Migration - sollte in Konsolidierung mit hoher Priorität markiert werden.
Status: belegt; HYPOTHESE bzgl. Übertragbarkeit des Lizenzmodells auf SaaS (im Code keine Aussage zu geplanter SaaS-Lizenzierung, nur aktuelles On-Premise-Modell belegt)
---
## Abdeckung
**Gelesen (tiefgehend, mit Zeilenbezug zitiert):**
- src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs
- src/backend/Centron.BL/Administration/Settings/SettingsCollection.cs
- src/backend/Centron.BL/Administration/Settings/UpdateSettingsCollection.cs
- src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs (Ausschnitt: ID-Zähler)
- src/backend/Centron.BL/Modules/ModuleBL.cs
- src/backend/Centron.BL/Modules/ModuleCategoryBL.cs
- src/backend/Centron.BL/Modules/ModuleClass.cs
- src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs
- src/backend/Centron.BL/Notifications/UserNotificationBL.cs
- src/webservice/Centron.WebServices.Core/Entities/Notifications/CentronNotificationsSettingsDTO.cs
- src/webservice/Centron.WebServices.Core/Entities/Notifications/LogKind.cs
- src/backend/Centron.BL/Administration/Settings/AppSettingsGroupBL.cs (Ausschnitte: CentronNotifications, RmaSettings)
- src/backend/Centron.BL/Mail/MailSettingsBL.cs
- src/backend/Centron.BL/Mail/Blacklist/DomainBlacklistBL.cs
- src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs (vollständig)
- src/backend/Centron.BL/Mailings/MailingTemplateBL.cs
- src/backend/Centron.BL/Mailings/MailingDataBL.cs
- src/backend/Centron.BL/Customizations/CustomTables/CustomTableBL.cs
- src/backend/Centron.BL/MailScanner/MailScannerBL.cs
- src/backend/Centron.BL/Mail/Factory/CentronMailFactory.cs
- src/backend/Centron.BL/Mail/Factory/TestMails.cs
- src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs
- src/backend/Centron.BL/Mail/Protocols/TestMail.cs
- src/backend/Centron.BL/Mail/Protocols/GraphMail.cs (Fehlerbehandlung, stichprobenartig via Grep)
- src/backend/Centron.BL/Mail/MailSignatureBL.cs
- src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs
- src/backend/Centron.BL/Administration/Company/MandatorBL.cs
- src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs (erste ~150 Zeilen)
- src/backend/Centron.Entities/Entities/MailScanner/MailScannerProfile.cs
- docs/guides/development/settings-management.md (vollständig)
- docs/guides/development/create-mail-templates.md (vollständig)
**Ausgelassen / nur oberflächlich gestreift (bekannte Lücken):**
- src/backend/Centron.BL/Mail/Exchange/* (ExchangeMail.cs, EwsHelper) - nicht gelesen; Exchange-Protokoll-Details (EWS-spezifische Validierung/Fehlermeldungen) fehlen.
- src/backend/Centron.BL/Mail/Protocols/GraphMail.cs - nur Fehlermeldungstexte per Grep erfasst, keine Volllektüre (OAuth-Flow, Token-Handling nicht im Detail analysiert).
- src/backend/Centron.BL/Mail/MailFormatting/* (RichEditMailMessageExporter, SignatureReplacementBL, StringToHtmlConverter) - nur indirekt über Aufrufe in SMTPMail/MailSignatureBL erschlossen, keine Volllektüre.
- src/backend/Centron.BL/Mail/VariableReplacement/PlmReplacementBL.cs - nicht gelesen.
- src/backend/Centron.BL/Administration/AccessTokens, Applications, ArtificialIntelligence, BackgroundServices, BookKeepingAccountSystems, Connections, DataSecurity, Documents, Employees, FileManagement, Logins, PerformanceTests, PhoneSettings, Portal, Profiling, Rights, SQLManagement, Scripts, Themes, WebServiceConfiguration, Masterdata - nicht untersucht (teilweise thematisch näher an anderen Clustern wie Rechte/Sicherheit oder Stammdaten, ggf. Überschneidung mit Parallel-Agenten).
- src/backend/Centron.BL/Administration/Mandatory/* (u. a. TextFormattingBL, referenziert von MandatorBL) - nicht gelesen.
- src/backend/Centron.BL/Administration/Environments/* (RegistryBL, ReportPrintingBL, SqlServerBL) - nur Verzeichnisliste erfasst, keine Lektüre (Betriebs-/Infrastruktur-Einstellungen, potenziell SyRS-relevant für Web-/SaaS-Migration).
- src/backend/Centron.BL/Administration/CentronConfigDb/MasterPasswordConfigurationDatabaseStorage.cs und MasterPasswordSecureFileStorage.cs - nur indirekt über CentronConfigurationDbBL erschlossen, keine Volllektüre der konkreten Speicherimplementierungen.
- src/backend/Centron.BL/Administration/CompanyInformations/CompanyBL.cs, Company/BranchBL.cs, NumberGroupBL.cs - nicht gelesen (Filialen-/Nummernkreisverwaltung, ggf. eigenständige Kandidaten für Stammdaten-Cluster).
- src/backend/Centron.BL/SystemArea/SystemTableI3DBL.cs - nicht gelesen.
- Mail-Repositories/DAO-Schicht (z. B. MailTemplateRepository, MailTemplateFolderRepository) - nicht gelesen, nur über BL-Aufrufe referenziert.
- WebService-/API-Schicht (ICentronRestService.Administration.cs, CentronRestService.Administration.cs) - nicht im Detail geprüft; API-Signaturen (Parameter, Rückgabetypen, Rechteprüfungen auf Service-Ebene) wurden nicht verifiziert, nur aus BL-Layer erschlossen.
- Frontend/WPF-Views (ViewModels, XAML) für Settings/Module/Mail-Verwaltung - nicht untersucht; UI-Texte/Validierungsmeldungen dort ggf. zusätzlich relevant für SwRS.
- ApplicationSettingDefinitions.cs (Beschreibungstexte) - nicht vollständig gelesen (nur referenziert), könnte weitere Detailregeln zu einzelnen Settings enthalten.
**Bekannte generelle Lücken:**
- Statusmaschinen für Mailings (MailingData.Version=2-Filterung deutet auf eine ältere Version-1-Struktur hin, die nicht weiter untersucht wurde) - Migrationslogik zwischen Version 1 und 2 unklar.
- Fachliche Bedeutung des MailScanner-Workflow-Engine-Zusammenspiels (ProcessBL, MailScannerWorkflowProcessDTO) wurde nur oberflächlich behandelt, nicht die eigentliche Verarbeitungslogik (Regeln, wann/wie eingehende Mails verarbeitet werden).
- Rechteprüfung war nur für MailScannerBL.GetProfiles eindeutig im BL-Code sichtbar; ob andere Administrations-/Settings-Endpunkte in der WebService-Schicht (nicht BL) zusätzliche Rechteprüfungen haben, wurde nicht verifiziert.
@@ -0,0 +1,570 @@
# Cluster ARCH — Anwendungsarchitektur / Shell / Querschnittsfunktionen
Rohbefunde (Zwischenformat) für Reverse Requirements Engineering an CentronERP (c-entron.NET, C#/WPF/XAML, MSSQL).
Quellbasis: `C:\DEV\MasterArbeit\QuellCode\CentronERP` (nur gelesen, nicht verändert).
---
### Kandidat ARCH-01
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Übertragbarkeit / Anpassbarkeit)
Akteur: IT-Administrator (Betreiber), Systemarchitekt
Vorbedingung: Installation der c-entron.NET Desktop-Anwendung
Fakt: Der Client unterstützt wahlweise eine direkte SQL-Server-Verbindung oder eine Verbindung über den c-entron Web-Service (`CentronConnectionType.SqlServer` vs. `CentronConnectionType.CentronWebServices`). Jedes Fachmodul deklariert über `ICentronAppModuleController.SupportsConnectionTypes`, welche Verbindungsarten es unterstützt (laut Doku-Kommentar "sollte immer beides sein").
Aussage: Das System soll wahlweise über eine direkte Datenbankverbindung oder über eine Web-Service-Schicht (REST/SOAP-artig) betrieben werden können, wobei Fachmodule beide Betriebsarten unterstützen müssen.
Ergebnis: Zwei-Schichten-Architektur mit austauschbarer Datenzugriffsstrategie; Grundlage für spätere Web-/SaaS-Migration (Web-Service-Pfad ist der näher an SaaS liegende Modus).
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Connections/CentronConnectionType.cs:6-12 - Enum mit den zwei Werten SqlServer/CentronWebServices
- [PRIMÄR] src/centron/Centron.WPF.UI.Extension/Modules/ICentronAppModuleController.cs:46-49 - Property SupportsConnectionTypes mit Kommentar "this should always be both sql and webservice!"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:296-313 - Verzweigung PreDoLoginToCentron je nach ConnectionType
Prüfidee: Stichprobenartig prüfen, ob alle 84 registrierten Module tatsächlich beide ConnectionTypes deklarieren; Abweichungen dokumentieren.
Konsolidierungshinweis: Grundlage für alle modulspezifischen Cluster (Voraussetzung: Web-Service-fähig für SaaS-Neuimplementierung).
Status: belegt
---
### Kandidat ARCH-02
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Endanwender (c-entron.NET Benutzer)
Vorbedingung: Anwendungsstart, LoginDialog wird angezeigt
Fakt: Die Authentifizierung unterstützt mehrere Verfahren: `Basic` (c-entron-eigenes Login), `ActiveDirectory`, `OpenIdConnect` (Microsoft Entra ID via MSAL/OIDC) sowie `WebAccount` (Kunden-Login für Web-Funktionen). `AuthenticatorFactory` wählt anhand der Systemeinstellung `SystemAuthenticationMethod` und ggf. Benutzer-spezifischer `AuthentificationKind` mit Fallback-Kette (`FallbackAuthenticator`) den passenden Authenticator.
Aussage: Das System soll mehrere konfigurierbare Authentifizierungsverfahren (Benutzername/Passwort, Active Directory, OpenID Connect/Microsoft Entra ID) unterstützen und pro Benutzer mit Fallback-Logik kombinieren können.
Ergebnis: Zentraler Authentifizierungs-Einstiegspunkt mit Erweiterbarkeit für weitere Identity-Provider; wichtig für SaaS (SSO-Fähigkeit vorhanden).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs:44-146 - GetAuthenticatorWithSystemAuth/GetMainAuthenticator mit Switch über BasicAuthObject/WebAccountAuthObject/OpenIdConnectAuthObject
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md:1-197 - vollständiger OIDC-Login-Flow inkl. Sequenzdiagramm
- [SEKUNDÄR] src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs (JwtAuthority=10351, JwtAudience=10352, SystemAuthenticationMethod=10360) - Konfigurationspunkte laut Doku
Prüfidee: End-to-End-Test aller vier Login-Pfade inkl. Fallback bei Fehlkonfiguration (z.B. AD nicht erreichbar).
Konsolidierungshinweis: Ergänzt durch ARCH-03 (OIDC-Detailfluss) und ARCH-04 (2FA).
Status: belegt
---
### Kandidat ARCH-03
Ebene: SwRS
Typ: Schnittstelle / Sicherheit
Akteur: Endanwender, externe Client-Anwendung
Vorbedingung: OpenID Connect ist serverseitig aktiviert (`JwtEnabled`)
Fakt: Der OIDC-Login-Flow läuft über `GET /config/jwt` (anonym, liefert Authority/Audience/Enabled), MSAL-Tokenakquise (ID-Token, Scopes `openid`,`profile`), `POST /jwt/login` (Bearer-ID-Token, Body `Application`/`AppVersion`/`Device`) und liefert ein c-entron-Ticket (Plain-Text-String) mit 30 Minuten Gültigkeit zurück. Nutzerzuordnung erfolgt über `oid`-Claim gegen Spalte `OpenIdConnectSubjectIdentifier` in Tabelle `Sichbenu`.
Aussage: Das System soll ein Microsoft-Entra-ID-basiertes Single-Sign-On über einen definierten Token-Austausch-Endpunkt (`/jwt/login`) bereitstellen, der ein zeitlich begrenztes Sitzungs-Ticket ausstellt.
Ergebnis: SSO-fähige Schnittstelle, die für Web-/SaaS-Clients wiederverwendbar ist (keine c-entron-spezifischen Credentials nötig, sofern Konto verknüpft).
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md:150-157 - Ticket-Erstellung mit `expireDate = DateTime.Now.AddMinutes(30)`
- [PRIMÄR] src/webservice/Centron.Controllers/Controllers/Unversioned/JwtAuthController.cs (referenziert in Doku Zeile 395) - `/jwt/login` Endpoint
- [KONTEXT] src/backend/Centron.BL/Administration/Logins/Auth/OpenIdConnectAuthenticator.cs (Doku Zeile 397) - User-Lookup per oid-Claim
Prüfidee: Verifizieren der Ticket-Lebensdauer und ob ein Refresh-Mechanismus existiert (nicht in Doku beschrieben).
Konsolidierungshinweis: Detaillierung von ARCH-02.
Status: belegt
---
### Kandidat ARCH-04
Ebene: SyRS
Typ: Sicherheit
Akteur: Endanwender, Administrator
Vorbedingung: Benutzer hat einen Zwei-Faktor-Schlüssel in der Personalverwaltung hinterlegt
Fakt: Es existiert eine TOTP-basierte Zwei-Faktor-Authentifizierung (`TwoFactorAuthenticationBL`, `Centron.Core.GoogleAuthenticator.TwoFactorAuthenticator`, Entität `TwoFactorAuthLastLogin`). `ValidateAuthenticationPin` prüft eine eingegebene PIN gegen den hinterlegten Schlüssel.
Aussage: Das System soll optional eine Zwei-Faktor-Authentifizierung (TOTP, z.B. Authenticator-App) pro Benutzer als zusätzliche Absicherung des Logins unterstützen.
Ergebnis: Zusätzliche Sicherheitsstufe für sensible Konten; relevant für SaaS-Compliance-Anforderungen (z.B. Zugriffsschutz bei extern erreichbarem Login).
Belege:
- [PRIMÄR] src/backend/Centron.BL/TwoFactorAuthenticator/TwoFactorAuthenticationBL.cs:43-54 - ValidateAuthenticationPin nutzt GoogleAuthenticator.TwoFactorAuthenticator.ValidatePin
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/Administration/TwoFactorAuthLastLogin.cs - Entität für letzten 2FA-Login
- [KONTEXT] src/shared/Centron.Core/GoogleAuthenticator/TwoFactorAuthenticator.cs, src/shared/Centron.Core/TotpAuth/* - TOTP-Implementierung
Prüfidee: Prüfen, ob 2FA erzwingbar (Pflicht) konfiguriert werden kann oder rein optional ist; wie Wiederherstellung bei Verlust des Geräts erfolgt (nicht recherchiert).
Konsolidierungshinweis: -
Status: belegt; Umfang (Pflicht vs. optional) nicht abschließend geklärt [HYPOTHESE: es fehlt Beleg für eine erzwingende Policy]
---
### Kandidat ARCH-05
Ebene: StRS
Typ: funktional / Lizenzierung
Akteur: c-entron-Vertrieb, Kunde, Systemadministrator
Vorbedingung: Kunde hat einen Lizenzvertrag
Fakt: Lizenzen sind GUID-basierte Merkmale mit optionalem `count`, `valid until date`, `valid until version`. Es wird zwischen `Applications` (dürfen sich am Web-Service anmelden, Liste in `ApplicationKind.cs`, ca. 40 Einträge z.B. Centron, ServiceBoard, WebCart, PasswordManager, Outlook Add-In) und reinen Einzel-Feature-Lizenzen (`LicenseGuids.cs`) unterschieden. Single Source of Truth ist ein zentraler Lizenzserver.
Aussage: Das System soll ein zentrales, GUID-basiertes Lizenzmodell mit Zähler-, Ablaufdatum- und Versionsbindung besitzen, das sowohl den Zugang ganzer Anwendungen als auch einzelner Features steuert.
Ergebnis: Feingranulare kommerzielle Steuerung von Funktionsumfang und Zugriff; zentrale Voraussetzung für Feature-Gating in einer SaaS-Variante (z.B. Tarif-/Paketmodell).
Belege:
- [PRIMÄR] docs/reference/security/licensing-system.md:1-44 - Beschreibung GUID/count/valid until date/valid until version, Applications vs. Only Licenses
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs:11-53 - ca. 40 ApplicationKind-Einträge mit LicenseGuids, teils mit `licenseUsageKind: LicenseUsageKind.PerUser`, `expirationKind`
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 - ILicenseManager Interface (HasLicense, GetLicenseCount, CheckLicense)
Prüfidee: Klären, ob Lizenzprüfung offline (Dongle/Cache) funktionsfähig bleibt und wie oft synchronisiert wird (`FileLicenseCache`, `UpdateLicenseInterval`).
Konsolidierungshinweis: Basis für alle modulspezifischen "nur mit Lizenz X verfügbar"-Anforderungen in den Fachclustern.
Status: belegt
---
### Kandidat ARCH-06
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Systemadministrator
Vorbedingung: Anwendung läuft im DEBUG-Build (Entwicklungsumgebung)
Fakt: `DeveloperSecurity.cs` ersetzt in DEBUG-Builds alle E-Mail-Adressen außerhalb der Domain `nexoware.com` automatisch durch `test@nexoware.com`, um versehentliches Versenden an echte Kunden zu verhindern. In RELEASE-Builds ist dieser Schutz nicht aktiv.
Aussage: Das System soll in Entwicklungs-/Testumgebungen automatisch verhindern, dass E-Mails an reale externe Empfänger versendet werden.
Ergebnis: Reduziertes Risiko von Datenlecks/fehlgeleiteter Kommunikation während Entwicklung und Test; Hinweis für Testkonzept einer SaaS-Neuimplementierung (Sandbox-Mailing-Regel sollte übernommen werden).
Belege:
- [PRIMÄR] docs/reference/security/developer-security.md:11-23 - Beschreibung des Verhaltens inkl. Domainregel
Prüfidee: Verifizieren, dass die Regel tatsächlich in `DeveloperSecurity.cs` so implementiert ist (Doku nicht Code gelesen) und ob ein äquivalenter Schutz für RELEASE-Testinstanzen fehlt.
Konsolidierungshinweis: -
Status: belegt; Basis nur Dokumentation, Quellcode `DeveloperSecurity.cs` nicht gegengelesen [HYPOTHESE: exakte Implementierungsdetails ungeprüft]
---
### Kandidat ARCH-07
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Modularität / Erweiterbarkeit)
Akteur: Entwickler, Systemarchitekt
Vorbedingung: -
Fakt: Fachmodule implementieren `ICentronAppModuleController` (ID, ModuleName, Description, Icons, MainCategory, SupportsConnectionTypes, CreateModuleInstance, GetSettings, GetRights, Dispose) und werden zentral in `ModuleRegistration.cs` registriert. Aktuell sind 84 Module über `ModuleRegistrationItem.For<T>(...)` eingetragen, gruppiert in 18 Hauptkategorien (`CentronModuleCategory`: MyCentron, Sales, Ticket, Contract, Billing, DataExchange, Logistic, Purchasing, Controlling, Administration, BaseData, PasswordManager, Help, Tests, Automate, Production, QM, NexowareConnect).
Aussage: Das System soll Fachfunktionen als eigenständige, über ein einheitliches Interface registrierte Module bereitstellen, die zur Laufzeit anhand von Rechte- und Feature-Flag-Prüfung ein-/ausgeblendet werden.
Ergebnis: Plugin-artige, kategorisierte Modularchitektur als fachliche Gliederung des Gesamtsystems; direkte Vorlage für die Bounded-Context-/Microservice-Gliederung einer Web-Neuimplementierung.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI.Extension/Modules/ICentronAppModuleController.cs:11-71 - vollständiges Interface
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs:414-416 sowie Zählung (grep) - 84 ModuleRegistrationItem.For-Aufrufe
- [PRIMÄR] src/backend/Centron.Interfaces/UI/Modules/CentronModuleCategory.cs:3-23 - 18 Kategorien
- [SEKUNDÄR] docs/guides/ui/create-module.md:1-116 - Entwickler-Anleitung zur Modulerstellung
Prüfidee: Kategorien gegen die tatsächlich in den Fachclustern untersuchten Module abgleichen (Vollständigkeitscheck der Systemübersicht).
Konsolidierungshinweis: Liefert die Rahmen-Taxonomie für alle anderen RRE-Cluster (jedes Fachcluster sollte sich einer/mehreren CentronModuleCategory zuordnen lassen).
Status: belegt
---
### Kandidat ARCH-08
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Administrator, Endanwender
Vorbedingung: Modul ist registriert
Fakt: Jede `ModuleRegistrationItem.For<T>` Registrierung erhält einen optionalen Rechte-Ausdruck (`Expression<Func<bool>> rightsCheck`, z.B. `Helper.HasAnyRight(...)`) und einen optionalen Feature-Flag-Check (`Func<bool> moduleFeatureCheck`, z.B. `() => ModuleFeatures.IsThingiesAvailable` oder `() => Debugger.IsAttached`). `ModuleRightsExpressionParser` wertet die Rechte-Ausdrücke zur Laufzeit aus (`CheckRights`, `GetRights`).
Aussage: Das System soll die Sichtbarkeit jedes Fachmoduls unabhängig über (a) ein deklaratives Rechtesystem und (b) Feature-Flags steuern können, ohne Codeänderung am Modul selbst.
Ergebnis: Feingranulare Zugriffssteuerung und kontrollierte Feature-Auslieferung (z.B. Module "in Entwicklung" ausblenden); Vorlage für Rollen-/Rechtekonzept einer SaaS-Variante.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs:910-951 - Klasse ModuleRegistrationItem mit CheckModuleFeatures/CheckRights/GetRights
- [SEKUNDÄR] docs/guides/ui/create-module.md:105-116 - Beschreibung "erster Parameter Rechte, zweiter Parameter Feature-Flag"
- [KONTEXT] CentronRights.md:1-80 - Beispielhafte, granulare Rechte inkl. "restricting rights" (nur eigene/nur eigene Filiale)
Prüfidee: Prüfen, ob Rechte pro Mandant/Filiale unterschiedlich vergeben werden können (Hinweis "nur eigene Filiale" in CentronRights.md).
Konsolidierungshinweis: Ergänzt ARCH-07; Rechte-Details sind Gegenstand der Fachcluster, hier nur das Rahmenkonzept.
Status: belegt
---
### Kandidat ARCH-09
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Übertragbarkeit / Anpassbarkeit)
Akteur: Entwickler, Drittanbieter/Partner
Vorbedingung: DLLs liegen im Unterordner "Extensions" des Anwendungsverzeichnisses
Fakt: `ExtensionLogic.LoadExtensionEngine()` nutzt MEF (`System.ComponentModel.Composition`, `DirectoryCatalog`) um zur Laufzeit alle `*.dll` im Ordner "Extensions" zu laden und exportierte `ICore`-Implementierungen zu sammeln; `RegisterExtensions()`/`UnregisterExtensions()` rufen `Register(CentronApplication.Instance)`/`Unregister()` auf jeder gefundenen Extension auf.
Aussage: Das System soll eine Plugin-Schnittstelle bereitstellen, über die zusätzliche Erweiterungen als separate Assemblies zur Laufzeit geladen und in die Anwendung integriert werden können, ohne den Kern neu zu kompilieren.
Ergebnis: Erweiterbarkeit für Partner-/Individualintegrationen; architektonisches Merkmal, das bei einer Web-Neuimplementierung durch ein äquivalentes Plugin-/Extension-API (z.B. Webhooks, serverseitige Module) ersetzt werden müsste.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Extension/ExtensionLogic.cs:29-52 - LoadExtensionEngine mit DirectoryCatalog/CompositionContainer
- [PRIMÄR] src/centron/Centron.WPF.UI/Extension/ExtensionLogic.cs:54-67 - RegisterExtensions
- [SEKUNDÄR] src/centron/Centron.WPF.UI/App.xaml.cs:322-325 - DoInitializeExtensionEngine als Teil der Startsequenz
Prüfidee: Prüfen, wie viele produktive Extensions aktuell existieren und ob die Schnittstelle stabil versioniert ist.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ARCH-10
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Zuverlässigkeit / Reife)
Akteur: Endanwender
Vorbedingung: Anwendungsstart mit Kommandozeilenargumenten (z.B. Deep-Link via URL-Protokoll)
Fakt: `StartupArgSynchronizer` verwendet einen computerweiten, pfadgebundenen `Mutex`, um zu erkennen, ob bereits eine Instanz der c-entron.NET läuft. Falls ja, werden Argumente über eine Memory-Mapped-File (`FileArgSeparator`, `ArgFileLength=1024`) an den laufenden Prozess übergeben statt eine zweite Instanz zu starten; bei mehreren laufenden Prozessen wird ein Auswahldialog (`SelectTargetProcessView`) gezeigt.
Aussage: Das System soll sicherstellen, dass pro Benutzer/Pfad nur eine Instanz der Anwendung aktiv ist, und Start-Argumente/Deep-Links an eine bereits laufende Instanz weiterleiten können.
Ergebnis: Konsistentes Single-Instance-Verhalten und URL-Protokoll-Aktivierung (z.B. aus E-Mail/Browser heraus ein bestimmtes Modul öffnen); bei Web-Migration äquivalent durch Tab-/Session-Handling und Deep-Links zu ersetzen.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/StartupArgs/StartupArgSynchronizer.cs:18-49 - Mutex-basierte Instanzerkennung
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:97-126 - Nutzung im Startup (TryPassArgsToRunningApp, ReceivedArgs)
- [KONTEXT] src/centron/Centron.WPF.UI/StartupArgs/SelectTargetProcessView.xaml - UI bei mehreren laufenden Instanzen
Prüfidee: Testen des Verhaltens bei mehreren parallel angemeldeten Terminal-Server-Sitzungen (RDP/Citrix) desselben Benutzers.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ARCH-11
Ebene: StRS
Typ: nicht-funktional (ISO25010: Kompatibilität / Systemumgebung)
Akteur: IT-Administrator, Endanwender
Vorbedingung: -
Fakt: Der Client (`Centron.WPF.UI.csproj`) zielt auf `net10.0-windows`, ist ein `WinExe` (WPF, WinForms-Abhängigkeiten wie `System.Windows.Forms.Screen`), bindet COM-Interop zu Microsoft Outlook (`Microsoft.Office.Interop.Outlook`) sowie ein modifiziertes Drittanbieter-TAPI-Modul (`Traysoft.AddTapi.dll`) ein. `global.json` fixiert die .NET-SDK-Version auf 10.0.100.
Aussage: Das System (c-entron.NET) soll als natives Windows-Desktop-Programm mit lokalen Windows-/Outlook-/TAPI-Abhängigkeiten betrieben werden und ist somit nicht plattformunabhängig.
Ergebnis: Klare Systemvoraussetzung "Windows + .NET 10 Runtime + ggf. Outlook/TAPI-Hardware" für den Bestandsclient; zentrale Motivation für die geplante Web-/SaaS-Neuimplementierung (Plattformunabhängigkeit als Ziel).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Centron.WPF.UI.csproj:1-24 - TargetFramework net10.0-windows, WinExe, COM-Interop-Referenzen
- [PRIMÄR] global.json:1-6 - SDK-Version 10.0.100
- [SEKUNDÄR] docs/reference/architecture/tapi.md:1-10 - TAPI-Integration nur für Windows-Produkte (c-entron.NET, Outlook Add-In, ServiceBoard)
Prüfidee: Abgleich mit Kunden-Systemvoraussetzungsdokument (falls vorhanden) auf weitere Hardware-/Software-Voraussetzungen (z.B. Terminalserver-Freigabe).
Konsolidierungshinweis: Begründet die grundsätzliche Zielsetzung des RRE-Projekts (StRS "Business Need").
Status: belegt
---
### Kandidat ARCH-12
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Internationalisierbarkeit / Anpassbarkeit)
Akteur: Endanwender
Vorbedingung: -
Fakt: Lokalisierung erfolgt über .NET-Standard-Ressourcendateien (.resx) pro Assembly (`LocalizedStrings.resx` = Deutsch/Standard, `LocalizedStrings.en.resx` = Englisch), gesteuert über `CultureInfo.CurrentUICulture`. Getrennte Ressourcen existieren für WPF-UI-Layer und Business-Logic-Layer. Web-Service-Antworten werden über den HTTP-Header `Accept-Language` lokalisiert.
Aussage: Das System soll Benutzeroberfläche und fachliche Meldungen mehrsprachig (mind. Deutsch als Standard, Englisch als Zusatzsprache) über eine schichtenweise Ressourcendatei-Struktur bereitstellen, wobei Web-Service-Aufrufe die Sprache über den Accept-Language-Header steuern können.
Ergebnis: Grundlage für Mehrsprachigkeit im gesamten System; Struktur (getrennte Ressourcen je Schicht/Assembly) ist relevant für Übertragung in eine Web-Architektur (z.B. i18n-Framework, Sprachverhandlung über HTTP).
Belege:
- [PRIMÄR] docs/guides/ui/localization.md:1-35 - Ressourcenstruktur, CultureInfo.CurrentUICulture
- [PRIMÄR] docs/guides/ui/localization.md:275-280 - Accept-Language Header Beispiel für Web-Service-Calls
Prüfidee: Vollständigkeitsprüfung, ob wirklich alle Layer (auch Webservice-Fehlermeldungen) konsistent lokalisiert sind (laut Doku-Beispiel nur "einige" Codepfade).
Konsolidierungshinweis: Ergänzt durch ARCH-13 (Sprachauswahl im Client eingeschränkt).
Status: belegt
---
### Kandidat ARCH-13
Ebene: StRS
Typ: nicht-funktional (ISO25010: Internationalisierbarkeit) — Abweichung/Workaround
Akteur: Endanwender
Vorbedingung: LoginDialog wird angezeigt
Fakt: Im `LoginDialogViewModel` wird die Sprachliste initial nur mit `de-DE` befüllt; `en-US` wird nur hinzugefügt, wenn `IsDevBuild` (Compile-Symbol `DEV_BUILD`) aktiv ist. Standardsprache ist explizit "German is the default language" (Kommentar im Code). Produktivbenutzer können in der UI somit i.d.R. nur Deutsch wählen, obwohl englische Ressourcendateien im Code existieren.
Aussage: Das System soll (Soll-Zustand im Ist offen) die im Backend vorhandene Mehrsprachigkeit (Deutsch/Englisch) auch produktiv über die Login-/Spracheinstellung zugänglich machen.
Ergebnis: Diskrepanz zwischen technischer Lokalisierungs-Infrastruktur (ARCH-12) und tatsächlich für Endanwender nutzbarer Sprachauswahl; für SaaS-Zielbild zu klären, ob Mehrsprachigkeit ein echtes Geschäftsziel ist oder nur Entwickler-/Testzweck.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:93-98 - Languages.Add(en-US) nur `if (IsDevBuild)`
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:197-206 - IsDevBuild liest Compile-Symbol DEV_BUILD
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:239 - Kommentar "German is the default language."
Prüfidee: Produktentscheidung/Product Owner befragen, ob Englisch-Support als Geschäftsziel für die Web-Neuimplementierung gilt (aktuell nur "verstecktes" Dev-Feature).
Konsolidierungshinweis: Präzisiert ARCH-12; wichtig für StRS "Stakeholder-Bedürfnisse: internationale Kunden".
Status: belegt; Soll-Anforderung nicht ableitbar [HYPOTHESE: fehlende Produktentscheidung, ob Mehrsprachigkeit für Endkunden freigeschaltet werden soll]
---
### Kandidat ARCH-14
Ebene: StRS
Typ: funktional
Akteur: Kunde mit mehreren Gesellschaften/Niederlassungen, Administrator
Vorbedingung: Lizenz "branch functionality" vorhanden (laut licensing-system.md Beispiel)
Fakt: Es existiert ein Modul "Mandantenverwaltung" (`MandatorManagementAppModuleController`, ID `{717AD6A2-...}`, Kategorie Administration) sowie ein separates "BranchManagement" (Filialverwaltung, Nummernkreise) unter demselben Namensraum `Administration.MandatorManagement`.
Aussage: Das System soll die Verwaltung mehrerer Mandanten/Gesellschaften bzw. Filialen (Niederlassungen) innerhalb einer c-entron-Instanz unterstützen, inklusive eigener Nummernkreise je Filiale.
Ergebnis: Mehrmandantenfähigkeit auf Ebene "mehrere Unternehmenseinheiten in einer Datenbank" (kein Hinweis auf Datenbank-pro-Kunde-Mandantentrennung im Sinne von SaaS-Multi-Tenancy); wichtig für SyRS-Datenmodell-Entscheidung bei Neuimplementierung.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/MandatorManagementAppModuleController.cs:9-45 - Modul "Mandanten Verwaltung"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/BranchManagement/* - BranchManagementView/ViewModel, NumberGroupsViewModel (Dateiliste)
- [KONTEXT] CentronRights.md:14-26 - Rechte mit Filial-Einschränkung ("nur eigene Filiale") als Beleg für aktive fachliche Nutzung von Filialen/Mandanten in Rechten
Prüfidee: Klären, ob "Mandant" hier = rechtlich eigenständige Gesellschaft (mit eigener Buchhaltung) oder nur Organisationseinheit ist; Datenmodell (MandantI3D-Spalten) verifizieren.
Konsolidierungshinweis: Grundlegend für Datenmodell-Cluster (Rechnungswesen/Finance) — dort ggf. mit ARCH-14 verknüpfen statt duplizieren.
Status: belegt; genaue fachliche Abgrenzung "Mandant" vs. "Filiale" nicht abschließend verifiziert [HYPOTHESE: Begriffsdefinition nur aus Namensgebung/Icon abgeleitet, keine Fachdoku gelesen]
---
### Kandidat ARCH-15
Ebene: SwRS
Typ: Daten / nicht-funktional (ISO25010: Wartbarkeit)
Akteur: Entwickler (indirekt: alle Endanwender über Datenkonsistenz)
Vorbedingung: -
Fakt: Die Architektur trennt strikt drei Objekttypen: `Entity` (BL-Layer, NHibernate-Mapping via Fluent NHibernate, Primärschlüssel "I3D", ausschließlich virtuelle Properties, keine Logik), `DTO` (WebService/Logics-Layer, `[DataContract]`/`[DataMember]`, `List<T>` statt `IEnumerable<T>` zur JSON-Serialisierung, `DateTime?` statt `DateTime` wegen .NET-Default-Wert-Problem) und `ViewModel` (UI-Layer). Konvertierung Entity→DTO über `ObjectMapper.Map<TEntity,TDTO>()`, DTO→Entity manuell (ObjectMapper hierfür explizit verboten).
Aussage: Das System soll intern konsequent zwischen Datenbank-Entities, Transport-DTOs und UI-ViewModels trennen und definierte Konvertierungsregeln (automatisiertes Mapping nur Entity→DTO, manuelles Mapping DTO→Entity) einhalten.
Ergebnis: Klare Schichtentrennung als Wartbarkeits-/Kapselungsprinzip; wesentliche Randbedingung für Neuimplementierung des Datenzugriffs (z.B. Wahl von EF Core/Dapper und äquivalentem DTO-Konzept für eine Web-API).
Belege:
- [PRIMÄR] docs/reference/architecture/dtos-and-entities.md:15-118 - vollständige Beschreibung Entity/DTO/Mapping-Regeln
Prüfidee: Stichprobe an realen Entity/DTO-Paaren (z.B. Helpdesk/Ticket) auf Einhaltung der Regeln (List<T>, DateTime?, kein ObjectMapper bei DTO→Entity).
Konsolidierungshinweis: Basis-Pattern, das in allen Fachclustern bei Datenmodell-Anforderungen als Kontext zitiert werden kann statt neu zu belegen.
Status: belegt
---
### Kandidat ARCH-16
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Wartbarkeit) / Schnittstelle
Akteur: Entwickler
Vorbedingung: -
Fakt: Fehlerbehandlung folgt einem zweistufigen Muster: `Result`/`Result<T>` (Business-Logic-Layer, Status Success/Error/Warning, Factory-Methoden `AsSuccess`/`AsError`/`AsWarning`/`FromException`) wird über `Response.FromBLResult(...)`/`Response<T>.FromBLResult(...)` in ein API-`Response`-Objekt (Status Success/Failed, `MessageCode`) übersetzt; `Warning` wird auf API-Ebene als `Success` gemappt.
Aussage: Das System soll einen einheitlichen, geschichteten Result/Response-Mechanismus für Operationsergebnisse und Fehlerbehandlung verwenden, der in der Business-Logik feiner granuliert (inkl. Warnungen) als an der API-Grenze.
Ergebnis: Konsistentes Fehler-/Statusmodell über alle Schichten; direkte Vorlage für ein äquivalentes Response-Envelope-Format einer REST/GraphQL-API in der Web-Neuimplementierung.
Belege:
- [PRIMÄR] docs/reference/architecture/results-and-responses.md:18-147 - Result/Response-Klassenstruktur, Statuswerte, Mapping-Logik
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs:24-59 - clientseitige Zuordnung von `MessageCode` zu lokalisierten Fehlermeldungen (z.B. RightCheckFailed, LicenseNotFound, MandatoryFieldsNotFilled)
Prüfidee: Prüfen, ob alle Webservice-Endpunkte konsequent `Response`/`Response<T>` statt roher Exceptions zurückgeben.
Konsolidierungshinweis: Ergänzt ARCH-15; beide bilden zusammen das SwRS-Basisdatenmodell/Fehlerkonzept, auf das Fachcluster verweisen sollten statt es zu wiederholen.
Status: belegt
---
### Kandidat ARCH-17
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Zuverlässigkeit)
Akteur: Endanwender, Support
Vorbedingung: Unbehandelte Exception oder unbeobachtete Task-Exception tritt auf
Fakt: `App.xaml.cs` registriert globale Handler (`DispatcherUnhandledException`, `TaskScheduler.UnobservedTaskException`), die an `CentronApplication.Instance.ExceptionHandler` (Typ `CentronExceptionHandler`) delegieren. Dieser kennt eine Liste bekannter, bewusst zu ignorierender Exceptions (mit Typ + Stacktrace-Marker, max. Rekursionstiefe 2) sowie eine Tabelle von `MessageCode`→lokalisierter Nutzermeldung.
Aussage: Das System soll unbehandelte Ausnahmen zentral abfangen, protokollieren (NLog) und dem Benutzer eine lokalisierte, verständliche Fehlermeldung anzeigen, statt abzustürzen, mit Ausnahme explizit als harmlos bekannter Fehlerbilder.
Ergebnis: Erhöhte gefühlte Stabilität der Desktop-Anwendung trotz Einzel-Ausnahmen; Verhaltens-Vorlage für zentrales Error-Handling/Logging-Konzept einer Web-Anwendung (globaler Error-Boundary + strukturiertes Logging).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:130-232 - Registrierung globaler Exception-Handler inkl. Fallback-MessageBox vor Initialisierung
- [PRIMÄR] src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs:18-85 - HandleException, ignorierte Exceptions, Message-Mapping
Prüfidee: Prüfen, ob äquivalentes zentrales Error-Handling auch auf Web-Service-Seite existiert (nicht recherchiert in diesem Cluster).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ARCH-18
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Effizienz / Startzeitverhalten)
Akteur: Endanwender
Vorbedingung: Anwendungsstart
Fakt: Der Start läuft über eine sichtbare Splash-Screen-Sequenz mit fünf benannten, sequentiellen Initialisierungsschritten (`DoInitializeClassContainer`, `DoInitializeDevExpressControls`, `DoInitializeObjectMapper`, `DoInitializeDaoFactory`, `DoInitializeExtensionEngine`), jeweils mit lokalisiertem Fortschrittstext. Vor der Anmeldung wird zusätzlich `ProfileOptimization` (.NET Startup-Profil) aktiviert und mehrere produktspezifische Workarounds (FastReport, DevExpress-Ribbon) ausgeführt.
Aussage: Das System soll dem Benutzer während des Anwendungsstarts sichtbares, stufenweises Feedback über den Initialisierungsfortschritt geben und dabei zeitkritische Subsysteme (DB-Zugriff, Objektmapper, Extension-Engine, UI-Theme) in definierter Reihenfolge vorbereiten.
Ergebnis: Vorhersehbare, für den Benutzer nachvollziehbare Startsequenz; bei Web-Migration i.d.R. obsolet (Server-seitiges Preloading statt Client-Splash), aber die fachliche Reihenfolge (Konfiguration→Datenbank→Objektmapper→Erweiterungen) bleibt als Abhängigkeitsgraph relevant.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:236-285 - DoInitializeWithSplashScreen mit Actions-Liste
- [SEKUNDÄR] src/centron/Centron.WPF.UI/App.xaml.cs:287-360 - Einzelmethoden der Initialisierungsschritte
Prüfidee: Startzeit messen und mit Zielwert (falls vorhanden) vergleichen; klären ob preload (DAOFactory/ObjectMapper) bei Web-Service-Verbindung übersprungen wird (Code zeigt: ja, abhängig von `IsDefaultConnectionAWebServiceConnection`/`RememberLogin`).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ARCH-19
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Benutzbarkeit)
Akteur: Endanwender (Power-User)
Vorbedingung: Anwendung läuft
Fakt: Es existiert eine "Command Palette" (`Start/CommandPalette/*`, u.a. `CommandPaletteViewModel`, diverse `*CommandProvider`-Klassen für Kundensuche, Artikelsuche, Belegsuche, Ticketnummern, Modul-Liste etc.) als zentrales Tastatur-gesteuertes Schnellzugriffs-/Such-Werkzeug über viele Fachbereiche hinweg.
Aussage: Das System soll eine anwendungsweite, tastaturbasierte Befehls-/Suchpalette bereitstellen, über die Module, Datensätze (Kunden, Artikel, Belege, Tickets, Seriennummern) und Aktionen schnell gefunden und ausgeführt werden können.
Ergebnis: Zentrales, cross-modulares Produktivitätsfeature; sollte als eigenständige, modulunabhängige Querschnittsfunktion auch in einer Web-Neuimplementierung erhalten bleiben (z.B. als globale Suchleiste/Command-K-Pattern).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Start/CommandPalette/CommandPaletteViewModel.cs (Dateiname/Struktur) - zentrale ViewModel-Klasse
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Start/CommandPalette/Provider/*.cs (Dateiliste, u.a. CustomerSearchCommandProvider, ArticleSearchCommandProvider, DocumentSearchCommandProvider, ReceiptNumberCommandProvider, HelpdeskNumberCommandProvider, ModuleListCommandProvider) - modulübergreifende Provider
Prüfidee: Nutzungshäufigkeit/Bedeutung beim Kunden erfragen (aus Code allein nicht ableitbar, ob zentrales oder Nischenfeature).
Konsolidierungshinweis: -
Status: belegt; Bedeutung/Priorität aus Endnutzersicht nicht belegt [HYPOTHESE: keine Nutzungsstatistik verfügbar]
---
### Kandidat ARCH-20
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Benutzbarkeit) / Daten
Akteur: Endanwender
Vorbedingung: Benutzer passt Ansicht (Grid-Spalten, Fensteranordnung, Docking) an
Fakt: Es existiert eine eigene Layout-Persistenz-Schicht (`Layout/*LayoutSerializer.cs`) für diverse DevExpress-Steuerelemente (GridControl, TreeListControl, DockLayoutManager, NavBarControl, ComboBoxEdit, DateEdit u.a.), die Benutzeroberflächen-Zustand (Spaltenreihenfolge, Fensterlayout etc.) persistiert und wiederherstellt (`ICustomLayoutSavingControl`, `ILayoutSerializerOnlyIfSaveLayoutActive`).
Aussage: Das System soll benutzerspezifische Anpassungen von Ansichten (Spalten, Fensteranordnung, Docking-Layout) dauerhaft je Benutzer speichern und beim nächsten Start wiederherstellen.
Ergebnis: Personalisierung der Arbeitsumgebung als etabliertes Feature; funktionale Anforderung, die in einer Web-Anwendung durch äquivalente Persistenz von UI-Zustand (z.B. je Benutzer serverseitig gespeicherte Grid-/Layout-Einstellungen) nachgebildet werden müsste.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Layout/GridControlLayoutSerializer.cs, DockLayoutManagerLayoutSerializer.cs, TreeListControlLayoutSerializer.cs (Dateiliste) - konkrete Serializer je Steuerelement
- [KONTEXT] src/centron/Centron.WPF.UI/Layout/ILayoutSerializerOnlyIfSaveLayoutActive.cs - Hinweis auf konfigurierbares "Layout speichern"-Verhalten
Prüfidee: Prüfen, wo (Registry/DB/Datei) das Layout gespeichert wird und ob es geräteübergreifend synchronisiert wird (nicht recherchiert).
Konsolidierungshinweis: -
Status: belegt; Speicherort/Synchronisationsverhalten nicht verifiziert [HYPOTHESE: fehlende Information zu Speicherort]
---
### Kandidat ARCH-21
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Funktionale Eignung) / Datenschutz
Akteur: Produktmanagement, Endanwender (indirekt betroffen)
Vorbedingung: Anwendung ist eingeloggt
Fakt: `CentronAnalyticsManager` abonniert `ModuleOpenedEvent`/`ModuleClosedEvent` über einen zentralen `EventAggregator` und sendet Nutzungsereignisse (Modul-Nutzung) über einen `AnalyticEventsManager`, identifiziert über eine aus der Lizenz abgeleitete `dongleId` (Kundennummer) und die interne Mitarbeiter-ID (`employeeId`). Fehlen beide IDs, wird das Tracking deaktiviert ("Initialisiert...NULL. No events will be tracked!").
Aussage: Das System soll Nutzungstelemetrie (welche Module wie genutzt werden) kundenbezogen (Lizenznummer) und benutzerbezogen erfassen können, sofern eine gültige Lizenz- und Benutzerzuordnung vorliegt.
Ergebnis: Grundlage für produktseitige Nutzungsauswertung; für SaaS-Neuimplementierung datenschutzrechtlich (DSGVO) zu bewerten, da personenbezogene Nutzungsdaten erfasst werden.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Managers/CentronAnalyticsManager.cs:23-50 - Initialize(), Subscribe auf ModuleOpenedEvent/ModuleClosedEvent, dongleId/employeeId-Ermittlung
Prüfidee: Prüfen, ob eine Einwilligung/Opt-out für Telemetrie existiert und wie/wo die Daten gespeichert werden (nicht im gelesenen Ausschnitt ersichtlich).
Konsolidierungshinweis: Ggf. mit DSGVO-Modul (`Modules.Administration.DSGVO`, siehe ModuleRegistration.cs Zeile 12) im Sicherheits-/Datenschutz-Cluster verknüpfen.
Status: belegt; Opt-out/Einwilligungsmechanismus nicht verifiziert [HYPOTHESE: fehlende Information zu Consent-Handling]
---
### Kandidat ARCH-22
Ebene: SyRS
Typ: Schnittstelle
Akteur: Endanwender (Telefonie-Nutzer), Administrator
Vorbedingung: TAPI-fähige Telefonanlage/Software-Client vorhanden
Fakt: Telefonie-Integration erfolgt über die kommerzielle Komponente "TraySoft AddTAPI.NET", die firmenintern für .NET 5/6-Kompatibilität modifiziert wurde (`ProcessIncomingCall` Workaround wegen entferntem `BeginInvoke`). Genutzt in c-entron.NET (`PhoneManager.cs`, `TapiPhoneConnectionManager.cs`), Outlook Add-In und ServiceBoard.
Aussage: Das System soll eine TAPI-basierte Telefonieanbindung (eingehende/ausgehende Anrufe, Rufnummererkennung) über eine modifizierte Drittanbieterkomponente bereitstellen, die produktübergreifend (Desktop-Client, Outlook Add-In, ServiceBoard) genutzt wird.
Ergebnis: Cross-Produkt-Abhängigkeit von einer proprietären, Windows-gebundenen TAPI-Bibliothek; kritischer Migrationsaspekt für Web-/SaaS-Variante (TAPI ist ein reines Windows-Desktop-Konzept, erfordert Alternativkonzept z.B. Cloud-Telefonie/CTI-API).
Belege:
- [PRIMÄR] docs/reference/architecture/tapi.md:1-36 - Komponente, Produkte, Modifikation, Debugging-Hinweise
- [KONTEXT] src/centron/Centron.WPF.UI/Managers/PhoneManager.cs, TapiPhoneConnectionManager.cs (Dateiliste) - produktinterne Nutzung
Prüfidee: Umfang der TAPI-Nutzung beim Kunden erheben (Pflichtfeature oder Nischenfunktion) für Entscheidung über Migrationsstrategie.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat ARCH-23
Ebene: StRS
Typ: funktional
Akteur: Kunde des Kunden (Web-Account-Benutzer)
Vorbedingung: Web-Account wurde in c-entron.NET Adressstamm angelegt, Sonderpreise hinterlegt
Fakt: README.md beschreibt "WebCart" als Feature primär für Kunden der Kunden: Login als Web-Account bei "c-entron Nexus" (separate Web-Anwendung, "c-entron Web"), Artikelanzeige basiert auf hinterlegten "Sonderpreisen" im c-entron.NET Adressstamm, Zugriff über Menüpunkt "Shop".
Aussage: Das System soll einen webbasierten Bestellkanal (WebCart) für Endkunden der c-entron-Kunden bereitstellen, dessen Sortiment/Preise zentral im ERP (c-entron.NET) gepflegt werden.
Ergebnis: Bereits vorhandener Web-Kanal (c-entron Nexus) als Blaupause/Vorstufe für die geplante SaaS-Neuimplementierung — zeigt, dass Teile des Systems bereits heute web-basiert sind und mit dem ERP-Kern über Web-Accounts/Sonderpreise integriert sind.
Belege:
- [PRIMÄR] README.md:1,29-35 - Beschreibung WebCart, Web-Account-Login, Sonderpreise, "Shop"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/WebCart (Namensraum in ModuleRegistration.cs Zeile 40) - zugehöriges WPF-Verwaltungsmodul
Prüfidee: Architektur von "c-entron Nexus" (separates Blazor-Projekt laut README-Kontext "azure-blazor") im Detail untersuchen — ggf. eigener Cluster/Repository-Bereich außerhalb des hier untersuchten Scopes.
Konsolidierungshinweis: Wichtiger Kontext für ein SaaS-Zielbild: c-entron Nexus zeigt bereits Web-first-Muster (Blazor/DevExpress-Blazor-Komponenten), das ggf. als Ausgangspunkt dient.
Status: belegt; Detailarchitektur von c-entron Nexus außerhalb des recherchierten Bereichs [HYPOTHESE: Nexus/Blazor-Code nicht gelesen, nur README]
---
### Kandidat ARCH-24
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Wartbarkeit) / MVVM
Akteur: Entwickler
Vorbedingung: -
Fakt: Alle recherchierten ViewModels (`LoginDialogViewModel`, Modul-ViewModels) implementieren/erben von DevExpress-MVVM-Basisklassen (`ViewModelBase`, `BindableBase`) sowie einer eigenen Basis `CentronBindableBase` (in `Centron.Core.Mvvm`). Views erben von einer eigenen `BaseModule`-Basisklasse (statt UserControl) für Fachmodule bzw. `BaseSettingControl` für Einstellungsseiten; Rechtevergabe, Initialisierung (`DoInitalize`) und Speichern (`DoSave`) folgen festen Konventionen.
Aussage: Das System soll ein einheitliches MVVM-Grundgerüst mit klar getrennten Verantwortlichkeiten (View: Anzeige/Ribbon, ViewModel: Zustand/Async-Init/Save, Container: Rechte-/Feature-Prüfung) für alle Fachmodule und Einstellungsseiten verwenden.
Ergebnis: Konsistente Entwicklungskonventionen als Wartbarkeitsfaktor; die eigentliche `mvvm-in-centron.md`-Referenzdokumentation ist inhaltsleer (Platzhalter "I don't know, but I would like to - please tell me."), das Muster musste daher aus Code-Konventionen (create-module.md, create-settings-page.md) rekonstruiert werden.
Belege:
- [PRIMÄR] docs/guides/ui/create-module.md:52-103 - BaseModule, IRibbonControlModule*, ViewModel-Konventionen
- [PRIMÄR] docs/guides/ui/create-settings-page.md:1-45 - BaseSettingControl, DoInitalize/DoSave/CanSave/DoAfterSave-Konvention, explizites Verbot eigener MessageBoxen bei Fehlern
- [KONTEXT] src/shared/Centron.Core/Mvvm/CentronBindableBase.cs (Dateiname) - eigene MVVM-Basisklasse
- [KONTEXT] docs/reference/architecture/mvvm-in-centron.md:1-3 - Dokument explizit als Platzhalter/unvollständig markiert
Prüfidee: `CentronBindableBase.cs` und mind. 2-3 reale ViewModel-Klassen lesen, um das Muster über Doku-Rekonstruktion hinaus zu verifizieren.
Konsolidierungshinweis: -
Status: belegt; Referenzdokumentation "mvvm-in-centron.md" ist explizit leer/unvollständig [HYPOTHESE: Muster aus Nachbardokumenten und Namenskonventionen rekonstruiert, nicht aus einer autoritativen MVVM-Spezifikation]
---
### Kandidat ARCH-25
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Aktivierung der Windows-Anmeldung (SSO) über Entra ID gewünscht
Fakt: Für OIDC ist neben der App-Registration in Azure AD eine Verknüpfung jedes c-entron-Benutzers mit seiner Microsoft-Entra-Object-ID (Spalte `OpenIdConnectSubjectIdentifier` in Tabelle `Sichbenu`) nötig, entweder per Self-Service-Endpoint (`POST /jwt/connect_accounts`) oder Admin-Zuweisung über die WPF-UI unter "Persönliche Einstellungen".
Aussage: Das System soll die Verknüpfung eines c-entron-Benutzerkontos mit einem externen Identitätsanbieter-Konto (Microsoft Entra ID) sowohl per Selbstbedienung durch den Benutzer als auch administrativ ermöglichen.
Ergebnis: Flexibles Account-Linking-Modell als Voraussetzung für produktives SSO; Vorlage für generisches "externe Identität verknüpfen"-Konzept bei SaaS mit mehreren Identity Providern.
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md:180-196 - Self-Service/Admin-Zuweisung, Endpoint-Tabelle
- [KONTEXT] src/centron/Centron.WPF.UI/Modules/MyCentron/PersonalSettings/OpenIdConnectAccount (Namensraum, ModuleRegistration.cs Zeile 137) - zugehöriges UI-Modul "Persönliche Einstellungen"
Prüfidee: Prüfen, ob Entkopplung (Verknüpfung aufheben) ebenfalls möglich ist und wie der Fall "Entra-Konto bereits mit anderem c-entron-User verknüpft" behandelt wird.
Konsolidierungshinweis: Ergänzt ARCH-02/ARCH-03.
Status: belegt
---
### Kandidat ARCH-26
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: c-entron-Kunde (Endkunde des Kunden), Web-Account-Benutzer
Vorbedingung: -
Fakt: Neben Mitarbeiter-Logins existiert ein separater Authentifizierungspfad `WebAccountAuthObject`/`WebAccountAuthenticator` sowie `WebLoginType.Customer` (vs. `WebLoginType.User`/`WebLoginType.Domain`), der eigene Kundenkonten (z.B. für WebCart/Web-Shop) gegenüber internen Mitarbeiterkonten unterscheidet.
Aussage: Das System soll zwischen internen Mitarbeiter-Logins und externen Kunden-("Web-Account")-Logins mit eigenem Authentifizierungspfad und eigenen Berechtigungen unterscheiden.
Ergebnis: Grundlage für ein zweistufiges Nutzermodell (intern/extern) im Gesamtsystem; direkt relevant für die Zielarchitektur eines Kundenportals in der SaaS-Variante.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs:89-95,122-123,163-186 - WebAccountAuthObject-Zweig, WebLoginType.Customer
- [KONTEXT] src/backend/Centron.Entities/Entities/Administration/Logins/WebAccount.cs (Dateiname) - eigene Entität für Web-Konten
Prüfidee: Rechte-/Rollenmodell für WebAccount-Benutzer im Detail prüfen (vermutlich stark eingeschränkt ggü. Mitarbeitern).
Konsolidierungshinweis: Ergänzt ARCH-23 (WebCart).
Status: belegt
---
### Kandidat ARCH-27
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Kompatibilität)
Akteur: Systemadministrator (Terminalserver-Betrieb)
Vorbedingung: Betrieb über Remote-Desktop-Sitzung (RDP/Terminalserver/Citrix)
Fakt: Es existiert (inzwischen deaktivierter, aber im Code dokumentierter) produktionsrelevanter Workaround-Code für den Fall, dass sich eine RDP-Sitzung neu verbindet: Dies löst laut Kommentar einen bekannten DevExpress-Performance-Bug aus (massive Verlangsamung nach Reconnect), wofür früher ein Warnhinweis mit Neustart-Option angezeigt wurde (Ticket 115706, seit 2024-05 testweise entfernt, Ticket erwähnt in Kommentar SKA 2024-05-08).
Aussage: Das System soll (historisch) den Betrieb über Remote-Desktop-Sitzungen mit Reconnect-Verhalten unterstützen und Performance-Einbußen nach Reconnect erkennen bzw. dem Benutzer eine Neustart-Option anbieten.
Ergebnis: Hinweis auf reale Betriebsumgebung "Terminalserver/RDP" als verbreitetes Deployment-Szenario beim Kunden; relevant für StRS "unterstützte Umgebungen", auch wenn der spezifische Workaround aktuell deaktiviert ist.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:151-155 - Auskommentierter SystemEvents.UserPreferenceChanged-Hook mit Verweis auf Ticket 147477/115706
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:464-526 - vollständige (tote, aber vorhandene) Implementierung SystemEventsOnUserPreferenceChanged inkl. Benutzertext zu RDP-Verbindungsabbruch
Prüfidee: Klären, ob der Workaround dauerhaft entfernt bleibt oder nur testweise; Terminalserver-Nutzung beim Kunden quantitativ erheben.
Konsolidierungshinweis: -
Status: belegt; Funktion aktuell im Code deaktiviert (auskommentiert) [HYPOTHESE: Unklar ob RDP-Betrieb weiterhin offizielle Systemvoraussetzung ist oder nur Altlast]
---
### Kandidat ARCH-28
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Active-Directory-Anmeldung konfiguriert (`ActiveDirectoryAuthEnabled`)
Fakt: `AuthenticatorFactory` unterscheidet klar zwischen dem global konfigurierten `SystemAuthenticationMethod` (None/Basic/ActiveDirectory/OpenIdConnect) und einer pro-Benutzer hinterlegten `AuthentificationKind` (CentronLogin/WindowsAuth[obsolet]/OpenIdConnectAuth). Bei Konflikt (z.B. Benutzer ist für WindowsAuth markiert, aber AD ist nicht korrekt konfiguriert) wird ein klar lokalisierter Fehler über `FailingAuthenticator` zurückgegeben statt eines stillen Fallbacks.
Aussage: Das System soll bei inkonsistenter Authentifizierungs-Konfiguration (z.B. Benutzer für einen nicht verfügbaren Auth-Mechanismus markiert) eine eindeutige, lokalisierte Fehlermeldung liefern statt unsicherer stiller Fallbacks.
Ergebnis: Robustheit/Nachvollziehbarkeit bei Fehlkonfiguration von Authentifizierungsmechanismen; wichtige Sicherheitsanforderung, die bei Multi-Provider-Login-Konzepten (SaaS) übernommen werden sollte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs:66-82 - FallbackAuthenticator mit FailingAuthenticator und lokalisierter Fehlermeldung `AuthenticatorFactory_FallbackMisconfiguredErrorMessage`
Prüfidee: End-to-End-Test: Benutzer mit AuthentificationKind=WindowsAuth bei deaktiviertem AD anmelden lassen, erwartete Fehlermeldung verifizieren.
Konsolidierungshinweis: Ergänzt ARCH-02.
Status: belegt
---
### Kandidat ARCH-29
Ebene: StRS
Typ: funktional
Akteur: Produktmanagement, Entwickler
Vorbedingung: -
Fakt: `ApplicationKind.cs` listet neben dem Kern-ERP ("NEXOWARE c-entron ERP") ca. 40 weitere, separat lizenzierte Anwendungen/Produkte im selben Ökosystem (u.a. Service-Board, Service-Board Online, c-entron Nexus, Outlook Add-In, PasswordManager, WebCart, WebSuitePro, DocumentSync, Riversuite-Familie [Inventory/Compliance/Monitoring/Mobile/Online/Pro/N13/RFlow/SupRemo], TAPI-Server, Communicator, MailScanner/MailScannerNET, diverse ExternalApp-Connectoren zu Drittsystemen wie c-pra, DocBee, Visoma, WOASI).
Aussage: Das System ist Teil eines breiten Produkt-/Anwendungsportfolios (nicht nur ein einzelnes ERP), das über ein gemeinsames Lizenz- und Authentifizierungssystem am zentralen Web-Service andockt.
Ergebnis: Wichtige Erkenntnis für den StRS-Systemüberblick: Die Web-/SaaS-Neuimplementierung des ERP-Kerns muss die Schnittstellen zu diesem breiteren Produktportfolio (mind. Authentifizierung/Lizenzierung) weiterhin bedienen können, auch wenn die Einzelprodukte selbst außerhalb des Scopes liegen.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs:11-53 - vollständige Liste der ApplicationKind-Instanzen
Prüfidee: Mit Produktmanagement klären, welche dieser Anwendungen im Rahmen der SaaS-Neuimplementierung migriert/integriert werden müssen vs. weiterhin als separate Legacy-Clients bestehen bleiben.
Konsolidierungshinweis: Kontext für ARCH-05 (Lizenzmodell); ggf. im finalen StRS als "System-Kontext-Diagramm" darstellen.
Status: belegt
---
### Kandidat ARCH-30
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Wartbarkeit) / Sonstiges
Akteur: Entwickler
Vorbedingung: -
Fakt: Zentrale technische Basis-Dokumentation (`stanislaus-secret-api-documentation.md`) verweist für die "eigentliche" Web-Service-API-Dokumentation nur auf eine externe PDF-Datei auf einem internen Netzlaufwerk (`P:\Entwicklung C#\...`), nicht auf ein im Repository verfügbares oder generiertes Dokument.
Aussage: (Kein direktes Systemsoll ableitbar) — Dokumentationslücke: Eine vollständige, versionierte API-Referenz der c-entron Web-Service-Schnittstelle ist im Repository nicht auffindbar.
Ergebnis: Für ein RRE-Projekt mit Ziel Web-/SaaS-Neuimplementierung fehlt eine zentrale, im Code-Repository gepflegte API-Spezifikation; dies ist selbst ein Befund (Prozess-/Dokumentationslücke), kein Produktmerkmal.
Belege:
- [PRIMÄR] docs/reference/architecture/stanislaus-secret-api-documentation.md:1-10 - Verweis auf externe PDF ohne Repository-Zugriff
Prüfidee: Klären, ob die referenzierte PDF beschafft werden kann, um die Web-Service-API (`ICentronRestService`) vollständiger zu dokumentieren, ggf. stattdessen `ICentronRestService`-Interface direkt im Code als Quelle nutzen (in anderen Clustern ggf. bereits geschehen).
Konsolidierungshinweis: Meta-Befund, keine Systemanforderung im engeren Sinn — ggf. bei der Konsolidierung als "Wissenslücke" statt als ARCH-Kandidat führen.
Status: HYPOTHESE (fehlende Information: externe PDF nicht zugreifbar/nicht gelesen)
---
## Abdeckung
**Gelesen (tief, mit Zeilenreferenzen):**
- README.md (Projektwurzel)
- CentronRights.md (Auszug, erste ~80 Zeilen)
- docs/reference/architecture/dtos-and-entities.md, requests-and-responses.md (leer), results-and-responses.md, tapi.md, mvvm-in-centron.md (Platzhalter), stanislaus-secret-api-documentation.md
- docs/reference/security/licensing-system.md, developer-security.md, anmelden-mit-microsoft-technische-anleitung.md
- docs/guides/ui/create-module.md, create-dialog.md (Platzhalter), create-settings-page.md, localization.md
- src/centron/Centron.WPF.UI/App.xaml.cs (vollständig)
- src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs (Header/Imports, Konstruktor-Ende, ModuleRegistrationItem-Klasse; die ca. 800 Zeilen der eigentlichen Modul-Registrierungsliste wurden nicht Zeile für Zeile gelesen, nur strukturell über Imports und grep-Zählung [84 Einträge] erfasst)
- src/centron/Centron.WPF.UI.Extension/Modules/ICentronAppModuleController.cs
- src/backend/Centron.Interfaces/Administration/Connections/CentronConnectionType.cs
- src/backend/Centron.Interfaces/UI/Modules/CentronModuleCategory.cs
- src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs (erste ~220 Zeilen)
- src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs (erste 60 Zeilen)
- src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs (vollständig)
- src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs (erste ~360 Zeilen, DoLogin/PreDoLoginToCentron)
- src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/MandatorManagementAppModuleController.cs
- src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs (erste 100 Zeilen), CentronDialogManager.cs (Ausschnitt), CentronAnalyticsManager.cs (erste 50 Zeilen)
- src/centron/Centron.WPF.UI/Extension/ExtensionLogic.cs (erste 80 Zeilen)
- src/centron/Centron.WPF.UI/StartupArgs/StartupArgManager.cs (Ausschnitt), StartupArgSynchronizer.cs (Ausschnitt)
- src/backend/Centron.BL/TwoFactorAuthenticator/TwoFactorAuthenticationBL.cs (erste 60 Zeilen)
- src/backend/Centron.Common/UtilClasses/CultureUtils.cs (Ausschnitt)
- src/centron/Centron.WPF.UI/Centron.WPF.UI.csproj (erste 40 Zeilen)
- global.json
**Nur strukturell erfasst (Dateilisten via Glob, nicht Inhalt gelesen):**
- src/centron/Centron.WPF.UI/Start/CommandPalette/** (Dateistruktur/Namen als Beleg für ARCH-19, Inhalte nicht gelesen)
- src/centron/Centron.WPF.UI/Wizards/** (nicht inhaltlich ausgewertet — kein eigener Kandidat, da zu generisch/kein aussagekräftiger Fakt gefunden)
- src/centron/Centron.WPF.UI/Layout/** (Dateinamen als Beleg für ARCH-20)
- src/centron/Centron.WPF.UI/Managers/** (PhoneManager.cs, SoftPhoneConnectionManager.cs, TapiPhoneConnectionManager.cs, CentronHelpManager.cs, CentronMailManager.cs, CentronNotificationManager.cs, CentronReportManager.cs, CentronStatusBarManager.cs, CentronThemeManager.cs, IconManager.cs — nur Namen erfasst, nicht gelesen)
- src/shared/Centron.Core/** (Dateiliste vollständig erfasst als Beleg für Basis-Utility-Landschaft; nur Guard.cs, Mvvm/CentronBindableBase.cs referenziert, nicht inhaltlich gelesen)
- src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/BranchManagement/** (nur Dateiliste)
**Bekannte Lücken / nicht recherchiert:**
- `docs/reference/architecture/requests-and-responses.md` ist im Repository **leer** (0 Byte) — kein Beleg ableitbar, obwohl im Auftrag als Startpunkt genannt.
- `docs/guides/ui/create-dialog.md` und `docs/reference/architecture/mvvm-in-centron.md` sind reine Platzhalter ("I don't know, but I would like to - please tell me.") — MVVM- und Dialog-Erstellungsmuster wurden daher nur indirekt über `create-module.md`/`create-settings-page.md` rekonstruiert (siehe ARCH-24, als HYPOTHESE markiert).
- `CentronThemeManager.cs` (Theming/Dark-Mode) wurde nicht gelesen — mögliches weiteres Usability-Merkmal (Theme aus Registry laden, `DuplicateThemeAndReload`) nur indirekt über App.xaml.cs-Aufrufe bekannt, kein eigener Kandidat formuliert.
- `CentronStartupArgManager.cs` (Manager-Wrapper um StartupArgManager) nicht gelesen, nur der darunterliegende `StartupArgManager`/`StartupArgSynchronizer`.
- Vollständige Liste aller 84 Modul-Registrierungen (Rechte-/Feature-Flag-Ausdrücke) wurde nicht einzeln geprüft — nur Muster und Beispiele (ModuleRegistrationItem-Klasse, Doku-Beispiel) belegt.
- `Centron.Api.docuFORM`, `azure/`, `azure-blazor/`, `docker/`, `deployment/` (Repository-Wurzelverzeichnisse) wurden nicht untersucht — potenziell relevant für Deployment-/Betriebsarchitektur (Docker/Azure), aber außerhalb der im Auftrag genannten Startpunkte und aus Zeitgründen nicht vertieft. Mögliche Lücke für SyRS "Deployment-Architektur".
- c-entron Nexus (separate Web-/Blazor-Anwendung, im README erwähnt) wurde nur über die kurze README-Erwähnung erfasst, nicht über eigenen Quellcode — echte Web-Architektur-Erkenntnisse für das SaaS-Zielbild könnten dort zusätzlich vorhanden sein (potenziell wertvoller Zusatz-Cluster für spätere Iterationen).
- Rechte-System (`UserRightsConst`, `ModuleRightsExpressionParser`) wurde nur strukturell (Existenz, Parser-Konzept) belegt, nicht im Detail (z.B. Rechte-Vererbung, Rollenkonzept) — Grenze zu den Fachclustern bewusst nicht überschritten.
- Kein Zugriff/Prüfung auf tatsächliche Systemvoraussetzungsdokumente für Kunden (Hardware/Betriebssystemversionen/Terminalserver-Freigabe) außerhalb des Codes — ARCH-11/ARCH-27 beruhen ausschließlich auf Code-/Projektdatei-Indizien.
@@ -0,0 +1,542 @@
# Rohbefunde Cluster BILL – Abrechnung, Fakturierung & Verträge
Recherche-Agent für RRE an CentronERP. Fokus: Belege (Rechnung/Gutschrift/Vertrag), Preisfindung, Contract-Billing, ZUGFeRD/XRechnung, Mahnwesen, Statusmaschinen.
---
### Kandidat BILL-01
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung / Finanzbuchhaltung
Vorbedingung: Rechnung/Gutschrift ist im System erfasst und soll elektronisch versendet werden
Fakt: c-entron generiert beim Rechnungs-/Gutschriftexport automatisiert ZUGFeRD- bzw. XRechnung-konforme XML-Dateien (Versionen 1.0 bis 2.1/XRechnung 3.0.1), implementiert in `InvoiceZugferdBL.cs`. Die Formatwahl (ZUGFeRD Comfort vs. XRechnung) erfolgt automatisch anhand des Vorhandenseins einer Leitweg-ID.
Aussage: Das System soll rechtssichere elektronische Rechnungen (ZUGFeRD/XRechnung) automatisiert aus den erfassten Rechnungs- und Gutschriftdaten erzeugen können, ohne manuelle Nacharbeit der Anwenderin.
Ergebnis: Verkäufer kann gesetzeskonforme E-Rechnungen (auch für öffentliche Auftraggeber) versenden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156 (GenerateZugferdFile, Formatwahl anhand leitwegID) - Begründung: Kernmechanik der automatisierten E-Rechnungserzeugung im Code nachgewiesen
- [SEKUNDÄR] docs/reference/zugferd-feldzuordnung-anwender.md:9-14 - Begründung: Anwenderdokumentation bestätigt unterstützte Versionen
Prüfidee: Export einer Rechnung ohne und mit Leitweg-ID durchführen, resultierendes Dateiformat/-schema prüfen (KOSIT-Validator)
Konsolidierungshinweis: Details siehe BILL-10 bis BILL-16 (SyRS/SwRS-Ebene)
Status: belegt
---
### Kandidat BILL-02
Ebene: StRS
Typ: funktional
Akteur: Vertriebsinnendienst / Vertragsmanagement
Vorbedingung: Kunde hat einen laufenden Wartungs-/Servicevertrag mit wiederkehrender Abrechnung
Fakt: c-entron bietet ein eigenständiges Contract-Billing-Subsystem (`ReceiptContract`, `AutomaticFacturaBL.Contracts`), das Verträge nach konfigurierbaren Intervallen (Daily/Monthly/Quarterly/Yearly) automatisiert abrechnet, inkl. Integration externer RMM-Nutzungsdaten (Riverbird) und Kontingentverwaltung.
Aussage: Das System soll wiederkehrende Vertragsleistungen automatisiert, nach konfigurierbarem Abrechnungsintervall und unter Berücksichtigung von Nutzungsdaten/Kontingenten korrekt fakturieren.
Ergebnis: Reduzierter manueller Aufwand bei der Abrechnung von Wartungs-/MSP-Verträgen, korrekte periodengerechte Rechnungsstellung.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs (Felder BillingIntervalKind, BillingIntervalDuration, AutomatedBilling) - Begründung: Entität trägt Konfigurationsfelder für automatisierte Intervallabrechnung
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:721-802 (CheckRMMArticle) - Begründung: Ausführbare Logik zur automatisierten RMM-basierten Rechnungspositionserzeugung
Prüfidee: Testvertrag mit monatlichem Intervall anlegen, automatische Abrechnung anstoßen, Rechnungsperiode/-betrag verifizieren
Konsolidierungshinweis: Details in BILL-17, BILL-18, BILL-19
Status: belegt
---
### Kandidat BILL-03
Ebene: StRS
Typ: funktional
Akteur: Finanzbuchhaltung / Mahnwesen
Vorbedingung: Kunde hat offene, überfällige Forderungen
Fakt: Das System führt ein Mahnstufen-Modell (`DunningLevel1Fees/2/3`, `DunningLetterAfterDays1-3`) je Kunde und kann konfigurierbar ab einer bestimmten Mahnstufe die Neuanlage von Belegen (z.B. Aufträgen) sperren (`LockOrderAfterDunningLevel`, durchgesetzt in `ReceiptBL.CanUserCreateNewReceiptsAtCustomerOrSupplier`).
Aussage: Das System soll säumige Kunden anhand eines Mahnstufenmodells identifizieren und optional automatisch von der Neuanlage weiterer Belege ausschließen, um das Ausfallrisiko zu begrenzen.
Ergebnis: Kreditrisikobegrenzung; Vertrieb kann keine neuen Aufträge/Belege für gesperrte Kunden anlegen, solange die Mahnstufe nicht sinkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 (CanUserCreateNewReceiptsAtCustomerOrSupplier, exakte Fehlermeldung "Aufgrund der Mahnstufe darf kein neuer Beleg ... angelegt werden.") - Begründung: Durchgesetzte Regel im Code, inkl. Fehlermeldungstext
- [PRIMÄR] src/backend/Centron.Entities/Entities/Accounts/AccountCustomer.cs:25 (LockOrderAfterDunningLevel) - Begründung: Persistiertes Feld je Kunde als Datengrundlage der Regel
Prüfidee: Kunde mit LockOrderAfterDunningLevel=2 und aktueller Mahnstufe 2 anlegen, Versuch neuen Auftrag zu erstellen -> erwartete Fehlermeldung
Konsolidierungshinweis: Details in BILL-20, BILL-21
Status: belegt
---
### Kandidat BILL-04
Ebene: StRS
Typ: nicht-funktional (Compliance/Datenintegrität)
Akteur: Buchhaltung / Wirtschaftsprüfung
Vorbedingung: Eine Rechnung wurde bereits weiterverarbeitet (z.B. exportiert, in Buchhaltung übernommen) oder ist eine Barrechnung
Fakt: `ReceiptInvoiceBL.CancelInvoice` verweigert die Stornierung, wenn die Rechnung bereits storniert ist, es sich um eine Barrechnung handelt, sie bereits weiterverarbeitet oder bereits an die Buchhaltung exportiert wurde, oder es sich bei einer Vertragsrechnung nicht um die zuletzt erstellte handelt.
Aussage: Das System soll die Stornierung von Rechnungen nur zulassen, solange keine downstream-Verarbeitung (Export, Weiterverarbeitung) stattgefunden hat, um Inkonsistenzen mit Buchhaltung/Finanzamt zu vermeiden.
Ergebnis: Verhinderung nachträglicher Inkonsistenzen zwischen ERP und exportierten/gebuchten Finanzdaten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:143-206 (CancelInvoice, komplette Prüfkette) - Begründung: Vollständige, im Code durchgesetzte Vorbedingungskette mit exakten Fehlermeldungen
Prüfidee: Testrechnung exportieren (BookKeepingExportBL) und danach Stornoversuch -> Fehlermeldung "...bereits exportiert wurde." erwarten
Konsolidierungshinweis: Detaillierung in BILL-06
Status: belegt
---
### Kandidat BILL-05
Ebene: SyRS
Typ: funktional
Akteur: System (Belegverwaltung)
Vorbedingung: Beleg (Angebot/Auftrag/Lieferschein/Rechnung/Vertrag/Gutschrift/Abholliste) existiert
Fakt: Alle Belegtypen teilen sich eine gemeinsame Statusmaschine `ReceiptState` mit exakt drei Zuständen: `Active` ("offen"), `Completed` ("abgeschlossen"), `Canceled` ("storniert"). Der Enum wird u.a. für Zahlungsstatus (Completed=bezahlt) und Stornostatus verwendet.
Aussage: Das System soll für alle Belegtypen einen einheitlichen, dreiwertigen Lebenszyklus-Status (offen/abgeschlossen/storniert) führen und konsistent für Status- und Zahlungslogik verwenden.
Ergebnis: Einheitliche, belegtypübergreifende Zustandslogik als Basis für Folgeprozesse (Storno, Zahlungsstatus, Reporting).
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 - Begründung: Enum-Definition mit deutschen Beschreibungen, direkter Code-Beleg
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:4942-4951 (UpdateReceiptIsPaid nutzt ReceiptState.Completed/Active für isPaid) - Begründung: Zeigt Wiederverwendung der Statusmaschine für Zahlungsstatus
Prüfidee: Alle Belegtypen (Angebot, Auftrag, Rechnung, Vertrag, Gutschrift) auf konsistente State-Werte in DB prüfen
Konsolidierungshinweis: Basis für BILL-06, BILL-08
Status: belegt
---
### Kandidat BILL-06
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Rechnung mit State != Canceled liegt vor
Fakt: `CancelInvoice` (ReceiptInvoiceBL.cs:143-206) prüft nacheinander: Recht `RIGHT_RECHNUNGSTORNIEREN`, State != Canceled, `IsCashAsset == false`, keine Weiterverarbeitung (`GetReceiptForwardedInto`), kein Buchhaltungsexport (`BookKeepingExportBL.IsReceiptExported`), bei Vertragsrechnung Prüfung auf letzte Rechnung des Vertrags (`IsLastContractInvoice`). Erst danach wird eine neue Version mit Menge=0 je Artikel-/Rabattposition erzeugt und State auf `Canceled` gesetzt.
Aussage: Das System soll eine Rechnungsstornierung als neue, versionierte Belegrevision mit auf Null gesetzten Mengen realisieren und dabei alle genannten Vorbedingungen hart erzwingen.
Ergebnis: Nachvollziehbare, versionierte Stornohistorie statt Löschung; harte Sperren bei bereits verarbeiteten Belegen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:157-186 - Begründung: Exakte Prüfkette und Storno-Mechanik (Menge=0, neue Version, State=Canceled) im Code
Prüfidee: Stornierung einer Barrechnung (IsCashAsset=true) versuchen -> Fehlermeldung "...da es sich um eine Barrechnung handelt." erwarten
Konsolidierungshinweis: Verfeinerung von BILL-04
Status: belegt
---
### Kandidat BILL-07
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Rechnung ist noch nicht festgeschrieben (IsFixed=false)
Fakt: `FixInvoice` setzt per Raw-SQL `UPDATE RechKopf SET IsFixed = 1 WHERE I3D = @I3D` und protokolliert den Vorgang im Log (`ReceiptLogKind.FixedState`). `CheckIfInvoiceIsFixed` liefert bei bereits festgeschriebener Rechnung eine Warnung "Die Rechnung ist festgeschrieben. Änderungen nicht möglich."
Aussage: Das System soll eine Funktion zur Festschreibung von Rechnungen bereitstellen, die weitere inhaltliche Änderungen an der Rechnung nach Festschreibung verhindert.
Ergebnis: Nachträgliche Manipulation festgeschriebener (i.d.R. bereits gebuchter/exportierter) Rechnungen wird verhindert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:86-141 (FixInvoice) - Begründung: Direkte SQL-Persistenz des Fixier-Flags plus Audit-Log-Eintrag
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:273-291 (CheckIfInvoiceIsFixed) - Begründung: Exakte Warnmeldung im Code
Prüfidee: Rechnung festschreiben, danach Änderungsversuch an Positionen -> erwartete Blockade/Warnung
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-08
Ebene: SyRS
Typ: funktional
Akteur: Zahlungseingang / Buchhaltung
Vorbedingung: Beleg unterstützt Zahlungsinformationen (`IReceiptWithPayment` oder Gutschrift)
Fakt: `ReceiptBL.UpdateReceiptIsPaid` (Zeilen 4902-4971) verweigert die Statusänderung bei stornierten Belegen ("...wurde stoniert und kann daher nicht als bezahlt oder nicht bezahlt eingestellt werden."), prüft optimistisches Locking via `ConcurrencyControlGuid` und mappt `isPaid=true/false` auf `ReceiptState.Completed/Active`.
Aussage: Das System soll den Zahlungsstatus eines Belegs nur bei nicht-stornierten Belegen und unter Berücksichtigung von Optimistic-Concurrency-Control ändern lassen.
Ergebnis: Konsistenter Zahlungsstatus, keine widersprüchlichen Parallel-Änderungen, keine Zahlungsbuchung auf stornierten Belegen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:4936-4951 - Begründung: Durchgesetzte Prüfungen inkl. exakter Fehlermeldung im Code
Prüfidee: Stornierte Rechnung als "bezahlt" markieren -> erwartete Fehlermeldung
Konsolidierungshinweis: siehe BILL-05
Status: belegt
---
### Kandidat BILL-09
Ebene: SyRS
Typ: funktional
Akteur: System (Belegnummernkreis)
Vorbedingung: Neuer Beleg wird angelegt und benötigt eine Belegnummer
Fakt: `NumberGroupBL.GetNextNumber`/`FindNextNumber` (Zeilen 50-134) ermittelt die nächste freie Nummer durch iterative Prüfung gegen die Zieltabelle (SELECT COUNT), inkrementiert um `Interval`, und persistiert die neue "Current"-Nummer nur, wenn ein optimistischer Update (`WHERE I3D = @I3D AND Current = @altCurrent`) genau 1 Zeile ändert; andernfalls wird die Schleife wiederholt (Race-Condition-Schutz bei paralleler Nummernvergabe).
Aussage: Das System soll Belegnummern eindeutig, kollisionsfrei und race-condition-sicher unter gleichzeitigem Zugriff mehrerer Benutzer vergeben.
Ergebnis: Keine doppelten Belegnummern auch bei paralleler Rechnungserstellung durch mehrere Benutzer/Filialen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs:62-134 - Begründung: Konkrete Optimistic-Locking-Implementierung mit Retry-Schleife im Code
Prüfidee: Lasttest mit parallelen Rechnungsanlagen; auf doppelte Nummern in RechKopf prüfen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-10
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Rechnungs-/Gutschriftexport wird angestoßen, optional mit Leitweg-ID
Fakt: `InvoiceZugferdBL.GenerateZugferdFile` (Zeilen 124-156) wählt `ZugferdFileKind.Comfort`, wenn `leitwegID` leer/whitespace ist, sonst `ZugferdFileKind.XInvoice`. Ebenso bestimmt `CreateZugferdConformPdfDocument` (Zeile 193) das PDF-Konformitätslevel (`EN16931` vs. `XRechnung`) anhand desselben Kriteriums.
Aussage: Das System soll automatisch zwischen ZUGFeRD-Comfort- und XRechnung-Format wechseln, gesteuert einzig durch das Vorhandensein einer Leitweg-ID im Beleg.
Ergebnis: Für Rechnungen an öffentliche Auftraggeber wird automatisch das gesetzlich vorgeschriebene XRechnung-Format erzeugt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156,167-193 - Begründung: Direkte Verzweigungslogik im Code
Prüfidee: Export mit und ohne Leitweg-ID vergleichen (Dateikennung/Namespace im XML)
Konsolidierungshinweis: Verfeinerung von BILL-01
Status: belegt
---
### Kandidat BILL-11
Ebene: SyRS
Typ: funktional
Akteur: System (Steuerlogik E-Rechnung)
Vorbedingung: Rechnungsposition mit Steuersatz, Reverse-Charge-Flag und Handelsart (Inland/EU/Export) liegt vor
Fakt: `InvoiceZugferdBL.GetTaxCategoryCode` (Zeilen 2092-2107) liefert deterministisch: "AE" bei Reverse Charge, sonst bei Steuersatz 0%: "E" (Inland), "K" (EU), "G" (Export außerhalb EU); sonst "S" (Standard).
Aussage: Das System soll die UN/CEFACT-Steuerkategorie jeder Rechnungsposition automatisiert aus Steuersatz, Reverse-Charge-Kennzeichen und Handelsart ableiten.
Ergebnis: Korrekte, normkonforme Steuerkategorien im E-Rechnungs-XML ohne manuelle Zuordnung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2092-2107 - Begründung: Vollständige, deterministische Entscheidungslogik im Code nachgewiesen
Prüfidee: Testfälle für alle vier Kombinationen (Reverse Charge, Inland 0%, EU 0%, Export 0%, Standard) durchspielen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-12
Ebene: SyRS
Typ: funktional
Akteur: System (Steuerlogik E-Rechnung)
Vorbedingung: Steuerkategorie einer Position wurde ermittelt (siehe BILL-11)
Fakt: `GetTaxExemptionReason` (InvoiceZugferdBL.cs:2109-2122) liefert feste deutsche Begründungstexte: Reverse Charge -> "Steuerschuldnerschaft des Leistungsempfängers gem. §13B Abs 2 Nr. 10 UStG.", Inland 0% -> "Steuerfrei", EU 0% -> "Kein Ausweis der Umsatzsteuer bei innergemeinschaftlichen Lieferungen", Export 0% -> "Steuer nicht erhoben aufgrund von Export außerhalb der EU".
Aussage: Das System soll bei steuerbefreiten oder Reverse-Charge-Positionen automatisch den vorgeschriebenen Befreiungstext im E-Rechnungs-XML hinterlegen.
Ergebnis: E-Rechnungen erfüllen die formalen Anforderungen an Steuerbefreiungshinweise (§14 UStG / EN16931).
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2109-2122 - Begründung: Exakte Texte im Code
Prüfidee: Reverse-Charge-Rechnung exportieren, XML auf ExemptionReason-Text prüfen
Konsolidierungshinweis: Ergänzt BILL-11
Status: belegt
---
### Kandidat BILL-13
Ebene: SyRS
Typ: nicht-funktional (Datenqualität)
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Summe der Positionsnettobeträge weicht vom Rechnungskopf-Nettobetrag ab
Fakt: Konstante `AMOUNT_DIFFERENCE_TOLERANCE = 3.0m` (InvoiceZugferdBL.cs:64); bei Abweichung < Toleranz wird eine Warnung geloggt und der Kopfbetrag automatisch korrigiert ("ZUGFeRD: Bei der Rechnung weicht das Netto der Rechnung ... ab. Bitte prüfen Sie die Rechnung."), bei Abweichung >= Toleranz wird der Export mit `Result.AsError` abgebrochen (Zeilen 1033-1043).
Aussage: Das System soll beim E-Rechnungsexport die Konsistenz zwischen Kopf- und Positionssummen prüfen und bei Abweichungen über 3,00 Euro den Export verweigern statt eine fehlerhafte Rechnung zu versenden.
Ergebnis: Verhindert Versand rechnerisch inkonsistenter E-Rechnungen; kleinere Rundungsdifferenzen werden toleriert und automatisch korrigiert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:64,1033-1043 - Begründung: Hartkodierte Toleranzgrenze und Fehlerpfad im Code
Prüfidee: Rechnung mit manuell verändertem Kopfbetrag (Abweichung > 3€) exportieren -> Export muss fehlschlagen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-14
Ebene: SyRS
Typ: funktional
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Rechnungs-/Gutschriftposition mit negativem Nettopreis liegt vor
Fakt: ZUGFeRD/XRechnung unterstützt keine negativen Einzelpreise; c-entron macht laut Code-Kommentaren und Dokumentation den Preis positiv und negiert stattdessen die Menge, sodass die Positionssumme unverändert bleibt (`InvoiceZugferdBL.cs`, Kommentare Zeilen 994-999 zu Vorzeichenbehandlung bei Rabatten; Bestätigung in docs/reference/zugferd-field-mapping.md Abschnitt "Negative Prices").
Aussage: Das System soll negative Einzelpreise beim E-Rechnungsexport durch Vorzeichenumkehr der Menge (statt des Preises) abbilden, um EN16931-Konformität zu wahren.
Ergebnis: Rabatt-/Korrekturpositionen mit negativem Preis werden normkonform exportiert.
Belege:
- [SEKUNDÄR] docs/reference/zugferd-field-mapping.md:272-275,355-359 - Begründung: Ausführliche Beschreibung der Regel, jedoch nur indirekt über Code-Kommentare (Zeilen 994-999) im Quellcode rückbestätigt
- [KONTEXT] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:994-999 - Begründung: Verwandte Vorzeichenlogik für Rabatte im selben Modul bestätigt das Muster
Prüfidee: Gutschriftposition mit negativem Preis exportieren, XML auf positiven ChargeAmount und negierte BilledQuantity prüfen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-15
Ebene: SyRS
Typ: funktional
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Rechnung enthält Titelpositionen mit untergeordneten Positionen unterschiedlicher Steuersätze
Fakt: Beim Aggregieren von Titelpositionen wird bei unterschiedlichen Steuersätzen der untergeordneten Positionen der Export mit Fehlermeldung abgebrochen: "In der Titelposition '{Text}' kommen unterschiedliche Mehrwertsteuern vor (...), dass wird nicht unterstützt! Bitte klappen Sie die Titelposition auf, oder splitten Sie die Positionen..." (InvoiceZugferdBL.cs:950-952). Ausgeklappte Titelpositionen werden generell nicht unterstützt (nur eingeklappte/kollabierte Titelpositionen mit Menge=1 werden exportiert).
Aussage: Das System soll beim E-Rechnungsexport gemischte Steuersätze innerhalb einer eingeklappten Titelposition erkennen und den Export mit einer handlungsleitenden Fehlermeldung verweigern.
Ergebnis: Verhindert steuerlich inkorrekte E-Rechnungen bei Titelpositionen; Anwenderin erhält konkrete Lösungshinweise.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:938-953 - Begründung: Exakte Fehlermeldung und Abbruchlogik im Code
Prüfidee: Titelposition mit Kindpositionen zu 19% und 7% MwSt. exportieren -> erwarteter Abbruch mit obiger Meldung
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-16
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Gutschrift wurde aus einer oder mehreren Rechnungen erzeugt
Fakt: Beim E-Rechnungs-Export einer Gutschrift wird nur dann ein Verweis auf die Ursprungsrechnung (`InvoiceReferencedDocument`) gesetzt, wenn genau eine eindeutige Ursprungsrechnung ermittelt werden kann (`items.Count == 1`, ermittelt über `OriginKind == Invoice` und `DistinctBy(OriginReceiptI3D)`); bei mehreren oder keiner Ursprungsrechnung bleibt das Feld leer.
Aussage: Das System soll bei Gutschriften automatisch auf die zugehörige Ursprungsrechnung im E-Rechnungs-XML verweisen, sofern die Zuordnung eindeutig ist.
Ergebnis: Nachvollziehbarkeit von Gutschriften gegenüber Rechnungen für Kunden/Finanzamt, ohne fehlerhafte Mehrfachreferenzen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:803-811,1873-1878 - Begründung: Eindeutigkeitsprüfung und bedingte Referenzsetzung im Code
Prüfidee: Sammelgutschrift zu zwei Rechnungen exportieren -> InvoiceReferencedDocument darf nicht gesetzt sein
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-17
Ebene: SyRS
Typ: funktional
Akteur: System (Contract-Billing / RMM-Integration)
Vorbedingung: Vertrag ist für RMM-Abrechnung konfiguriert (`WhetherRMM=true`) und automatische Rechnungserstellung wird ausgeführt
Fakt: `CheckRMMArticle` (AutomaticFacturaWebServiceBL.cs:721-802) ruft für den Abrechnungszeitraum Nutzungsdaten des externen RMM-Systems (Riverbird, via `RiverConnectionBL.GetContractBillingAmounts`) ab. Ist der RMM-Service nicht erreichbar UND werden RMM-Artikel im Vertrag erwartet, wird eine `RMMServiceUnavailableException` mit Fehlermeldung "Die Rechnung kann nicht erstellt werden. {Message}" geworfen und die gesamte Rechnungserstellung abgebrochen.
Aussage: Das System soll bei RMM-basierter Vertragsabrechnung die automatische Rechnungserstellung abbrechen, wenn die externe Nutzungsdatenquelle nicht erreichbar ist, um Rechnungen mit unvollständigen Nutzungsdaten zu verhindern.
Ergebnis: Kunden werden nicht auf Basis unvollständiger/fehlerhafter Nutzungsdaten fakturiert; Fehlerprotokollierung ermöglicht Nachverfolgung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:790-802,2412-2415 (Exception-Definition und Wurf-Stelle) - Begründung: Vollständige Fehlerbehandlungslogik direkt im Code
- [SEKUNDÄR] docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md:45-52 - Begründung: Bestätigt fachlichen Zweck der Regel
Prüfidee: RMM-Service (Riverbird) für Testzeitraum offline simulieren, automatische Vertragsabrechnung anstoßen -> Abbruch mit Exception erwarten
Konsolidierungshinweis: Detailliert BILL-02
Status: belegt
---
### Kandidat BILL-18
Ebene: SyRS
Typ: funktional
Akteur: System (Contract-Billing)
Vorbedingung: RMM-Nutzungsmenge für einen Vertragsartikel wurde ermittelt, Vertragsartikel hat konfigurierte Kontingentmenge (`ContractAmount`)
Fakt: `ContractArticleReferenzes.CalculateContractBillingAmount(decimal riverbirdAmount)` (Entities/.../ContractArticleReferenzes.cs:27-39): Sind sowohl `ConsiderOverbooking` als auch `ConsiderUnderbooking` gesetzt, wird immer die feste `ContractAmount` abgerechnet; ist nur `ConsiderOverbooking` gesetzt und die Ist-Menge übersteigt die Kontingentmenge, wird auf `ContractAmount` gedeckelt; ist nur `ConsiderUnderbooking` gesetzt und die Ist-Menge liegt darunter, wird ebenfalls auf `ContractAmount` gedeckelt; ansonsten wird die tatsächliche RMM-Menge abgerechnet.
Aussage: Das System soll die abzurechnende Menge eines RMM-Vertragsartikels regelbasiert aus Ist-Nutzung und konfigurierbarer Über-/Unterbuchungsdeckelung ableiten.
Ergebnis: Kontrollierte Abrechnung bei schwankender Nutzung (z.B. Lizenzverträge mit Mindest-/Höchstmenge).
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/CustomerAssets/Contracts/ContractArticleReferenzes.cs:27-39 - Begründung: Vollständige, deterministische Berechnungsmethode im Code
Prüfidee: Testfälle mit ConsiderOverbooking/Underbooking-Kombinationen und Ist-Mengen über/unter ContractAmount durchspielen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-19
Ebene: SyRS
Typ: funktional
Akteur: System (Vertrags-Kontingentverwaltung)
Vorbedingung: Rechnung oder Gutschrift mit Bezug zu einem Vertrag mit Kontingent (Geld- oder Mengenkontingent) wird gebucht
Fakt: `ReceiptContractBL.ContractContingentBalanceCalculation` (Zeilen 149-221) berechnet den Kontingentwert entweder als Nettobetrag (`ContingentKinds.Money`) oder als Menge (inkl. Zeitumrechnung via `CalculateContingentWithRecalculationArticle`); bei Gutschriften (`CentronObjectKindNumeric.CreditVoucherClass`) wird der Wert mit `-1` multipliziert (Zeilen 188-190, 194-196), d.h. Gutschriften reduzieren den Kontingentverbrauch. Das Ergebnis wird in der Zuordnungstabelle `VertragRechKopfZuordnung` persistiert.
Aussage: Das System soll bei jeder vertragsbezogenen Rechnung den Kontingentverbrauch erhöhen und bei jeder vertragsbezogenen Gutschrift den Kontingentverbrauch entsprechend wieder verringern.
Ergebnis: Korrekter, buchungsgenauer Kontingentsaldo je Vertrag über Rechnungs- und Gutschriftbuchungen hinweg.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs:149-221 - Begründung: Vollständige Berechnungs- und Vorzeichenlogik im Code
Prüfidee: Vertragsrechnung buchen, danach zugehörige Gutschrift buchen, Kontingentsaldo vor/nach vergleichen
Konsolidierungshinweis: Ergänzt BILL-02/BILL-17
Status: belegt
---
### Kandidat BILL-20
Ebene: SwRS
Typ: funktional
Akteur: System (Auftrags-/Belegsperre)
Vorbedingung: Benutzer versucht neuen Beleg (z.B. Auftrag) für einen Kunden/Lieferanten anzulegen
Fakt: `ReceiptBL.CanUserCreateNewReceiptsAtCustomerOrSupplier<TReceipt>` (Zeilen 10194-10219) ermittelt zunächst die aktuelle Mahnstufe des Kunden (`GetCustomerOrSupplierDunningLevel<TReceipt>`) und den je Belegtyp konfigurierten Sperr-Schwellwert (`BlockNewReceiptsDunningLevel`, für Aufträge implementiert in `OrderSpecificLogic.cs:687-693` über `customerDetail.OrderLockAfterDunning`). Ist die aktuelle Mahnstufe >= Schwellwert, wird die Anlage mit Fehlermeldung "Aufgrund der Mahnstufe darf kein neuer Beleg vom Typ \"{...}\" angelegt werden." verweigert.
Aussage: Das System soll je Belegtyp konfigurierbar prüfen, ob die aktuelle Mahnstufe eines Kunden die Neuanlage von Belegen sperrt, und die Anlage in diesem Fall mit einer sprechenden Fehlermeldung verweigern.
Ergebnis: Automatisierte Kreditkontrolle direkt in der Belegerfassung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 - Begründung: Vollständige Sperrlogik inkl. exakter Fehlermeldung
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:687-693 - Begründung: Konkrete belegtypspezifische Implementierung des Schwellwerts für Aufträge
Prüfidee: Kunde mit LockOrderAfterDunning=1 und aktueller Mahnstufe 1: Auftragsanlage -> Fehlermeldung erwarten; Mahnstufe 0 -> Anlage möglich
Konsolidierungshinweis: Verfeinerung von BILL-03
Status: belegt
---
### Kandidat BILL-21
Ebene: SyRS
Typ: Daten
Akteur: Finanzbuchhaltung (Administration)
Vorbedingung: Mahnlauf wird konfiguriert
Fakt: Anwendungseinstellungen `DunningLevel1Fees=10127`, `DunningLevel2Fees=10128`, `DunningLevel3Fees=10129` (ApplicationSettingID.cs:855-857) sowie je-Kunde-Felder `DunningLetterAfterDays1-3` und `LockOrderAfterDunningLevel` definieren gestaffelte Mahngebühren und Fristen für bis zu drei Mahnstufen.
Aussage: Das System soll bis zu drei konfigurierbare Mahnstufen mit jeweils eigener Gebühr, Frist (Tage nach Fälligkeit) und optionaler Beleg-Sperre unterstützen.
Ergebnis: Flexibles, mehrstufiges Mahnwesen je Mandant konfigurierbar.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs:855-857 - Begründung: Konkrete Einstellungs-IDs im Code
- [PRIMÄR] src/backend/Centron.DAO/Repositories/Accounts/AccountRepository.cs:660-663 (Mapping MahnungNachTagen/2/3, AuftragsperreNachMahnung) - Begründung: Bestätigt Persistenzfelder je Kunde
Prüfidee: Drei Mahnstufen mit unterschiedlichen Gebühren konfigurieren, Mahnlauf für überfälligen Kunden ausführen, erzeugte Mahngebühr prüfen
Konsolidierungshinweis: Ergänzt BILL-03/BILL-20
Status: belegt
---
### Kandidat BILL-22
Ebene: SwRS
Typ: funktional
Akteur: Zahlungseingang / Buchhaltung
Vorbedingung: Ein bereits erfasster Zahlungseingang zu einer Rechnung wird gelöscht
Fakt: `PaymentsBL.DeleteIncomingPayment` (Zeilen 38-78) prüft das Recht `INCOMING_PAYMENT_TRANSACTIONS`; sofern `filter.DontChangeInvoice == false`, wird je betroffener Rechnung die Summe der zu löschenden Zahlungsbeträge negiert (`* -1`) und über `ReceiptBL.UpdateReceiptIsPaid` mit Währungsfaktor (`* invoice.CurrencyFactor`) und Log-Grund "Zahlungseingang gelöscht" zurückgebucht.
Aussage: Das System soll beim Löschen eines Zahlungseingangs den zugehörigen offenen/bezahlten Betrag der Rechnung automatisch um den gelöschten Betrag korrigieren.
Ergebnis: Konsistenter Rechnungssaldo auch nach nachträglicher Korrektur von Zahlungseingängen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Finances/Payments/PaymentsBL.cs:38-78 - Begründung: Vollständige Rückbuchungslogik im Code
Prüfidee: Zahlungseingang zu Rechnung erfassen, Saldo prüfen, Zahlungseingang löschen, Saldo erneut prüfen
Konsolidierungshinweis: Ergänzt BILL-08
Status: belegt
---
### Kandidat BILL-23
Ebene: SwRS
Typ: funktional
Akteur: Einkauf / Preispflege
Vorbedingung: Aktionspreis (Distributor-Sonderpreis) für Artikel wurde erfasst
Fakt: `PriceMatrixViewModel.GetPriceItemsFromArticleActionPrices` filtert Aktionspreise ausschließlich nach Gültigkeitsfenster: `EffectiveFrom.StartOfDay() <= DateTime.Now && EffectiveUntil >= DateTime.Now` (laut docs/reference/receipts/actionprice-system.md:312, im UI-Modul `PriceMatrixViewModel.cs`). Nur aktuell gültige Aktionspreise werden in der Preismatrix angezeigt.
Aussage: Das System soll in der Preisfindung nur zeitlich gültige Aktionspreise (aktuelles Datum zwischen Gültig-von/-bis) berücksichtigen.
Ergebnis: Verkäufer sehen ausschließlich aktuell gültige Sonderkonditionen bei der Preisfindung.
Belege:
- [SEKUNDÄR] docs/reference/receipts/actionprice-system.md:196-212,306-312 - Begründung: Dokumentierte Filterlogik mit Code-Referenz auf PriceMatrixViewModel.cs, jedoch nicht selbst im Quellcode gegengelesen
Prüfidee: Aktionspreis mit EffectiveUntil in der Vergangenheit anlegen, Preismatrix öffnen -> Preis darf nicht erscheinen
Konsolidierungshinweis: -
Status: belegt; nicht im Quellcode direkt verifiziert (nur Dokumentation), daher SEKUNDÄR statt PRIMÄR
---
### Kandidat BILL-24
Ebene: SwRS
Typ: Sicherheit / Datenintegrität
Akteur: Einkauf / Preispflege
Vorbedingung: Neuer Aktionspreis wird über den Dialog "Aktionspreis hinzufügen" erfasst
Fakt: Die Pflichtfeldprüfung (Distributor darf nicht leer sein; `EffectiveFrom` darf nicht nach `EffectiveUntil` liegen) ist ausschließlich in der WPF-ViewModel-Schicht implementiert (`AddActionPriceViewModel.cs:69-79`, `Ok()`-Methode mit MessageBox-Abbruch). Die Business-Logic-Schicht `ActionPriceBL.SaveOrUpdateActionPrice` (Zeilen 36-41) führt dagegen nur einen `Guard.NotNull`-Nullcheck durch, keine fachliche Validierung; auch über die REST-API (`SaveOrUpdateActionPrice`) ist kein serverseitiger Constraint ersichtlich.
Aussage: Das System soll die Pflichtfeld- und Plausibilitätsprüfung für Aktionspreise (Distributor vorhanden, gültiger Zeitraum) serverseitig (BL/API/DB) durchsetzen, nicht nur im WPF-Client.
Ergebnis: Verhindert, dass über die REST-API oder zukünftige Web-Clients ungültige Aktionspreise (leerer Distributor, invertierter Zeitraum) persistiert werden können.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Warehousing/ArticleManagement/OpenDialog/ActionPrice/AddActionPriceViewModel.cs:69-79 - Begründung: Zeigt, dass die Validierung nur clientseitig erfolgt
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ActionPriceBL.cs:36-41 - Begründung: Zeigt Fehlen jeglicher fachlicher Validierung in der Business-Logic-Schicht
Prüfidee: Aktionspreis direkt über REST-Endpoint `SaveOrUpdateActionPrice` mit leerem Distributor bzw. EffectiveFrom > EffectiveUntil senden -> prüfen ob Speicherung dennoch gelingt
Konsolidierungshinweis: Wichtiger Befund für Web-/SaaS-Neuimplementierung: bestehende Lücke nicht unreflektiert übernehmen, sondern serverseitig nachrüsten
Status: belegt; Workaround (Validierung nur im Legacy-WPF-Client vorhanden, kein serverseitiger Constraint nachweisbar)
---
### Kandidat BILL-25
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (E-Rechnungs-Export, Zahlungsdaten)
Vorbedingung: Rechnung wird für ZUGFeRD/XRechnung exportiert und benötigt eine Bankverbindung
Fakt: Die Bankauswahl für den E-Rechnungs-Export erfolgt hierarchisch: zunächst über die Einstellung `ReceiptInvoiceSettings.UseMandatorBankForInvoice` (Bank1-4), die pro Kunde über `AccountCustomer.MandatorBank` überschrieben werden kann; die konkreten IBAN/BIC-Daten stammen aus den Mandantenstammdaten (`Mandator.Bank1Iban/Bic` ... `Bank4Iban/Bic`). Bei SEPA-Lastschrift wird stattdessen die Kunden-IBAN aus `BankAccount.Iban` sowie die SEPA-Mandatsreferenz aus `BankAccount.AuthorizationNumber` verwendet.
Aussage: Das System soll die für den E-Rechnungsexport verwendete Bankverbindung nach einer festen Priorität (kundenspezifische Einstellung vor globaler Mandanteneinstellung) auflösen und zwischen Überweisung und SEPA-Lastschrift unterscheiden.
Ergebnis: Korrekte Zahlungsinformationen je nach Zahlungsart und Kundeneinstellung im E-Rechnungs-XML.
Belege:
- [SEKUNDÄR] docs/reference/zugferd-field-mapping.md:157-160 - Begründung: Dokumentierte Bankauswahl-Hierarchie mit Verweis auf Datenquellen; Umsetzung im Code (InvoiceZugferdBL.cs Settlement-Bereich) nicht Zeile-für-Zeile nachgelesen
Prüfidee: Kunde mit abweichender MandatorBank-Einstellung anlegen, Rechnung exportieren, verwendete IBAN/BIC im XML mit Erwartungswert vergleichen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-26
Ebene: SyRS
Typ: Daten
Akteur: System (Belegarchitektur)
Vorbedingung: Ein Beleg (Angebot/Auftrag/Lieferschein/Rechnung/Vertrag/Gutschrift/Abholliste) wird gespeichert oder verändert
Fakt: Jede Belegänderung wird über `AssetHeadDAO.SaveAssetVersion` als vollständige 1:1-Kopie in eine Versionstabelle geschrieben (z.B. `VertragKopfVersions`, `RechKopfVersions`); Versionstabellen müssen laut Doku und Code-Konvention exakt dieselben Spalten wie die Basistabelle enthalten (zzgl. `OriginalI3D`/`KopfVersionsI3D`), sonst schlägt die Versionierung zur Laufzeit fehl (`DoGetFieldList()`).
Aussage: Das System soll für alle Belegtypen eine vollständige, spaltengenaue Versionshistorie (Audit-Trail) führen, die jede Änderung als eigenständige, abfragbare Version persistiert.
Ergebnis: Lückenlose Nachvollziehbarkeit aller Belegänderungen inkl. Rollback-Fähigkeit; Grundlage für Compliance-Anforderungen (GoBD).
Belege:
- [PRIMÄR] docs/reference/receipts/receipts-backend-architecture.md:147-204 - Begründung: Detaillierte Beschreibung der 1:1-Versionierungsmechanik inkl. SQL-Beispiel; als architekturelle Konvention durchgängig in den Datenbank-Skripten (Kopf-/Pos-Versions-Tabellen) sichtbar
- [KONTEXT] src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs (Nutzung versionierter Verträge über Contract-Version-Views) - Begründung: Bestätigt praktische Nutzung des Versionierungsmusters bei Verträgen
Prüfidee: Vertrag mehrfach ändern, VertragKopfVersions auf lückenlose OriginalI3D-Kette prüfen
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat BILL-27
Ebene: SwRS
Typ: Daten
Akteur: System (Audit-Log)
Vorbedingung: Vertrag wird angelegt, geändert, abgerechnet oder gekündigt
Fakt: Verträge protokollieren Ereignisse zentral über die Tabelle `AnlageLog` mit `AnlageArt = 22` (Contract-Identifier) und `AnlageI3D` als Verweis auf den Vertrag; dasselbe Muster (`AnlageI3D`+`AnlageArt`) wird für alle Belegtypen verwendet (z.B. 1=Angebot, 2=Auftrag, 4=Rechnung, 6=Gutschrift).
Aussage: Das System soll geschäftsrelevante Ereignisse an Verträgen (Erstellung, Änderung, Abrechnung, Kündigung) in einem zentralen, belegtypübergreifenden Audit-Log erfassen.
Ergebnis: Einheitliche, auswertbare Historie für Compliance- und Support-Zwecke über alle Belegtypen hinweg.
Belege:
- [SEKUNDÄR] docs/reference/receipts/contracts-backend.md:204-220 - Begründung: Dokumentiert Tabellenschema und Verwendung; korrespondierendes Enum/Konstantenwert (AnlageArt=22) nicht separat im Code verifiziert
Prüfidee: Vertragsänderung durchführen, AnlageLog-Eintrag mit AnlageArt=22 und korrektem AnlageI3D erwarten
Konsolidierungshinweis: Ergänzt BILL-26
Status: belegt
---
### Kandidat BILL-28
Ebene: SyRS
Typ: funktional
Akteur: System (Preisfindung Titelpositionen)
Vorbedingung: E-Rechnungsexport einer Rechnung mit Titelposition ohne untergeordnete Positionen
Fakt: Für Titelpositionen ohne Kindpositionen wird beim ZUGFeRD-Export standardmäßig ein Steuersatz von 19% angenommen (laut docs/reference/zugferd-feldzuordnung-anwender.md:331 "Standard-Steuersatz: Wenn eine Titelposition keine untergeordneten Positionen hat, wird 19% verwendet").
Aussage: Das System soll für leere Titelpositionen beim E-Rechnungsexport einen definierten Standard-Steuersatz (19%) ansetzen, statt den Export mit unbestimmtem Steuersatz zu blockieren.
Ergebnis: Robuster Export auch bei untypischen/leeren Titelpositionen, aber mit Risiko falscher Steuerangabe bei abweichendem tatsächlichem Steuersatz.
Belege:
- [SEKUNDÄR] docs/reference/zugferd-feldzuordnung-anwender.md:331 und docs/reference/zugferd-field-mapping.md:365 - Begründung: In zwei unabhängigen Dokumentationsartefakten übereinstimmend beschrieben, jedoch nicht im Quellcode zeilengenau verifiziert
Prüfidee: Leere Titelposition (keine Kindpositionen) in Rechnung anlegen und exportieren, resultierenden Steuersatz im XML prüfen
Konsolidierungshinweis: Ergänzt BILL-15
Status: belegt; [HYPOTHESE]-nah, da nur SEKUNDÄR belegt (Code-Stelle nicht gegengelesen) - Risikobereich Steuerberechnung, vor Übernahme in Web-Neuimplementierung im Code verifizieren
---
### Kandidat BILL-29
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung / Vertragsverwaltung
Vorbedingung: Vertragsrechnung soll storniert werden
Fakt: `ReceiptInvoiceBL.CancelInvoice` erlaubt die Stornierung einer Vertragsrechnung nur, wenn sie laut `IsLastContractInvoice` die aktuell für den Vertrag zuletzt erstellte Rechnung ist (Abgleich über `ReceiptContractBL.GetContractInfos(...).CurrentInvoiceI3D`); andernfalls Fehlermeldung: "Die Rechnung kann nicht storniert werden, da Sie nicht die letzte für den Vertrag erstellte Rechnung ist. Sie können nur jeweils die zuletzt für einen Vertrag erstellte Rechnung stornieren."
Aussage: Das System soll bei Vertragsrechnungen die Stornierung auf die jeweils zuletzt erstellte Rechnung je Vertrag beschränken, um die Konsistenz der Vertragsabrechnungshistorie (Kontingente, Zuordnungen) zu erhalten.
Ergebnis: Verhindert inkonsistente Kontingent-/Zuordnungshistorie bei Verträgen durch Storno "mittendrin liegender" Rechnungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:170-172,236-251 - Begründung: Exakte Prüf- und Fehlermeldungslogik im Code
Prüfidee: Vertrag mit zwei Abrechnungsperioden abrechnen, Storno der ersten (nicht letzten) Rechnung versuchen -> erwartete Fehlermeldung
Konsolidierungshinweis: Verfeinerung von BILL-06
Status: belegt
---
### Kandidat BILL-30
Ebene: SwRS
Typ: Schnittstelle
Akteur: System (Belegsuche)
Vorbedingung: Anwenderin sucht über mehrere Belegtypen hinweg (inkl. Rechnungen, Verträge, Gutschriften)
Fakt: `ReceiptSearcher.SearchReceipts` (ReceiptSearcher.cs) iteriert über alle registrierten `ReceiptSearchConfiguration`-Implementierungen je Belegtyp, generiert dynamisch parametrisierte Raw-SQL-Statements (Timeout 5 Minuten) und prüft je Belegtyp konfigurierbare Rechte (`ShowRight`, `OnlyOwnRight`, `OnlyOwnBranchRight`); fehlende Rechte führen dazu, dass für diesen Belegtyp `null` zurückgegeben und er stillschweigend aus dem Suchergebnis ausgeschlossen wird.
Aussage: Das System soll bei der belegtypübergreifenden Suche serverseitig je Belegtyp und Benutzer prüfen, ob Zugriffsrechte bestehen, und Ergebnisse ohne Berechtigung nicht anzeigen.
Ergebnis: Konsistente Rechtedurchsetzung auch in der übergreifenden Belegsuche (z.B. Rechnungen, Verträge), keine Informationslecks über Belegtypgrenzen.
Belege:
- [PRIMÄR] docs/reference/receipts/receipt-search-architecture.md:154-190 (mit Code-Zitat aus ReceiptSearcher.CreateSqlStatementAndParameters) - Begründung: Dokumentation zitiert die tatsächliche Rechteprüfungslogik im Code direkt
Prüfidee: Benutzer ohne Vertragsrecht sucht belegtypübergreifend -> Verträge dürfen nicht im Ergebnis erscheinen
Konsolidierungshinweis: Rahmenbedingung für alle BILL-Kandidaten mit Belegzugriff
Status: belegt
---
## Abdeckung
**Vollständig gelesen (Docs):**
- docs/reference/receipts/actionprice-system.md
- docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md
- docs/reference/receipts/contracts-backend.md
- docs/reference/receipts/receipt-search-architecture.md
- docs/reference/receipts/receipts-backend-architecture.md
- docs/reference/zugferd-feldzuordnung-anwender.md
- docs/reference/zugferd-field-mapping.md
- docs/guides/development/xrechnung.md (nur Linksammlung, kein fachlicher Inhalt)
**Code-Dateien gezielt gelesen/gegengeprüft (mit Zeilenangaben in den Belegen):**
- src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs (vollständig)
- src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs (Zeilen 1-320, insb. CancelInvoice, FixInvoice, CheckIfInvoiceIsFixed)
- src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs (Ausschnitte: UpdateReceiptIsPaid Zeilen 4900-5000, CanUserCreateNewReceiptsAtCustomerOrSupplier Zeilen 10194-10230, GetNextReceiptTemplateNumber-Umfeld Zeile 7280ff.)
- src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs (Zeilen 1-140)
- src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs (mehrere gezielte Ausschnitte: Header/Formatwahl 100-200, Positionsverarbeitung 780-1050, Steuerlogik 2080-2130, Referenzdokument 1870-1900)
- src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs (CheckRMMArticle-Umfeld Zeilen 700-810, 1900-2060, Exception-Klasse Zeilen 2400-2416)
- src/backend/Centron.Entities/Entities/Sales/CustomerAssets/Contracts/ContractArticleReferenzes.cs (vollständig)
- src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs (Zeilen 149-238, Methodenübersicht via Grep)
- src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs (BlockNewReceiptsDunningLevel-Umfeld)
- src/backend/Centron.BL/Finances/Payments/PaymentsBL.cs (Zeilen 1-150)
- src/backend/Centron.BL/VoucherManagement/VoucherManagementBL.cs (vollständig, sehr klein/dünn)
- src/backend/Centron.BL/Warehousing/ActionPriceBL.cs (relevante Methode SaveOrUpdateActionPrice)
- src/centron/Centron.WPF.UI/.../AddActionPriceViewModel.cs (Ok()-Methode)
- src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs (Dunning-Settings-Ausschnitt)
- src/backend/Centron.Entities/Entities/Accounts/AccountCustomer.cs / IAccountCustomer.cs (LockOrderAfterDunningLevel)
- src/backend/Centron.DAO/Repositories/Accounts/AccountRepository.cs (Dunning-Feld-Mapping-Ausschnitt)
- src/backend/Centron.BL/WebServices/Sales/Receipts/DunningWebServiceBL.cs (vollständig)
**Bewusst ausgelassen / nur oberflächlich per Grep gesichtet (Zeitbudget):**
- src/backend/Centron.BL/Sales/Receipts/Invoices/Dunning/DunningBL.cs (nur referenziert, nicht Zeile für Zeile gelesen) – enthält vermutlich die eigentliche Mahnstufen-Berechnung; für tiefere SwRS-Kandidaten zur exakten Mahnstufen-Ermittlung empfehlenswert
- src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.Zugferd10.cs (Legacy-ZUGFeRD-1.0-Variante) nicht gelesen
- src/backend/Centron.BL/WebServices/Sales/Receipts/DownPayment/DownPaymentWebServiceBL.cs (Anzahlungsrechnungen) nicht gelesen – potenzieller weiterer Kandidatenbereich für Nachfolgeanalyse
- src/backend/Centron.BL/WebServices/Sales/Receipts/OposRunWebServiceBL.cs (OPOS-Liste/offene Posten) nicht gelesen
- Preismatrix-Kernlogik (PriceMatrixViewModel.cs) nicht direkt gelesen, nur über Dokumentation referenziert (BILL-23)
- Skonto-Berechnung (AssetConditionBL.GetPaymentConditionSkontoInBR_DE_18Format) nicht im Detail gelesen, nur referenziert
- SupplierInvoice/SupplierCreditVoucher-seitige Spiegelprozesse (Kreditorenseite) nicht untersucht – Cluster-Fokus lag auf Debitoren-/Verkaufsseite gemäß Auftrag
- Centron.DAO-Constraints (DB-Skripte, NOT NULL/CHECK-Constraints) wurden nicht systematisch nach zusätzlichen Abrechnungs-Constraints durchsucht; punktuell nur für ActionPrice (BILL-24) als Lückenbefund genutzt
**Bekannte Lücken für Konsolidierung:**
- Kein dediziertes `InvoiceStatus`/`VoucherStatus`/`ContractStatus`-Enum gefunden; alle Belegtypen nutzen einheitlich `ReceiptState` (Active/Completed/Canceled) – ggf. mit anderen Clustern (z.B. Auftrags-/Logistik-Cluster) abgleichen, da dieselbe Statusmaschine auch dort verwendet wird.
- BILL-23, BILL-25, BILL-27, BILL-28 sind nur SEKUNDÄR (Dokumentation) belegt, da aus Zeitgründen die referenzierten Code-Stellen (PriceMatrixViewModel.cs, InvoiceZugferdBL.cs Settlement-Bereich im Detail, AnlageLog-Konstanten) nicht zeilengenau gegengelesen wurden – vor Übernahme in die konsolidierte Spezifikation nachverifizieren.
- BILL-24 ist ein Risikobefund (Gap): fehlende serverseitige Validierung bei ActionPrice – sollte in der Zielarchitektur (Web/SaaS) explizit als Anforderung "serverseitige Validierung" aufgenommen werden, nicht nur als Ist-Zustand dokumentiert.
@@ -0,0 +1,506 @@
# RRE Rohbefunde – Cluster STAMMDATEN / CRM (Geschäftspartner, Kunden, Mitarbeiter-Stammdaten)
Quellbasis: `C:\DEV\MasterArbeit\QuellCode\CentronERP` (nur gelesen, keine Änderungen).
Hinweis: Der im Auftrag genannte Ordner `Centron.BL/BusinessPartner` enthält faktisch nur Lieferanten-Suche/-Assets
(`SearchSupplierBL.cs`, `SupplierAssetBL.cs`); die Kunden-/CRM-Kernlogik liegt unter `Centron.BL/Sales/Customers`
(Namespace `Centron.BusinessLogic.Sales.Customers`). Beide Bereiche wurden einbezogen.
---
### Kandidat CRM-01
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb
Vorbedingung: Neuanlage eines Kunden (Geschäftspartner Typ Kunde)
Fakt: Beim Speichern eines neuen `Customer` prüft `StoreCustomerBL.DoValidateValues` ausschließlich, ob `entity.Name` leer/whitespace ist; ist dies der Fall, wird der Speichervorgang mit der Meldung "Bitte geben Sie einen Namen ein" abgebrochen. Kein anderes Feld (z. B. Adresse, USt-IdNr., Bankverbindung) wird beim Speichern serverseitig validiert.
Aussage: Das System soll beim Anlegen und Ändern eines Kunden-Geschäftspartners zwingend einen nicht-leeren Namen verlangen und den Speichervorgang andernfalls mit einer Fehlermeldung ablehnen.
Ergebnis: Speichern schlägt fehl mit Fehlermeldung "Bitte geben Sie einen Namen ein", solange `Name` leer ist; alle übrigen Felder sind serverseitig ungeprüft.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:39-51 (`DoValidateValues`) - Begründung: Einzige serverseitige Pflichtfeldprüfung beim Kunden-Speichern.
Prüfidee: Kunde ohne Namen über Backend-API/BL anlegen und Fehlermeldungstext/-code prüfen; Kunde mit Namen aber ohne Adresse/USt-IdNr. anlegen und beobachten, dass kein Fehler auftritt.
Konsolidierungshinweis: Ergänzt CRM-18 (fehlende Formatvalidierung USt-IdNr./IBAN).
Status: belegt
---
### Kandidat CRM-02
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb
Vorbedingung: Neuanlage eines Kunden über `CustomerBL.GetEmptyCustomer`
Fakt: Ein neu instanziierter Kunde erhält per Default `State = 1` (aktiv) und `Locked = false` (nicht gesperrt); zusätzlich wird automatisch eine leere Standard-Adresse (`DefaultCustomer = true`) angelegt.
Aussage: Das System soll neu angelegte Kunden standardmäßig als aktiv und ungesperrt initialisieren und automatisch eine als Standard markierte Adresse anlegen.
Ergebnis: Neuer Kunde ist sofort `State=1`, `Locked=false`, mit genau einer Default-Adresse.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:12-17 (`State = 1` im Konstruktor) - Begründung: Basis-Default.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:198-211 (`GetEmptyCustomer`) - Begründung: Explizite Zuweisung `State=1; Locked=false;` plus Default-Adresse.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:30-34 - Begründung: Bei `isNew` wird `State=1`/`Locked=false` beim Speichern erneut erzwungen.
Prüfidee: Neuen Kunden über UI/BL anlegen, DB-Werte für `Status`/`Sperre` und Adress-Flag `DefaultCustomer` prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat CRM-03
Ebene: SyRS
Typ: funktional / Daten
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Kunde besitzt mehrere Adressen
Fakt: `AddressBL.DoAfterStoreTrans` erzwingt nach dem Speichern einer Adresse mit `DefaultCustomer = true`, dass alle anderen Adressen desselben Kunden `DefaultCustomer = false` erhalten (analog für Lieferanten mit `DefaultCreditor`).
Aussage: Das System soll sicherstellen, dass ein Kunde (bzw. Lieferant) zu jedem Zeitpunkt genau eine als Standard markierte Adresse besitzt.
Ergebnis: Beim Setzen einer neuen Standardadresse werden alle vorherigen Standard-Flags desselben Kunden automatisch zurückgesetzt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:257-287 (`DoAfterStoreTrans`) - Begründung: Zeigt Kaskadenlogik für eindeutige Standardadresse/-kreditor.
Prüfidee: Zweite Adresse eines Kunden als Standard markieren und speichern; prüfen, dass die erste Adresse automatisch entmarkiert wird.
Konsolidierungshinweis: Zusammen mit CRM-04 (Standard-Ansprechpartner) und CRM-05 (Adresszuordnung) Kernregel der Adressverwaltung.
Status: belegt
---
### Kandidat CRM-04
Ebene: SyRS
Typ: funktional / Daten
Akteur: Vertrieb
Vorbedingung: Adresse besitzt mehrere Ansprechpartner
Fakt: `ContactPersonBL.DoAfterStoreTrans` → `DoUpdateDefaultFlagFromOtherContacts` setzt beim Speichern eines Ansprechpartners mit `Default = true` alle anderen Ansprechpartner derselben Adresse auf `Default = false`.
Aussage: Das System soll sicherstellen, dass jede Adresse höchstens einen als Standard markierten Ansprechpartner besitzt.
Ergebnis: Eindeutigkeit des Standard-Ansprechpartners je Adresse wird durch die Business-Logik erzwungen (kein DB-Constraint, sondern Anwendungslogik).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:190-220 (`DoAfterStoreTrans`, `DoUpdateDefaultFlagFromOtherContacts`) - Begründung: Explizite Kaskadenlogik.
Prüfidee: Zwei Ansprechpartner derselben Adresse abwechselnd als Standard markieren, DB-Zustand prüfen.
Konsolidierungshinweis: Ergänzt CRM-03.
Status: belegt
---
### Kandidat CRM-05
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb, Buchhaltung (Kunden und Lieferanten teilen die Adress-Entität)
Vorbedingung: Anlage/Änderung einer Adresse
Fakt: `AddressBL.DoValidateValues` verlangt, dass eine Adresse entweder einer `CustomerI3D` oder einer `SupplierI3D` zugeordnet ist; ansonsten Fehlermeldung "Die Anschrift muss entweder einem Kunden oder einem Lieferanten zugeordnet sein."
Aussage: Das System soll jede Adresse zwingend genau einem Geschäftspartner (Kunde oder Lieferant) zuordnen und darf keine „verwaisten" Adressen speichern.
Ergebnis: Speichern einer Adresse ohne Kunden- oder Lieferanten-Referenz wird abgelehnt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:225-238 (`DoValidateValues`) - Begründung: Wortlaut der Validierungsregel und Fehlermeldung.
Prüfidee: Adresse ohne `CustomerI3D`/`SupplierI3D` speichern und Fehlermeldung prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat CRM-06
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Neuer Kunde ohne explizite Adresse/Ansprechpartner wird gespeichert
Fakt: `StoreCustomerBL.DoBeforeStoreTrans` legt bei fehlender Default-Adresse automatisch eine neue Adresse an (`AddressBL.CreateNewAddressForCustomer`) bzw. markiert die erste vorhandene Adresse als Standard; analog wird bei fehlendem Standard-Ansprechpartner automatisch einer erzeugt (`ContactPersonBL.GetEmptyContactPersonForAddress`) oder der erste vorhandene als Standard markiert. Die I3D (Kundennummer) eines neuen Kunden wird, falls `<=0`, über `Session.GetGenericDAO<Customer>().GetMaxValue() + 1` vergeben.
Aussage: Das System soll beim Anlegen eines Kunden automatisch eine gültige Mindeststruktur (genau eine Standardadresse mit genau einem Standard-Ansprechpartner) sowie eine fortlaufende Kundennummer sicherstellen.
Ergebnis: Jeder gespeicherte Kunde besitzt danach mindestens eine Default-Adresse mit mindestens einem Default-Ansprechpartner und eine eindeutige numerische Kundennummer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:53-106 (`DoBeforeStoreTrans`) - Begründung: Vollständige Auto-Vervollständigungslogik inkl. I3D-Vergabe (Zeile 61-64).
Prüfidee: Kunde ohne Adressliste anlegen; DB-Zustand nach Speichern prüfen (Adresse + Ansprechpartner vorhanden, `DefaultCustomer=true`, `Default=true`).
Konsolidierungshinweis: Ergänzt CRM-02.
Status: belegt; Workaround (Kundennummernvergabe per `MAX(I3D)+1` ohne erkennbare Sperre/Transaktion gegen Race Conditions im gesichteten Code – HYPOTHESE bzgl. Nebenläufigkeitssicherheit, da keine expliziten Locks sichtbar sind)
---
### Kandidat CRM-07
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Kunde wird für Folgeprozesse (Auftrag, Angebot, Rechnung) referenziert
Fakt: `CustomerBL.IsCustomerActiveUnlocked(Customer)` definiert einen Kunden als "aktiv/entsperrt" genau dann, wenn `customer.State == 1 && !customer.Locked`; diese Prüfung wird u. a. in `GetActiveUnlockedCustomer` verwendet.
Aussage: Das System soll einen Kunden als geschäftlich nutzbar (aktiv) nur dann behandeln, wenn sowohl der Status "aktiv" (`State=1`) gesetzt als auch keine Sperre (`Locked=false`) vorliegt.
Ergebnis: Zwei unabhängige Felder (`State`, `Locked`) steuern gemeinsam die Nutzbarkeit eines Kunden im System.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:382-391 (`IsCustomerActiveUnlocked`, `IsCustomerActiveAndNotLocked`) - Begründung: Zentrale Statuslogik.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99, 182-196 (`SearchCustomerBySearchText`, `GetActiveCustomerCompact`) - Begründung: Kundensuche filtert konsistent auf `State==1 && !Locked`.
Prüfidee: Kunden mit `State=1, Locked=true` und `State=0, Locked=false` anlegen und prüfen, dass beide in Standard-Kundensuchen nicht erscheinen.
Konsolidierungshinweis: Grundlage für CRM-08 (Statusfeld-Bedeutung), CRM-19 (Dongle-Statusprüfung).
Status: belegt
---
### Kandidat CRM-08
Ebene: StRS
Typ: Daten
Akteur: Vertrieb, Buchhaltung
Vorbedingung: -
Fakt: Der Kundenstatus wird über zwei getrennte, unabhängig setzbare Attribute abgebildet: `State` (int, wirkt wie "aktiv/inaktiv", Vergleich `== 1`) und `Locked` (bool, "gesperrt"). Es existiert kein enumeriertes Statusmodell mit benannten Zuständen (z. B. "gelöscht", "archiviert", "Bonitätssperre") im gesichteten BL-Code.
Aussage: Das System soll den Lebenszyklus-Status eines Kunden (aktiv/inaktiv, gesperrt/entsperrt) als eigenständiges fachliches Konzept abbilden, das im Zielsystem klar benannte, erweiterbare Zustände (z. B. Enum statt Rohint) unterstützt.
Ergebnis: Migrationsrelevanter Fakt: Legacy-Datenmodell nutzt zwei binäre/int-Felder statt eines State-Machine-Modells.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:15,30 (`State`, `Locked`) - Begründung: Felddefinition.
- [KONTEXT] src/backend/Centron.Entities/Entities/Businesspartner/Supplier.cs:8-9 - Begründung: Lieferant besitzt nur `State`, kein `Locked`-Äquivalent – Asymmetrie zwischen Kunden- und Lieferanten-Stammdatenmodell.
Prüfidee: Klärung mit Fachbereich, ob Lieferanten je gesperrt werden können und wie das aktuell (ohne `Locked`-Feld) gehandhabt wird.
Konsolidierungshinweis: Bezug zu CRM-07.
Status: HYPOTHESE (fehlende Information: ob Lieferanten-Sperre über anderes Feld/Modul realisiert wird – im gesichteten `Supplier`-Entity nicht vorhanden)
---
### Kandidat CRM-09
Ebene: SwRS
Typ: Schnittstelle / Daten
Akteur: Vertrieb, IT-Administration
Vorbedingung: Neuanlage eines Kunden
Fakt: `CustomerBL.CreateCustomerDirectories` legt beim Neuanlegen eines Kunden automatisch eine feste Verzeichnisstruktur im Dokumentenmanagement an (u. a. Bestellungen, Angebote, Aufträge, Service, Lieferscheine, Abholscheine, Rechnungen, Helpdesk, Geräte, Verträge, Projekte, Aktivitäten, Mails, Gutschriften) plus konfigurierbare Zusatzverzeichnisse aus `CustomerDirectory`.
Aussage: Das System soll bei Kundenanlage automatisch eine standardisierte, prozessbezogene Ablagestruktur im Dokumentenmanagement erzeugen.
Ergebnis: Jeder neue Kunde erhält ~14 Standardverzeichnisse plus rekursive Zusatzverzeichnisse.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:438-597 (`CreateCustomerDirectories`, `InsertSpecialCustomerDirectories`) - Begründung: Vollständige Verzeichnisliste und Rekursionslogik.
Prüfidee: Neuen Kunden anlegen und Verzeichnisbaum im DMS-Modul auf Vollständigkeit prüfen.
Konsolidierungshinweis: Relevant für spätere Cluster "Dokumentenmanagement" – hier nur als Kunden-Nebenwirkung erfasst.
Status: belegt
---
### Kandidat CRM-10
Ebene: SwRS
Typ: Daten
Akteur: Personalabteilung
Vorbedingung: Mitarbeiter-Stammdatensatz vorhanden
Fakt: `EmployeeBL.GetEmployeeCompactValidationExpression<T>()` definiert einen Mitarbeiter als "aktiv" gemäß: `State == 1 AND (CommencementDate == null OR CommencementDate <= heute) AND (LeavingDate == null OR LeavingDate > heute OR LeavingDate <= 1900-01-01)`. Das Datum `1900-01-01` wird also als Sentinel-Wert für "kein Austrittsdatum gesetzt" interpretiert.
Aussage: Das System soll einen Mitarbeiter automatisch anhand von Status, Eintritts- und Austrittsdatum als aktiv/inaktiv einstufen, ohne dass ein separates manuelles "Aktiv"-Flag gepflegt werden muss.
Ergebnis: Aktivitätsstatus ergibt sich aus drei Feldern kombiniert; `1900-01-01` fungiert als technischer Nullwert-Ersatz für `LeavingDate`.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs:671-676 (`GetEmployeeCompactValidationExpression`) - Begründung: Exakte Formel der Aktiv-Berechnung.
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/EmployeeArea/EmployeeBase.cs:15-23 (`CommencementDate`, `LeavingDate`, `IsActive`) - Begründung: Zeigt, dass zusätzlich noch ein eigenständiges `IsActive`-Feld existiert, das parallel gepflegt werden kann (`GetAllInactiveEmployees` nutzt `IsActive==false` statt der Expression, Zeile 321-324).
Prüfidee: Mitarbeiter mit `LeavingDate = 1899-01-01` bzw. `LeavingDate = null` anlegen und prüfen, ob beide als "aktiv" gelten (sofern `State=1`); Vergleich mit `IsActive`-Feld auf Inkonsistenzen prüfen.
Konsolidierungshinweis: Zwei parallele Aktiv-Konzepte (`IsActive`-Flag vs. berechneter Ausdruck) – Klärungsbedarf für Zielsystem.
Status: belegt; Workaround (Sentinel-Datum 1900-01-01 statt NULL-Semantik; zwei redundante Aktiv-Konzepte im Datenmodell)
---
### Kandidat CRM-11
Ebene: SyRS
Typ: Sicherheit
Akteur: Personalabteilung
Vorbedingung: Bearbeitung eines Mitarbeiter-Stammdatensatzes
Fakt: `EmployeeBL.SaveOrUpdateEmployee` prüft vor jedem Speichern das Recht `UserRightsConst.Administration.EmployeeManagement.ADMINISTRATE_ALL_EMPLOYEES`; ohne dieses Recht wird der Aufruf mit "You do not have the necessary rights to perform this action." abgelehnt.
Aussage: Das System soll das Anlegen und Ändern von Mitarbeiter-Stammdaten auf Benutzer mit dem Recht "Mitarbeiterverwaltung" beschränken.
Ergebnis: Rechteprüfung vor jeder Mitarbeiter-Speicherung; Fehlermeldung bei fehlendem Recht.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs:128-131 (`SaveOrUpdateEmployee`) - Begründung: Explizite Rechteprüfung als erste Anweisung der Methode.
Prüfidee: Benutzer ohne `ADMINISTRATE_ALL_EMPLOYEES` versuchen lassen, einen Mitarbeiter zu speichern; Fehlermeldung/-code prüfen.
Konsolidierungshinweis: Analog CRM-12 (AppUser), CRM-13 (Kundenzugriff).
Status: belegt
---
### Kandidat CRM-12
Ebene: SyRS
Typ: Sicherheit / Daten
Akteur: Personalabteilung, IT-Administration
Vorbedingung: Anlegen/Ändern eines Benutzerkontos (`AppUser`), das mit einem Mitarbeiter verknüpft ist
Fakt: `AppUserBL.SaveOrUpdateAppUser` prüft das Recht `RIGHT_PERSONALMANAGEMENT`; verlangt bei Neuanlage einen bereits gespeicherten `Employee`; prüft die Eindeutigkeit des Login-Namens (`Name`, case-insensitive, getrimmt) unter allen `AppUser` UND zusätzlich gegen alle `WebAccount.Username` (kundengebundene Web-Zugänge); bei Kollision mit einem WebAccount wird der zugehörige Kunde in der Fehlermeldung genannt. Zusätzlich wird `OpenIdConnectSubjectIdentifier` global eindeutig geprüft.
Aussage: Das System soll sicherstellen, dass ein Login-Name eines internen Benutzerkontos systemweit eindeutig ist – sowohl unter internen Benutzerkonten als auch gegenüber Web-Kundenzugängen – und dass eine externe SSO-Kennung (OpenID Connect Subject) global eindeutig bleibt.
Ergebnis: Speichern schlägt fehl mit spezifischer Fehlermeldung, wenn Login-Name oder OIDC-Kennung bereits vergeben sind; Meldung nennt bei WebAccount-Kollision explizit Kundenname und -nummer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:136-186 (`SaveOrUpdateAppUser`) - Begründung: Vollständige Validierungs-/Rechtekette inkl. Fehlermeldungstexte.
Prüfidee: Zwei AppUser mit gleichem (Groß-/Kleinschreibung abweichendem) Login anlegen; AppUser-Login identisch zu bestehendem WebAccount-Username anlegen; Fehlermeldungen prüfen.
Konsolidierungshinweis: Cross-Entity-Dublettenprüfung – relevant für spätere Cluster "Benutzer-/Rechteverwaltung" und "Web-Portal".
Status: belegt
---
### Kandidat CRM-13
Ebene: SyRS
Typ: funktional / Daten
Akteur: IT-Administration, Personalabteilung
Vorbedingung: Ermittlung aktiver interner Benutzer
Fakt: `AppUserBL.GetActiveAppUsers` definiert einen aktiven `AppUser` über eine Kombination aus `IsAccountDisabled == false`, einem Zeitfenster-Check auf `AccountDisabledFromDate`/`AccountDisabledToDate` (Konto kann zeitlich befristet deaktiviert sein) UND zusätzlich `Employee.IsActive == true`.
Aussage: Das System soll ein Benutzerkonto nur dann als aktiv betrachten, wenn weder eine permanente noch eine zeitlich befristete Kontosperre vorliegt und der zugehörige Mitarbeiter als aktiv geführt wird.
Ergebnis: Aktivstatus eines Logins hängt von drei Feldern des `AppUser` plus dem Aktivstatus des verknüpften `Employee` ab.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:38-55 (`GetActiveAppUsers`) - Begründung: Komplexe, mehrteilige Bedingung im Code sichtbar.
Prüfidee: AppUser mit `AccountDisabledFromDate` in der Zukunft anlegen und prüfen, ob er aktuell noch als aktiv gilt (erwartet: ja, da Sperre erst ab Datum wirkt).
Konsolidierungshinweis: Ergänzt CRM-10 (Mitarbeiter-Aktivstatus), da AppUser-Aktivstatus vom Employee-Aktivstatus abhängt, aber NICHT dieselbe Formel wie `GetEmployeeCompactValidationExpression` nutzt (Inkonsistenz).
Status: belegt; Workaround (zwei unterschiedliche "Mitarbeiter aktiv"-Kriterien im Code: `EmployeeBL.GetEmployeeCompactValidationExpression` vs. hier direktes `Employee.IsActive` – mögliche Dateninkonsistenz)
---
### Kandidat CRM-14
Ebene: SyRS
Typ: Sicherheit
Akteur: Vertrieb
Vorbedingung: Kundensuche/-anzeige
Fakt: `CustomerBL.HasUserReadCustomersRight` prüft das Recht `UserRightsConst.Sales.Customer.CustomerCommon.SEARCH_CUSTOMER`; `SearchCustomerBL.SearchCustomerBySearchTextWithPaging` prüft zusätzlich das (offenbar ältere/parallele) Recht `UserRightsConst.RIGHT_KUNDENSTAMM`.
Aussage: Das System soll den lesenden Zugriff auf Kundenstammdaten an ein dediziertes Benutzerrecht koppeln.
Ergebnis: Kundensuche/-liste liefert bei fehlendem Recht einen Fehler bzw. eine leere/verweigerte Antwort.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:234-240 (`HasUserReadCustomersRight`) - Begründung: Rechteprüfung `SEARCH_CUSTOMER`.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/SearchCustomerBL.cs:113-121 (`SearchCustomerBySearchTextWithPaging`) - Begründung: Zweites, abweichendes Recht `RIGHT_KUNDENSTAMM`.
Prüfidee: Benutzer mit nur einem der beiden Rechte gegen beide Endpunkte testen, um Inkonsistenz zu bestätigen.
Konsolidierungshinweis: Möglicher technischer Schulden-Befund: zwei unterschiedliche Rechte für denselben fachlichen Vorgang (Kunden lesen/suchen).
Status: HYPOTHESE (fehlende Information: ob `RIGHT_KUNDENSTAMM` und `SEARCH_CUSTOMER` fachlich bewusst unterschiedliche Berechtigungsstufen abbilden oder ein historisches Duplikat sind)
---
### Kandidat CRM-15
Ebene: SwRS
Typ: Daten
Akteur: Buchhaltung
Vorbedingung: Kunde mit Umsatzsteuer-relevanten Daten
Fakt: Die Umsatzsteuer-Identifikationsnummer wird redundant an zwei Stellen geführt: pro Adresse als `Address.AdressSalesTaxIdentificationNumber` und separat auf Kundenebene als `CustomerFinanceInfo.SalesTaxIdentificationNumber`; zusätzlich existiert `Customer.VATNotActive` (bool) sowie identisch benannt `CustomerFinanceInfo.VATNotActive`. Ein Format-/Prüfsummen-Check (z. B. gegen EU-USt-IdNr.-Schema) wurde im BL-Code nicht gefunden.
Aussage: Das System soll die Umsatzsteuer-Identifikationsnummer als eindeutiges, konsistentes Attribut je Geschäftspartner führen und deren Format serverseitig validieren (kein Duplikat auf Adress- und Kundenebene).
Ergebnis: Migrationsrelevanter Datenmodell-Befund: redundante/uneindeutige Führung der USt-IdNr., keine Formatprüfung serverseitig.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Address.cs:30 (`AdressSalesTaxIdentificationNumber`) - Begründung: Feld auf Adressebene.
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Customers/CustomerFinanceInfo.cs:9,11 (`SalesTaxIdentificationNumber`, `VATNotActive`) - Begründung: Zweites, konkurrierendes Feld auf Kundenebene.
- [KONTEXT] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:131 (`VATNotActive`) - Begründung: Drittes Feld gleichen Namens direkt auf `Customer`.
Prüfidee: Prüfen, welches der Felder tatsächlich in Rechnungsstellung/EDI (z. B. ZUGFeRD) verwendet wird; Format-Grep in Validierungs-/Regex-Bibliotheken.
Konsolidierungshinweis: Wichtig für SwRS-Feindefinition bei Neuimplementierung (Single Source of Truth für USt-IdNr.).
Status: HYPOTHESE (fehlende Information: welches Feld führend ist und ob eine Formatvalidierung an anderer Stelle – z. B. UI-Layer, hier nicht vollständig durchsucht – existiert)
---
### Kandidat CRM-16
Ebene: SyRS
Typ: nicht-funktional / Daten
Akteur: Buchhaltung
Vorbedingung: Erfassung von Bankverbindungen am Kunden
Fakt: `Customer` führt zwei vollständige, redundant modellierte Bankverbindungssätze direkt als Entity-Felder (`BankIBAN`, `BankSWIFT`, `BankCountry`, `BankCity`, `BankStreet` sowie `Bank02`/`BankCode02`/`BankAccountNumber02`/`BankIBAN02`/`BankSWIFT02`/`BankCountry02`/`BankCity02`/`BankStreet02`) statt einer normalisierten 1:n-Beziehung zu Bankkonten.
Aussage: Das System soll Bankverbindungen eines Kunden als normalisierte, beliebig erweiterbare Liste (nicht als fest verdrahtete Feldpaare "01"/"02") modellieren.
Ergebnis: Datenmodell begrenzt einen Kunden technisch auf maximal zwei Bankverbindungen.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:134-146 - Begründung: Zeigt die verdoppelten Feldsätze `Bank...`/`Bank...02`.
Prüfidee: Fachbereich befragen, ob mehr als zwei Bankverbindungen je Kunde jemals benötigt wurden (z. B. bei Konzernkunden/Sammelkonten).
Konsolidierungshinweis: Migrationsrelevanter Datenmodell-Befund für Zielarchitektur.
Status: belegt
---
### Kandidat CRM-17
Ebene: SwRS
Typ: nicht-funktional / Sicherheit
Akteur: Buchhaltung, Vertrieb
Vorbedingung: Erfassung/Änderung der Bankverbindung eines Kunden in der WPF-Oberfläche
Fakt: Die IBAN-Prüfsummenvalidierung (Modulo-97-Verfahren nach ISO 7064) ist ausschließlich im WPF-Client implementiert (`IbanValidation.IbanChecksumCheck`) und wird konkret im Bankdaten-Formular des Kunden (`CrmFinanceView.xaml.cs`, Fehlertext "Keine gültige IBAN") aufgerufen. Im Backend (`Centron.BL`) wurde keine entsprechende Prüfung gefunden (weder in `StoreCustomerBL` noch in `BankAccountBL`).
Aussage: Das System soll die Prüfsummenvalidität einer IBAN serverseitig (nicht nur clientseitig) vor dem Persistieren erzwingen.
Ergebnis: Eine über einen anderen Kanal (z. B. API, Import, zukünftiges Web-Frontend) gespeicherte, prüfsummenungültige IBAN wird vom Backend nicht abgelehnt.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Finances/Crm/Finance/CrmFinanceView.xaml.cs:30-39 - Begründung: Aufruf der Validierung nur im UI-Eventhandler.
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/DataExchange/DataImport/AccountImport/IbanValidation.cs:10-35 (`IbanChecksumCheck`) - Begründung: Implementierung des Mod-97-Verfahrens, referenziert externe Quelle "dotnet-snippets.de".
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:39-51 - Begründung: Zeigt, dass die serverseitige Validierung IBAN nicht prüft (Negativbeleg).
Prüfidee: IBAN mit falscher Prüfsumme über eine Web-Service-/API-Schnittstelle (unter Umgehung der WPF-Oberfläche) speichern und prüfen, ob das Backend dies zulässt.
Konsolidierungshinweis: Ergänzt CRM-15/CRM-16 (Bankdaten-Qualität); zentrale Erkenntnis für SyRS "serverseitige Validierung erforderlich".
Status: belegt; Workaround (Validierung nur clientseitig vorhanden – Lücke bei Neuimplementierung als Web-/SaaS-System zu schließen, da UI-Client dort nicht die einzige Eingabequelle ist)
---
### Kandidat CRM-18
Ebene: StRS
Typ: Sicherheit / Compliance
Akteur: Buchhaltung, Vertrieb, Datenschutzbeauftragter
Vorbedingung: Löschantrag zu einer Kontaktperson (DSGVO/Art. 17 DSGVO)
Fakt: `DataSecurityBL` implementiert eine "DSGVO löschen"-Funktion für `ContactPerson`: personenbezogene Felder (Geburtsdatum, Beruf, Telefon 1-5, Fax 1-2, E-Mail 1-2, Mailing-Flags, Kommentarfelder, Abteilung, Bild, Active-Directory-SID, Website, Web-Zugangsdaten) werden geleert bzw. mit dem Platzhaltertext "DSGVO: Auf Anfrage gelöscht. (Durchgeführt von {ShortSign} am {Datum} um {Uhrzeit} Uhr)" überschrieben; jeder gelöschte Wert wird vor dem Löschen in ein Lösch-Protokoll (`deleteProtocol`) geschrieben; die Kontaktperson erhält `IsDsgvoDeleted=true`, `DsgvoDeletedEmployeeI3D`, `DsgvoDeletedDate` und wird (außer bei `Standard`-Kontakt) deaktiviert (`Status=0`).
Aussage: Das System soll auf Anfrage die personenbezogenen Daten einer Kontaktperson DSGVO-konform anonymisieren, den Vorgang inkl. verantwortlichem Mitarbeiter und Zeitpunkt nachvollziehbar protokollieren und die vorherigen Werte für Nachweiszwecke in einem Löschprotokoll festhalten.
Ergebnis: Kontaktperson ist nach Ausführung anonymisiert, als DSGVO-gelöscht markiert und (i. d. R.) deaktiviert; ein Audit-Trail bleibt erhalten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:1152-1276 - Begründung: Vollständige Feld-für-Feld-Anonymisierungslogik inkl. Protokollierung und Statusmarkierung.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:26-27 - Begründung: Konstanten für den Lösch-Kommentartext.
Prüfidee: DSGVO-Löschung einer Testkontaktperson auslösen; prüfen, dass alle genannten Felder geleert sind, `IsDsgvoDeleted=true` gesetzt ist und ein lesbares Protokoll erzeugt wird.
Konsolidierungshinweis: Ergänzt CRM-19 (fehlende Kunden-Löschung), CRM-20 (Retentions-Statistiken).
Status: belegt
---
### Kandidat CRM-19
Ebene: SwRS
Typ: Compliance
Akteur: Datenschutzbeauftragter, Buchhaltung
Vorbedingung: DSGVO-Löschantrag bezieht sich auf einen gesamten Kunden (nicht nur eine Kontaktperson)
Fakt: Die Methode `DataSecurityBL.DoDeleteCustomer(int i3d, bool isReferenceDelete)` ist im Quellcode vorhanden, wirft aber unbedingt `throw new NotImplementedException("DoDeleteCustomer is not ready for use!")`. Der zugehörige Aufrufcode ist zudem auskommentiert (`// DoDeleteCustomer(...)`).
Aussage: Das System soll eine vollständige, DSGVO-konforme Löschung/Anonymisierung auf Kundenebene (nicht nur auf Ebene einzelner Kontaktpersonen) bereitstellen.
Ergebnis: Im Ist-System existiert aktuell keine produktiv nutzbare Funktion zur Löschung eines kompletten Kundendatensatzes im Rahmen der DSGVO-Bereinigung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:856-858 (`DoDeleteCustomer`) - Begründung: Explizite `NotImplementedException`.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:803 - Begründung: Auskommentierter Aufruf bestätigt, dass die Funktion nicht im aktiven Ablauf verwendet wird.
Prüfidee: Im laufenden System versuchen, eine kundenbezogene DSGVO-Löschung auszuführen, und den resultierenden Fehler dokumentieren.
Konsolidierungshinweis: Wichtige Lücke für StRS-Anforderung "vollständige Umsetzung des Rechts auf Löschung"; ergänzt CRM-18.
Status: belegt; Workaround (Funktion bewusst deaktiviert/nicht fertiggestellt)
---
### Kandidat CRM-20
Ebene: StRS
Typ: Compliance / Sicherheit
Akteur: Datenschutzbeauftragter
Vorbedingung: Durchführung einer DSGVO-Datenbereinigung
Fakt: `DataSecurityBL.GetDataSecurityCleanUpStats` liefert Statistiken zu löschrelevanten Datenbeständen (Kunden mit letzter Aktion älter als Datum X, bereits gelöschte Kunden, CRM-Aktivitäten älter als Datum X, Belege [Angebote/Aufträge/Lieferscheine/Abholscheine/Rechnungen/Gutschriften] älter als Datum X, mit Filter nach Kundenart/Objektart/Abschlussstatus). Zugriff ist an das Recht `UserRightsConst.DsgvoModule.ACCESS_CLEANUP_DATABASE` UND ein Feature-Flag `ModuleFeatures.IsDsgvoDatabaseCleanupAvailable` gekoppelt.
Aussage: Das System soll autorisierten Benutzern eine Übersicht über lösch-/archivierungsrelevante Alt-Datenbestände (Kunden, CRM-Aktivitäten, Belege) auf Basis konfigurierbarer Aufbewahrungsfristen bereitstellen, bevor eine Bereinigung ausgeführt wird.
Ergebnis: Statistik-Report vor Ausführung der eigentlichen Löschung; feature-geflaggt und rechtebeschränkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:34-62 (`GetDataSecurityCleanUpStats`) - Begründung: Zeigt Filter- und Rechtekombination.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:64-70 (`DataSecurityExecuteCleanUp`) - Begründung: Ausführungsmethode ist rechtegeschützt, der eigentliche Bereinigungsvorgang liefert im gesichteten Ausschnitt nur `Result.AsSuccess()` ohne sichtbare Löschlogik an dieser Stelle (weitere Implementierung evtl. in nicht gelesenen Codeteilen der 1900-Zeilen-Datei).
Prüfidee: Statistikabruf mit und ohne Recht `ACCESS_CLEANUP_DATABASE` testen; Feature-Flag deaktivieren und Verhalten prüfen.
Konsolidierungshinweis: Ergänzt CRM-18/CRM-19.
Status: belegt (Ausführungslogik nur teilweise gesichtet – Datei hat 1900 Zeilen, nicht vollständig gelesen)
---
### Kandidat CRM-21
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb
Vorbedingung: Kunde besitzt eine "Kundenherkunft" (`CustomerAncestry`, z. B. Konzernzugehörigkeit/Quelle)
Fakt: `CustomerAncestryBL.DeleteCustomerAncestry` verhindert das Löschen eines `CustomerAncestry`-Datensatzes, solange mindestens ein `Customer` mit `CustomerOriginI3D` darauf verweist (`Count`-Prüfung vor `Delete`), und liefert sonst die (englischsprachige) Fehlermeldung "Couldn´t be deleted, because the ancestry is used by customers".
Aussage: Das System soll referenzierte Stammdaten-Klassifikationswerte (hier: Kundenherkunft) erst dann zur Löschung zulassen, wenn keine Kunden mehr darauf verweisen.
Ergebnis: Referentielle Integrität wird anwendungsseitig (nicht per DB-Fremdschlüssel-Exception) sichergestellt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerDetails/CustomerAncestryBL.cs:33-43 (`DeleteCustomerAncestry`) - Begründung: Zeigt Zähl-Check und Fehlermeldung.
Prüfidee: Kundenherkunft löschen, die noch von einem Kunden referenziert wird; Fehlermeldung/-verhalten dokumentieren; feststellen, ob Fehlermeldung an Endnutzer tatsächlich englischsprachig ausgegeben wird (i18n-Lücke).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat CRM-22
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb (Helpdesk/Support)
Vorbedingung: Eingehende E-Mail soll automatisch einem Kunden/Ansprechpartner zugeordnet werden
Fakt: `ContactPersonBL.SearchAddressContactByEmailAddress` sucht Kontaktpersonen anhand der Absender-E-Mail über eine benannte Query (`SearchAddressContactByEmailAddress`) mit mehreren Prioritätsstufen (exakte E-Mail, Domain, Domain+Web, Domain+TLD). Das Verhalten wird über `WorkflowSetting` gesteuert: `IsCustomerDetectionOverEMailDomainActive` schaltet die Domain-basierte Erkennung ein/aus; `CustomerDetectionOverContactEMail1`/`CustomerDetectionOverContactEMail2` steuern, ob E-Mail-Feld 1 bzw. 2 der Kontaktperson für die Zuordnung herangezogen wird; zusätzlich wird die Domain gegen eine Blacklist (`DomainBlacklistBL.IsBlacklisted`, z. B. generische Provider wie gmail.com) geprüft, bevor eine Domain-Zuordnung erfolgt.
Aussage: Das System soll eingehende Kommunikation (z. B. Helpdesk-Mails) automatisch anhand konfigurierbarer Regeln (exakte Kontakt-E-Mail, Domain-Zugehörigkeit, Blacklist generischer Domains) einem Kunden bzw. einer Kontaktperson zuordnen können.
Ergebnis: Priorisierte, konfigurierbare automatische Kunden-/Kontakterkennung über E-Mail.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:310-411 (`SearchAddressContactByEmailAddress`, `FilterSearchAddressContactResults`) - Begründung: Zeigt vollständige Priorisierungs- und Konfigurationslogik.
Prüfidee: Test-Mail von bekannter Domain mit und ohne aktivierte Domain-Erkennung senden; Blacklist-Domain (z. B. gmail.com) testen und prüfen, dass keine Domain-Zuordnung erfolgt.
Konsolidierungshinweis: Schnittstellen-relevant für Cluster "Helpdesk/Ticketing" – hier nur aus CRM-Sicht (Kontaktzuordnung) erfasst.
Status: belegt
---
### Kandidat CRM-23
Ebene: SwRS
Typ: Daten / Sicherheit
Akteur: Personalabteilung, IT-Administration
Vorbedingung: Mitarbeiter erhält RFID-Token (z. B. für Zeiterfassung/Zutrittskontrolle)
Fakt: `EmployeeRfidTokenBL.SaveOrUpdateEmployeeRfidTokens` speichert `EmployeeRfidToken`-Datensätze mit AES/Master-Key-verschlüsseltem `RfidTokenEncrypted`-Wert (`CentronConfigurationDbBL.EncryptWithMasterKey`), prüft dabei aber weder auf Ebene der Methode noch erkennbar per DB-Constraint, ob derselbe Token bereits einem anderen Mitarbeiter zugeordnet ist oder ob ein Mitarbeiter bereits einen Token besitzt.
Aussage: Das System soll sicherstellen, dass ein RFID-Token eindeutig genau einem aktiven Mitarbeiter zugeordnet ist, um Fehlzuordnungen bei Zeiterfassung/Zutritt zu verhindern.
Ergebnis: Ohne zusätzliche DB-Constraints besteht das Risiko doppelt vergebener Tokens.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/EmployeeRfidTokenBL.cs:39-57 (`SaveOrUpdateEmployeeRfidTokens`) - Begründung: Keine Duplikatsprüfung im Methodenkörper sichtbar (nur `Guard.NotNull`).
Prüfidee: Zwei `EmployeeRfidToken`-Datensätze mit identischem entschlüsseltem Tokenwert für unterschiedliche Mitarbeiter anlegen und prüfen, ob dies zugelassen wird.
Konsolidierungshinweis: -
Status: HYPOTHESE (fehlende Information: ob Eindeutigkeit ggf. per DB-Unique-Index auf `RfidTokenEncrypted` sichergestellt ist – DAO/Mapping-Definitionen wurden für dieses Cluster nicht vollständig durchsucht)
---
### Kandidat CRM-24
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Länderstammdaten für Adressen/Kunden
Fakt: `CountryBL.GetDefaultCountry()`/`GetDefaultCountryI3D()` ermitteln genau ein Land mit `Default == true` (`.First()` bei der I3D-Variante, was bei keinem gesetzten Default-Land eine Exception auslösen würde); `GetInlandCountry` leitet das "Inland" hingegen aus `MandatorBL.GetDefaultMandator().Country` ab, mit explizitem TODO-Kommentar "TODO: Check the country of the branch for the current user...", d. h. eine niederlassungsspezifische (Branch-)Länderzuordnung ist noch nicht implementiert.
Aussage: Das System soll für jede Adresse automatisch ein Vorgabeland setzen (Neuanlage), abgeleitet aus dem für den Benutzer/die Niederlassung gültigen Mandanten- bzw. Niederlassungsland.
Ergebnis: Aktuell wird global das Mandanten-Standardland verwendet, unabhängig von der Niederlassung des angemeldeten Benutzers.
Belege:
- [PRIMÄR] src/backend/Centron.BL/CountryArea/CountryBL.cs:190-207 (`GetInlandCountry`, `GetDefaultCountryI3D`, `GetDefaultCountry`) - Begründung: Zeigt Implementierung und offenes TODO.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:46-51,248-249 - Begründung: `GetInlandCountry`/`GetDefaultCountry` werden beim Anlegen neuer Adressen als Default gesetzt.
Prüfidee: Benutzer einer Niederlassung mit abweichendem Land eine neue Kundenadresse anlegen lassen und beobachten, welches Land vorbelegt wird.
Konsolidierungshinweis: -
Status: belegt; Workaround (TODO im Code bestätigt unvollständige Niederlassungs-Länderzuordnung)
---
### Kandidat CRM-25
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Kunde besitzt Vertriebsbetreuer
Fakt: `CustomerBase` besitzt sechs Betreuer-Referenzen `Adviser1I3D`…`Adviser6I3D`, von denen die ersten vier im Code kommentiert sind als "Innendienst" (Adviser1), "Aussendienst" (Adviser2), "Techniker 1" (Adviser3), "Techniker 2" (Adviser4); `SearchCustomerBL.GetCustomerFromEmployeeExpression` nutzt genau diese vier Felder, um Kunden eines Mitarbeiters zu ermitteln (Adviser5/6 werden dort nicht berücksichtigt).
Aussage: Das System soll einem Kunden mehrere Betreuerrollen (u. a. Innendienst, Außendienst, Techniker) mit je einem zuständigen Mitarbeiter zuordnen können und Mitarbeitern ihre zugeordneten Kunden anzeigen.
Ergebnis: Vier feste Betreuerrollen sind fachlich benannt und in der Kundensuche nach Mitarbeiter aktiv genutzt; zwei weitere Felder (`Adviser5/6I3D`) sind im Modell vorhanden, aber ohne erkennbare fachliche Bezeichnung/Verwendung in den gesichteten Dateien.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:19-24 - Begründung: Kommentare benennen die Rollen.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/SearchCustomerBL.cs:82-90 (`GetCustomerFromEmployeeExpression`) - Begründung: Nutzung von Adviser1-4, Auslassung von Adviser5/6.
Prüfidee: UI-Bezeichnungen der Felder Adviser5/Adviser6 im WPF-Client (nicht Teil dieses Clusters) abgleichen, um deren fachliche Bedeutung zu klären.
Konsolidierungshinweis: -
Status: belegt (Rollen 1-4); HYPOTHESE bzgl. Adviser5/6 (fehlende Information zur fachlichen Bezeichnung)
---
### Kandidat CRM-26
Ebene: SwRS
Typ: Daten
Akteur: Vertrieb
Vorbedingung: Kunde benötigt Bestellnummer-Pflicht bei Auftragserfassung
Fakt: `Customer.PurchaseOrderNumberRequiered` (bool) ist ein pro Kunde konfigurierbares Flag; ebenso `Customer.ProjNrNeeded` (Projektnummer-Pflicht) und `Customer.ProductionConfigurationRequiring`.
Aussage: Das System soll pro Kunde konfigurierbar erzwingen können, dass bei der Auftrags-/Belegerfassung bestimmte Zusatzangaben (Bestellnummer des Kunden, Projektnummer, Produktionskonfiguration) verpflichtend sind.
Ergebnis: Kundenindividuelle Pflichtfeld-Schalter, die vermutlich in nachgelagerten Modulen (Auftragserfassung) ausgewertet werden (dort nicht verifiziert, da außerhalb des Clusters).
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:48 (`PurchaseOrderNumberRequiered`) - Begründung: Feld inkl. auffälligem Schreibfehler im Bezeichner ("Requiered" statt "Required").
- [KONTEXT] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:208,235-236 (`ProjNrNeeded`, `ProductionConfigurationRequiring`, `PrintProductionConfiguration`) - Begründung: Weitere kundenindividuelle Pflicht-/Steuerflags.
Prüfidee: Auftrag für Kunden mit `PurchaseOrderNumberRequiered=true` ohne Bestellnummer anlegen (im Auftragsmodul, nicht Teil dieses Clusters) und Systemverhalten prüfen.
Konsolidierungshinweis: Für Cluster "Vertrieb/Auftragsabwicklung" ggf. gegenzuprüfen, wo diese Flags ausgewertet werden.
Status: belegt (Feldexistenz); HYPOTHESE bzgl. Durchsetzung außerhalb dieses Clusters nicht verifiziert
---
### Kandidat CRM-27
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung, Vertrieb
Vorbedingung: Lieferant/Kontaktperson mit E-Mail-Adresse
Fakt: `SearchSupplierBL.SearchSupplierByEmail` sucht zunächst Lieferanten mit exakt passender `Supplier.Email`; findet sie keine, sucht sie aktive `ContactPerson` mit passender `Email1`/`Email2`, deren Adresse `DefaultCreditor = true` markiert ist, und leitet daraus den zugehörigen Lieferanten ab.
Aussage: Das System soll einen Lieferanten sowohl über eine direkt hinterlegte Firmen-E-Mail als auch über die E-Mail-Adresse des Standard-Ansprechpartners (an der als Standard-Kreditor markierten Adresse) auffindbar machen.
Ergebnis: Zweistufige Fallback-Suche für Lieferantenidentifikation per E-Mail.
Belege:
- [PRIMÄR] src/backend/Centron.BL/BusinessPartner/SearchSupplierBL.cs:84-121 (`SearchSupplierByEmail`) - Begründung: Zeigt zweistufige Suchlogik inkl. `DefaultCreditor`-Filter.
Prüfidee: Lieferant ohne eigene E-Mail, aber mit Standard-Ansprechpartner-E-Mail anlegen; Suche nach dieser E-Mail testen.
Konsolidierungshinweis: Analog zu CRM-22 (Kunden-/Kontakterkennung per E-Mail), hier für Lieferanten.
Status: belegt
---
### Kandidat CRM-28
Ebene: StRS
Typ: nicht-funktional (Datenqualität)
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Anlage/Pflege von Kunden- und Lieferanten-Stammdaten über die Zeit
Fakt: Im gesamten gesichteten `Centron.BL`-Code (Customer-, Address-, ContactPerson-, Supplier-Bereich) wurde keine Dubletten-Erkennung (z. B. Ähnlichkeitssuche über Name/Adresse/USt-IdNr.) und keine Merge-Funktion für zwei Geschäftspartner-Datensätze gefunden; die einzige Unterstützung ist die Freitext-Suche nach Matchcode/Name/I3D vor manueller Neuanlage (`SearchCustomerBL`, `SearchCustomerBySearchText`).
Aussage: Das System soll Vertriebs- und Buchhaltungsmitarbeiter bei der Neuanlage von Geschäftspartnern durch eine aktive Dubletten-Prüfung (z. B. Ähnlichkeitssuche) unterstützen und eine Funktion zum Zusammenführen (Merge) versehentlich doppelt angelegter Datensätze bereitstellen.
Ergebnis: Fehlende Funktionalität im Ist-System; Dublettenvermeidung liegt vollständig in der manuellen Sorgfalt des Sachbearbeiters.
Belege:
- [KONTEXT] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99 (`SearchCustomerBySearchText`) - Begründung: Zeigt, dass nur eine einfache Textsuche als Vorab-Prüfung existiert.
- [KONTEXT] Negativbefund aus gezielter Suche (`grep -rniE "dublette|duplicate|merge"` über `Sales/Customers`, `EmployeeArea`, `CountryArea`, `BusinessPartner`) - Begründung: Keine Treffer zu fachlicher Dubletten-/Merge-Logik für Geschäftspartner (nur technische Login-Duplikatsprüfungen, siehe CRM-12).
Prüfidee: Fachbereich befragen, ob Dublettenbereinigung ggf. über ein separates, hier nicht durchsuchtes Modul (z. B. externes Datenqualitäts-Tool) erfolgt, das nicht Teil von `Centron.BL` ist.
Konsolidierungshinweis: Zentrale StRS-Anforderung für die Web-/SaaS-Neuimplementierung; unabhängig von CRM-12 (dort nur technische Login-Namen-Eindeutigkeit, keine fachliche Geschäftspartner-Dublette).
Status: HYPOTHESE (fehlende Information: Negativbefund – Abwesenheit von Funktionalität kann nicht abschließend über Quellcode-Grep bewiesen werden, ggf. existiert Logik in einem nicht durchsuchten Modul oder als externes Tool)
---
## Abdeckung
**Gelesen (vollständig oder in relevanten Ausschnitten):**
- `src/backend/Centron.BL/Sales/Customers/CustomerBL.cs` (komplett, 653 Zeilen)
- `src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs` (komplett, 135 Zeilen)
- `src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs` (komplett, 309 Zeilen)
- `src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs` (komplett, 518 Zeilen)
- `src/backend/Centron.BL/Sales/Customers/SearchCustomerBL.cs` (Ausschnitt, erste 150 von 509 Zeilen)
- `src/backend/Centron.BL/Sales/Customers/CustomerDetails/CustomerAncestryBL.cs` (komplett, 45 Zeilen)
- `src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs` (Ausschnitte: Zeilen 1-250, 316-345, 460-480, 640-690)
- `src/backend/Centron.BL/EmployeeArea/AppUserBL.cs` (komplett, 252 Zeilen)
- `src/backend/Centron.BL/EmployeeArea/EmployeeRfidTokenBL.cs` (komplett, 91 Zeilen)
- `src/backend/Centron.BL/CountryArea/CountryBL.cs` (komplett, 219 Zeilen)
- `src/backend/Centron.BL/BusinessPartner/SearchSupplierBL.cs` (Ausschnitt, erste 120 Zeilen)
- `src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs` (Ausschnitte: Zeilen 1-150, 1150-1300, plus Grep über Gesamtdatei; Datei hat 1900 Zeilen, nicht vollständig gelesen)
- `src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs`, `CustomerBase.cs`, `Address.cs` (komplett)
- `src/backend/Centron.Entities/Entities/EmployeeArea/EmployeeBase.cs` (komplett)
- `src/backend/Centron.Entities/Entities/Businesspartner/Supplier.cs` (komplett, 44 Zeilen)
- `src/backend/Centron.Entities/Entities/Sales/Customers/CustomerFinanceInfo.cs` (komplett)
- `src/centron/Centron.WPF.UI/Modules/DataExchange/DataImport/AccountImport/IbanValidation.cs` (komplett)
- `src/centron/Centron.WPF.UI/Modules/Finances/Crm/Finance/CrmFinanceView.xaml.cs` (Ausschnitt, IBAN-Validierungshandler)
**Ausgelassen / nicht vertieft (bekannte Lücken):**
- `Centron.BL/CustomerArea/*` (BusinessLineBL, ContactActivityBL, ContactDepartmentBL, InterestBL, ProductBL, RmaBL, RmaSendKindBL) – nur Dateiliste erfasst, Inhalte nicht gelesen.
- `Centron.BL/Sales/Customers/CRM/*` (CustomerActivityBL, CustomerActivityStatisticBL, CustomerCRMStatisticBL), `CrmProjects/CrmProjectBL.cs`, `Contacts/ContactSalutationBL.cs`, `SalutationBL.cs`, `CustomerSettingBL.cs`, `TextBlock/BusinessTextBlockBL.cs`, `CustomerDetails/SalesAreaBL.cs`, `Addresses/AddressSpecialArticleBL.cs`, `ContactExt.cs`, `CustomerExt.cs` – nicht gelesen; potenziell weitere CRM-Aktivitäten-/Klassifikationsregeln.
- `Centron.BL/EmployeeArea/*` außer den oben genannten (EmployeeArticleBL, EmployeeDepartmentBL, EmployeeHolidayBL, EmployeeStatisticBL, EmployeeUserSettingsBL, TeamManagement/TeamManagementBL) – nicht gelesen.
- `Centron.BL/CountryArea/FederalStateBL.cs` – nicht gelesen.
- `Centron.BL/BusinessPartner/SupplierAssetBL.cs` sowie Rest von `SearchSupplierBL.cs` (Zeilen 121-Ende) – nicht gelesen.
- `Centron.DAO`-Mapping-/Constraint-Definitionen (z. B. NHibernate `.hbm.xml` oder Fluent-Mappings) wurden nicht systematisch nach DB-seitigen UNIQUE-/NOT-NULL-Constraints durchsucht; alle hier dokumentierten Pflichtfeld-/Eindeutigkeitsregeln stammen aus der BL-Schicht (Anwendungslogik), nicht aus verifizierten DB-Constraints. Dies ist eine grundsätzliche Einschränkung für alle Kandidaten mit Aussagen zu "eindeutig"/"Pflichtfeld".
- Frontend (XAML/WPF-Views) wurde nur punktuell für CRM-17 (IBAN) herangezogen; UI-seitige Pflichtfeld-Kennzeichnungen (z. B. rote Sternchen, weitere Format-Validatoren wie E-Mail-Regex, Telefonnummer-Masken) wurden nicht systematisch erhoben.
- `DataSecurityBL.cs` (1900 Zeilen) enthält augenscheinlich analoge Lösch-/Anonymisierungslogik auch für Lieferanten und Interessenten (Zeilen ~1580-1850, u. a. weitere `DoDelete...`-Methoden mit "Comment"/"Kommentar"-Feldern) – nur stichprobenartig erfasst, nicht vollständig ausgewertet.
- Es wurde keine gezielte Suche nach IBAN/USt-IdNr.-Validierung in Web-Service-Schnittstellen (`Centron.BL/WebServices/**`) durchgeführt; CRM-17/CRM-15 könnten dort weitere (bislang nicht gefundene) Validierungen besitzen.
@@ -0,0 +1,460 @@
# Cluster: Dokumente, Reporting & Textbausteine — Rohbefunde (RRE)
Analyseumfang: DocuBoard (BL/DAO/Entities/WebServices), DocumentationArea, Administration/FileManagement (Dokumentenverwaltung), ReportEngine, Reporting, TextModuleArea, Centron.Api.docuFORM.
Hinweis vorab: Der Ordner `DocuBoard` enthält entgegen der Namenserwartung **kein** Dokumentenmodul, sondern IT-Asset-/Gerätemanagement (Partner, Artikelzuordnung, AD-Systembenutzer-Ausschluss). Die eigentliche Dokumentenverwaltung liegt unter `Administration/FileManagement` (`DocumentBL`, `Directory`, `SharedDocument`). Dies wird unten als eigener Befund (DOC-01) dokumentiert, weitere Anforderungen zu Dokumenten beziehen sich auf `FileManagement`.
---
### Kandidat DOC-01
Ebene: KONTEXT (Namensraum-Klärung, keine eigene Anforderung)
Typ: Daten
Akteur: Entwickler/Architekt (Migrationsteam)
Vorbedingung: -
Fakt: Der Namespace/Ordner `Centron.BL/DocuBoard` (und korrespondierend `Centron.Entities/Entities/DocuBoard`, `Centron.DAO/Mappings/DocuBoard`, `Centron.BL/WebServices/DocuBoard`) enthält ausschließlich Klassen zu IT-Asset-Management (`AssetManagementPartnerBL`, `AssetManagementArticleAssignmentBL`, `AssetManagementADSystemUserExclusionBL`), keine Dokumentenverwaltung. Die tatsächliche Dokumentenverwaltung (Upload, Versionierung, Sperren, Volltextsuche) befindet sich in `Centron.BL/Administration/FileManagement/DocumentBL.cs`.
Aussage: (kein SwRS-Kandidat; Migrationshinweis) Bei der Neumodellierung ist der Begriff „DocuBoard" nicht mit Dokumentenverwaltung gleichzusetzen; ein Modul „Asset-/Gerätemanagement" ist separat von „Dokumentenverwaltung" zu führen.
Ergebnis: Vermeidung von Fehlinterpretation der Fachdomäne bei der Anforderungsableitung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DocuBoard/AssetManagementPartnerBL.cs:1-55 - Begründung: Klasseninhalt (Partner, Items, CustomerCompact) zeigt Gerätemanagement, kein Dokument-Bezug.
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:49-72 - Begründung: Enthält die tatsächliche Dokument-CRUD-Logik (GetDocumentsByDirectory, GetDocument).
Prüfidee: Abgleich mit Fachbereich/Product Owner, ob „DocuBoard" als Produktname für ein separates Asset-Modul vermarktet wird.
Konsolidierungshinweis: Betrifft ggf. auch das Cluster „IT-Asset-Management", falls ein anderer Agent dieses Thema bearbeitet.
Status: belegt
---
### Kandidat DOC-02
Ebene: StRS
Typ: funktional (Geschäftsziel)
Akteur: Sachbearbeiter (Vertrieb/Verwaltung), Administrator
Vorbedingung: Benutzer ist an c-entron angemeldet und besitzt Zugriff auf einen Ordner (Directory)
Fakt: `DocumentBL.AddFileToDirectory` legt Dokumente in einer Ordnerstruktur (`Directory`) ab, verknüpft Metainformationen (`DocumentMetaInformation`), setzt einen Dokumenttyp-abhängigen Icon-Index (`GetImageIndexForDocumentType`) und aktualisiert die Trefferanzahl des Ordners (`NumDocuments`). Bei Helpdesk-Ordnern wird zusätzlich ein Historieneintrag erzeugt (`HelpdeskHistoryBL.CreateHistoryForDocument`).
Aussage: Das System soll es Sachbearbeitern ermöglichen, beliebige Dateien in einer hierarchischen Ordnerstruktur abzulegen, automatisch nach Dateityp zu kategorisieren (Icon/Typ) und bei fachlichem Bezug (z. B. Helpdesk-Vorgang) automatisch eine Historie zu führen.
Ergebnis: Zentrale, typisierte Dokumentenablage mit Prozessanbindung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:587-648 - Begründung: `AddFileToDirectory` Implementierung inkl. MetaInformations, ImageIndex, Historie.
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/Administration/FileManagement/Document.cs:17-54 - Begründung: Entity-Felder bestätigen Typ/Version/Directory-Modell.
Prüfidee: UI-Test: Datei in Kundenordner hochladen, prüfen ob Icon nach Dateityp korrekt vergeben wird und `NumDocuments` im Elternordner steigt.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-03
Ebene: SyRS
Typ: funktional
Akteur: Sachbearbeiter
Vorbedingung: Dokument existiert bereits (documentI3D > 0)
Fakt: `DocumentBL.CheckOutDocument`/`CheckInDocument`/`UndoCheckOut` implementieren ein Sperr-(Lock-)Konzept über `LockedBy` (Employee), `LockedByWorkstation`, `LockedFilePath`. `CanCheckOutDocument` verweigert das Auschecken, wenn bereits gesperrt. `UpdateDocument` verweigert ein Update, wenn das Dokument von einem anderen Benutzer gesperrt ist (`document.LockedBy != currentUser.User.Employee` → return null, kein Fehlertext).
Aussage: Das System soll ein Check-out/Check-in-Verfahren für Dokumente bereitstellen, das gleichzeitige Bearbeitung durch mehrere Benutzer durch eine Sperre (Employee, Workstation, Dateipfad) verhindert.
Ergebnis: Kollisionsfreie kollaborative Dokumentbearbeitung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:878-951 - Begründung: CanCheckOutDocument/CheckOutDocument/CheckInDocument/UndoCheckOut.
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:538-585 - Begründung: UpdateDocument prüft Sperre vor Änderung, gibt bei Fremdsperre `null` zurück (kein sprechender Fehlercode).
Prüfidee: Zwei parallele Sessions: Benutzer A checkt aus, Benutzer B versucht Update → erwartete Ablehnung.
Konsolidierungshinweis: -
Status: belegt; Workaround (UpdateDocument liefert bei Sperre `null` statt Fehlermeldung/Result-Objekt — inkonsistent zum übrigen Result-Pattern)
---
### Kandidat DOC-04
Ebene: SwRS
Typ: Daten / nicht-funktional (Versionierung)
Akteur: System (automatisiert)
Vorbedingung: Dokument wird aktualisiert (UpdateDocument, CheckInDocument, AddNewDocumentVersion)
Fakt: Jede Dokumentaktualisierung erzeugt einen **neuen** `Document`-Datensatz mit inkrementierter `Version` (`document.Version + 1`) statt eines Updates des bestehenden Datensatzes; alle Versionen referenzieren über `OwnerDocument` den „Kopf"-Datensatz. `GetDocumentsFromDirectory` filtert pro `OwnerDocument`-Gruppe nur die jeweils neueste Version (`Max(f => f.Version)`).
Aussage: Das System soll Dokumentversionen unveränderlich (append-only) verwalten: jede neue Version ist ein eigener Datensatz, verknüpft über eine Ankerreferenz (OwnerDocument), wobei Standardlisten nur die aktuellste Version anzeigen.
Ergebnis: Nachvollziehbare Versionshistorie ohne Datenverlust.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:538-585 - Begründung: UpdateDocument-Methode, Erzeugung neues Document-Objekt mit Version+1.
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:94-112 - Begründung: GetDocumentsFromDirectory gruppiert nach OwnerDocument, wählt max. Version.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:843-876 - Begründung: AddNewDocumentVersion als expliziter Versionierungs-Endpunkt.
Prüfidee: Datei zweimal hochladen (gleicher Name/Ordner) → prüfen ob zwei Datensätze mit Version 1/2 und gemeinsamer OwnerDocument-Referenz entstehen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-05
Ebene: SwRS
Typ: nicht-funktional (Performance/Datenintegrität)
Akteur: System (automatisiert)
Vorbedingung: Dokument (z. B. PDF eines Belegs) wird wiederholt exportiert/gedruckt
Fakt: `DocumentBL.GetIdenticalDocumentInDirectory` (referenziert Ticket 160276) prüft vor dem Speichern, ob im Zielordner bereits ein Dokument mit identischem Namen, identischer Version und identischer Dateigröße existiert, um mehrfaches Ablegen desselben Report-PDFs bei wiederholtem Druck/Export zu vermeiden.
Aussage: Das System soll beim automatischen Ablegen generierter Belegdokumente (z. B. Rechnungs-PDFs) Duplikate anhand von Name, Version und Dateigröße erkennen und vermeiden.
Ergebnis: Reduzierte Datenredundanz im Dokumentenarchiv.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:74-92 - Begründung: Methode inkl. Code-Kommentar mit Ticket-Referenz 160276.
Prüfidee: Denselben Beleg zweimal exportieren, prüfen ob nur ein Dokumentdatensatz im Zielordner entsteht.
Konsolidierungshinweis: Hängt mit DOC-13 (PDF-Archivierung) zusammen.
Status: belegt
---
### Kandidat DOC-06
Ebene: SyRS
Typ: Sicherheit
Akteur: Sachbearbeiter, Administrator
Vorbedingung: Löschversuch eines Dokuments
Fakt: `DocumentBL.CanDeleteDocument` verhindert das Löschen eines Dokuments, wenn es (a) in einem aktiven, noch nicht abgeschlossenen elektronischen Signierprozess (`SharedDocument`, `IsSigned == false`, nicht abgelaufen) als Basis-, Abrede-, Anrede- oder Signaturdatei verwendet wird, oder (b) in den globalen Einstellungen (`AppSettingsGroupBL.GetSharedDocumentSettings`) als Standard-Abrede/-Anrede/-Signatur für einen der sechs Belegtypen (Angebot, Auftrag, Lieferschein, Abholschein, Rechnung, Gutschrift, Vertrag) hinterlegt ist. Jeder Fall liefert eine spezifische deutsche Fehlermeldung mit `DefaultMessageCodes.DocumentInActiveSigningProcess` bzw. `.ErrorMessage`.
Aussage: Das System soll das Löschen von Dokumenten verhindern, solange diese in einem laufenden elektronischen Unterschriftsprozess referenziert oder als Systemvorlage für Signaturprozesse konfiguriert sind, und dem Benutzer den konkreten Verwendungszweck als Fehlermeldung mitteilen.
Ergebnis: Schutz vor Datenverlust bei referenzierten Vorlagen/aktiven Rechtsvorgängen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:425-536 - Begründung: Vollständige CanDeleteDocument-Logik mit allen Fehlermeldungstexten.
Prüfidee: Dokument, das als Signatur-Einstellung für Rechnungen hinterlegt ist, löschen → erwartete Fehlermeldung "...als Signatur für den Signierungs-Prozess für Rechnungen eingestellt".
Konsolidierungshinweis: Überschneidet sich mit dem Cluster „C-Sign/Signierprozesse" (SharedDocument) — dort ggf. tiefergehend behandelt.
Status: belegt
---
### Kandidat DOC-07
Ebene: SwRS
Typ: Sicherheit
Akteur: Sachbearbeiter, Administrator
Vorbedingung: Dokument (.msg/.eml) enthält S/MIME-Signatur
Fakt: `DocumentBL.GetMailDocumentFromEml` verifiziert bei signierten E-Mail-Anhängen (MultipartSigned/ApplicationPkcs7Mime) die S/MIME-Signatur über `TemporarySecureMimeContext`. Bei Fehlschlag der Verifikation wird nur eine Warnung geloggt (`Logger.Warn`), die Mail wird trotzdem unverifiziert angezeigt.
Aussage: Das System soll beim Anzeigen archivierter E-Mail-Dokumente (.eml) vorhandene S/MIME-Signaturen prüfen und dem Benutzer erkennbar machen, wenn die Signatur ungültig oder nicht verifizierbar ist.
Ergebnis: Vertrauenswürdigkeit archivierter E-Mail-Kommunikation.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:196-234 - Begründung: Verifikationslogik inkl. Warn-Logging bei Fehlschlag.
Prüfidee: Signierte E-Mail mit ungültiger Signatur importieren und im DocuBoard/FileManagement öffnen — prüfen ob Warnhinweis im UI sichtbar ist (aktuell nur Log, kein UI-Hinweis erkennbar).
Konsolidierungshinweis: -
Status: HYPOTHESE (fehlende Information: Es ist im BL-Code nicht erkennbar, ob die Warnung tatsächlich bis in die UI durchgereicht wird oder nur im Server-Log verbleibt — WPF-Client-Code wurde in diesem Cluster nicht geprüft.)
---
### Kandidat DOC-08
Ebene: SwRS
Typ: Daten / Validierung
Akteur: System (automatisiert)
Vorbedingung: Dokumentname enthält Nicht-ASCII/Sonderzeichen
Fakt: `DocumentBL.SaveOrUpdateDocument` bereinigt den Dokumentnamen mit Regex `[^-ÿ]+` (entfernt alle Zeichen außerhalb Latin-1), da die DB-Spalte `Name` als `varchar` (kein Unicode) definiert ist und laut Code-Kommentar "auf manchen DBs auch indiziert" ist und nicht mehr geändert werden kann.
Aussage: Das System soll beim Speichern eines Dokumentnamens Zeichen außerhalb des Latin-1-Zeichensatzes entfernen, um Beschädigungen durch die nicht-Unicode-fähige Datenbankspalte zu vermeiden.
Ergebnis: Verhinderung von Zeichensatzproblemen/Datenkorruption bei Dokumentnamen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:680-686 - Begründung: Code inkl. erklärendem Kommentar zur technischen Schuld.
Prüfidee: Datei mit z. B. kyrillischem oder emoji-haltigem Dateinamen hochladen, prüfen welche Zeichen im gespeicherten Namen verloren gehen.
Konsolidierungshinweis: Für die Web/SaaS-Neuimplementierung mit Unicode-fähiger DB entfällt diese Einschränkung vermutlich — als technische Schuld / Migrationsanforderung vermerken.
Status: belegt; Workaround (Altlast wegen Legacy-DB-Schema)
---
### Kandidat DOC-09
Ebene: SyRS
Typ: funktional / Lizenzierung
Akteur: Sachbearbeiter
Vorbedingung: Lizenz "c-entron Office" (`LicenseGuids.DocumentProcessing`) vorhanden
Fakt: Volltextindizierung von Dokumenten (`CreateIndexesForDocument`) ist an eine Lizenzprüfung gebunden (`LicenseManager.Instance.HasLicense(LicenseGuids.DocumentProcessing)`); ohne Lizenz liefert die Methode Fehler „Lizenz für c-entron Office nicht vorhanden". Unterstützte Formate: .txt, .rtf, .docx, .pdf, .html, .doc, .msg, .eml (via DevExpress RichEdit/Pdf sowie MsgReader). Nicht erkannte Dateitypen erhalten keinen Index (`Result<int>.AsSuccess(-1)`).
Aussage: Das System soll Dokumente lizenzabhängig automatisch volltextindizieren (Formate: TXT, RTF, DOC/DOCX, PDF, HTML, MSG, EML) und bei fehlender Lizenz die Indizierung mit einer eindeutigen Fehlermeldung verweigern.
Ergebnis: Volltextsuche über Dokumentinhalte als lizenzpflichtiges Zusatzmodul.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:1122-1199 - Begründung: CreateIndexesForDocument mit Lizenzprüfung und Format-Switch.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:689-708 - Begründung: SaveOrUpdateDocument löst Indizierung synchron oder asynchron (je nach Einstellung `IsDocumentGenerateFulltextIndexAsyncActive`) nach jedem Speichern aus.
Prüfidee: Ohne Lizenz ein Dokument hochladen und Volltextsuche versuchen → erwartete Fehlermeldung; mit Lizenz PDF-Inhalt suchen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-10
Ebene: SyRS
Typ: funktional
Akteur: Sachbearbeiter
Vorbedingung: Benutzer hat Recht `RIGHT_DOCUMENTFILEREAD`
Fakt: `DocumentBL.SearchDocumentsThroughPaging` prüft zunächst das Benutzerrecht, unterstützt eine Sonderform `id:<Zahl>` für direkte I3D-Suche, kombiniert bei Volltextsuche pro Suchwort Indextreffer (nur Dokumente, die **alle** Suchwörter enthalten, mit Fallback auf Dokumente mit mind. einem Treffer) und begrenzt Ergebnisse aus Performancegründen hart auf 2000 Dokument-IDs sowie ein SQL-Timeout von 30 Sekunden.
Aussage: Das System soll eine rechteabhängige, paginierte Dokumentensuche mit Volltext- und Attributfiltern (Name, Typ, Größe, Ersteller, Datum) bereitstellen, wobei die Volltextsuche auf maximal 2000 Treffer-IDs begrenzt ist und Anfragen nach 30 Sekunden abgebrochen werden.
Ergebnis: Performante, rechtegeschützte Dokumentensuche auch bei großen Archiven.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:953-1118 - Begründung: SearchDocumentsThroughPaging + CreateFilterExpression inkl. Rechteprüfung, ID-Suche, 2000er-Limit, 30s-Timeout.
Prüfidee: Suche ohne Recht `RIGHT_DOCUMENTFILEREAD` ausführen → erwartete Fehlermeldung "Sie haben kein Recht, Dokumente zu lesen".
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-11
Ebene: StRS
Typ: funktional (Geschäftsziel)
Akteur: Sachbearbeiter (interne Dokumentation/Wissensdatenbank), Management
Vorbedingung: Benutzer hat Recht `READ_DOCUMENTATION` bzw. `READ_INTERNAL_DOCUMENTATION`
Fakt: `DocumentationBL` verwaltet fachliche „Dokumentationen" (z. B. zu Helpdesk-Vorgängen) mit zwei getrennten Sichtbarkeitsstufen: `PublicDocumentation` (immer sichtbar) und `InternalDocumentation` (wird aus dem Ergebnis entfernt, falls der Benutzer nicht das Recht `READ_INTERNAL_DOCUMENTATION` besitzt — in allen Get-Methoden konsequent per Schleife `documentation.InternalDocumentation = null`).
Aussage: Das System soll bei Wissens-/Vorgangsdokumentationen zwischen einer öffentlichen und einer nur intern sichtbaren Textkomponente unterscheiden und die interne Komponente rechteabhängig aus der Antwort entfernen (nicht nur UI-seitig ausblenden).
Ergebnis: Informationstrennung zwischen kundenseitig sichtbaren und internen Vermerken.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs:27-95 - Begründung: Mehrere GetDocumentation*-Methoden mit identischem Muster (Rechteprüfung + Entfernen von InternalDocumentation).
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/DocumentationArea/Documentation.cs:19-23 - Begründung: Entity-Felder PublicDocumentation/InternalDocumentation.
Prüfidee: Dokumentation mit beiden Feldern anlegen, mit Benutzer ohne READ_INTERNAL_DOCUMENTATION abrufen → InternalDocumentation muss `null` sein, nicht nur UI-verborgen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-12
Ebene: SwRS
Typ: Daten / Versionierung
Akteur: System (automatisiert)
Vorbedingung: Bestehende `Documentation` wird geändert (`isNew == false`)
Fakt: `DocumentationBL.DoBeforeStoreTrans` legt vor jeder Änderung einer bestehenden Documentation einen Snapshot als `DocumentationVersion` an (Caption, Category, ChangedBy/Date, CreatedBy/Date, State, Version, PublicDocumentation, InternalDocumentation etc.), inkl. TODO-Kommentar "ska 2013-02-20: temporary solution. We have to improve our logic to get the current application version." bei `ChangedVersion`.
Aussage: Das System soll bei jeder Änderung einer Dokumentation automatisch eine unveränderliche Versions-Kopie (Snapshot) mit Autor, Zeitstempel und Anwendungsversion erzeugen.
Ergebnis: Nachvollziehbare Änderungshistorie von Wissensdokumentationen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs:317-347 - Begründung: DoBeforeStoreTrans-Implementierung inkl. TODO-Kommentar zur unfertigen Versionsermittlung.
Prüfidee: Bestehende Dokumentation zweimal ändern, prüfen ob zwei DocumentationVersion-Datensätze mit korrekten Feldwerten entstehen.
Konsolidierungshinweis: Analog zu DOC-04 (Dokumentversionierung in FileManagement) — gleiches Architekturmuster (Append-Only-Historie), ggf. bei Migration vereinheitlichen.
Status: belegt; Workaround (ChangedVersion-Ermittlung laut Code-Kommentar seit 2013 unvollständig gelöst)
---
### Kandidat DOC-13
Ebene: SyRS
Typ: funktional
Akteur: System (automatisiert), Sachbearbeiter
Vorbedingung: Report wird aus einer Reportgruppe (z. B. Angebot, Rechnung) erzeugt
Fakt: `ReportDataBL.ConvertReportToPdfStream` archiviert das erzeugte PDF automatisch über `ArchivePdf`, außer (a) für die Gruppen Rechnung/Gutschrift (dort erfolgt Archivierung separat/anders), (b) `group.PDFExportActive == false`, (c) `ignoreReportGroupExport == true` (z. B. bei Vorschau), (d) Parameter `@NoPdfExport == "1"` oder `@Vorschau == "1"` gesetzt ist. Bei aktivierter Gruppe mit `CustomExportFilename` wird der Dateiname über `ReportGroupBL.GetExportFilename`/`PdfExportFilenameReplacementBL` anhand von Platzhaltern (Belegnummer, Version, Kundennummer, Datum) generiert.
Aussage: Das System soll erzeugte Belegreports (PDF) automatisch im Dokumentenarchiv ablegen, sofern die Reportgruppe dies erlaubt und es sich nicht um eine Vorschau handelt, wobei der Archiv-Dateiname über ein konfigurierbares Platzhalterschema (Nummer/Version/Kunde/Datum) gebildet wird.
Ergebnis: Automatische, konfigurierbare Belegarchivierung ohne Benutzerinteraktion.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1289-1420 (ConvertReportToPdfStream/ArchivePdf, Ausschnitt bis Zeile ~1387) - Begründung: Bedingungslogik für Archivierung inkl. Parameter-Flags.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportGroupBL.cs:46-132 - Begründung: GetExportFilename mit Belegarten-Mapping und Platzhalter-Dateinamen.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReplacementBLs/PdfExportFilenameReplacementBL.cs:17-58 - Begründung: Platzhalter „%Nummer%"-artige Konstanten (NUMBER, VERSION, CUSTOMER_ID, DATE) inkl. Regex-Rückwandlung für Dateisuche.
Prüfidee: Angebot mit aktivierter PDF-Archivierung und benutzerdefiniertem Dateinamensschema drucken; prüfen ob Datei mit erwartetem Muster im Kundendokumentenordner abgelegt wird.
Konsolidierungshinweis: Sonderbehandlung Rechnung/Gutschrift (siehe Code Zeile 1310) technisch unklar dokumentiert — evtl. eigener Kandidat nötig, falls andere Datei das im Detail regelt (ZUGFeRD/GoBD-Pflichtarchivierung, siehe DOC-15).
Status: belegt
---
### Kandidat DOC-14
Ebene: SwRS
Typ: funktional / Fehlerbehandlung
Akteur: System (automatisiert)
Vorbedingung: PDF-Erzeugung über alternativen PDF-Drucker (COM-Interface) schlägt fehl
Fakt: `PdfStrategies.GetPdfStrategy` wählt zwischen mehreren PDF-Erzeugungsstrategien (`DefaultPdfStrategy`, `PdfCreatorPdfStrategy`, `SevenPdfStrategy`, Fallback `FastReportPdfStrategy`) abhängig von Benutzereinstellungen. Schlägt eine alternative Strategie fehl, wird sie über `MarkStrategyAsFailed` für **30 Minuten** in einer statischen In-Memory-Dictionary (`_failedStrategies`) gesperrt; in diesem Zeitraum wird automatisch auf `FastReportPdfStrategy` zurückgefallen (`CreatePdf` in `ReportDataBL`). PDF/A-3-Pflicht (ZUGFeRD) wird nur unterstützt, wenn der gewählte Drucker `ExportsInPdfA3 == true` ist, sonst ebenfalls Fallback auf FastReport.
Aussage: Das System soll bei Fehlschlag eines konfigurierten alternativen PDF-Druckertreibers automatisch für einen Zeitraum von 30 Minuten auf eine interne Standard-PDF-Erzeugung (FastReport) ausweichen, um Reportdruck trotz Druckerfehler nicht zu blockieren.
Ergebnis: Ausfalltoleranz der PDF-Erzeugung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/PdfStategy/PdfStrategies.cs:23-157 - Begründung: Vollständige Strategie-Auswahl- und Fallback-/Circuit-Breaker-Logik inkl. 30-Minuten-Konstante.
- [SEKUNDÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1317-1345 - Begründung: CreatePdf nutzt Strategie, fängt Fehler ab und erzwingt Fallback FastReportPdfStrategy.
Prüfidee: Alternativen PDF-Drucker simuliert nicht verfügbar machen, prüfen ob nach Fehlschlag automatisch FastReport verwendet wird und ob nach 30 Minuten erneut versucht wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-15
Ebene: SyRS
Typ: Daten / Compliance
Akteur: Buchhaltung, System (automatisiert)
Vorbedingung: Reportgruppe = Rechnung (GUID `23EC705E-3C04-4B8F-AAB9-0C06C0C80759`), ZUGFeRD aktiviert
Fakt: `ReportDataBL.GetReportForPrinting`/`ConvertReportToPdfStream` prüft für die Rechnungsgruppe (`ReportGroupConstants.RECHNUNG`) über `InvoiceZugferdBL.IsZugferdEnabled()`, ob PDF/A-3b-Konformität (`requiresPdfA3`) erforderlich ist. `CustomZugferdPdfGenerator` registriert die Rechnungsgruppe als Ziel für einen speziellen ZUGFeRD-PDF-Generator. `PdfExportSettingsBL.ApplyPdfExportSettings` erzwingt bei PDF/A-3 fest `PdfCompliance = PdfA_3b` und `EmbeddingFonts = true` (nicht konfigurierbar), während Farbraum/Kompression/JPEG-Komprimierung konfigurierbar bleiben.
Aussage: Das System soll Rechnungsdokumente bei aktivierter ZUGFeRD-Funktion zwingend als PDF/A-3b mit eingebetteten Schriften erzeugen (E-Rechnungs-Konformität), unabhängig von den sonst konfigurierbaren PDF-Exporteinstellungen.
Ergebnis: Rechtskonforme elektronische Rechnungsstellung (ZUGFeRD/PDF-A3).
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1012-1020 - Begründung: requiresPdfA3 wird aus IsZugferdEnabled() für die Rechnungsgruppe abgeleitet.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/PdfExport/PdfExportSettingsBL.cs:169-216 - Begründung: ApplyPdfExportSettings erzwingt PdfA_3b + EmbeddingFonts bei requiresPdfA3.
- [SEKUNDÄR] src/backend/Centron.BL/ReportEngine/CustomPdfGenerators/CustomZugferdPdfGenerator.cs:1-18 - Begründung: Feste GUID-Zuordnung Rechnungsgruppe → ZUGFeRD-Generator.
Prüfidee: Rechnung mit aktivierter ZUGFeRD-Einstellung drucken, PDF/A-3b-Konformität des Ergebnisses technisch validieren (z. B. veraPDF).
Konsolidierungshinweis: Ggf. Überschneidung mit Cluster „Rechnungswesen/EDI" (ZugferdExportItem, InvoiceZugferdBL) — dort vermutlich tiefer behandelt.
Status: belegt
---
### Kandidat DOC-16
Ebene: SwRS
Typ: funktional / Datenintegrität
Akteur: Administrator (Reportentwicklung)
Vorbedingung: ReportData-Query-Kette mit `SuperQuery`-Verweisen
Fakt: `ReportDataBL.HasQueryLoop` erkennt zyklische Abhängigkeiten zwischen `ReportDataQuery`-Objekten (über `SuperQuery`-Referenzen) mittels iterativem Erreichbarkeits-Algorithmus. Bei erkannter Schleife bricht `Register()` mit Fehlermeldung „Loop detected in ReportData: '<Name>'" ab, bevor irgendeine Query ausgeführt wird.
Aussage: Das System soll bei der Registrierung eines Reports zyklische Abhängigkeiten zwischen verketteten Unterabfragen (Query-Chains) erkennen und die Reportausführung mit einer Fehlermeldung verhindern.
Ergebnis: Schutz vor Endlosschleifen/Fehlausführung bei fehlerhaft konfigurierten Reports.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:969-985 - Begründung: HasQueryLoop-Implementierung.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:626-633 - Begründung: Aufruf und Fehlerabbruch in Register().
Prüfidee: Zwei ReportDataQuery-Objekte mit sich gegenseitig referenzierendem SuperQuery anlegen und Reportausführung testen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-17
Ebene: SwRS
Typ: funktional (Diff/Migration von Parametern)
Akteur: Administrator (Reportentwicklung)
Vorbedingung: Ein im Report-Designer geänderter Report (`ReportData.ReportBase64`) wird gespeichert (`UpdateFastreport`)
Fakt: `ReportDataBL.CheckReportDataParameters` vergleicht die FastReport-Parameterliste des alten und neuen Reports (Name, Typ, Expression, Description). Parameter, die im Namen fehlen oder deren Typ sich geändert hat, werden aus `ReportDataParameters` gelöscht (`DeleteFRParameters`); neue/geänderte werden für alle betroffenen `ReportGroupsToReportData`-Zuordnungen neu angelegt (`AddFRParameters`); reine Beschreibungsänderungen werden aktualisiert (`UpdateFRParametgers`, Methode-Name enthält Tippfehler im Original).
Aussage: Das System soll beim Speichern eines geänderten Reports automatisch erkennen, welche benutzerdefinierten Reportparameter entfernt, neu hinzugefügt oder nur in der Beschreibung geändert wurden, und die zugehörigen Parameter-Konfigurationsdatensätze je Gruppenzuordnung entsprechend synchronisieren.
Ergebnis: Konsistente Parameterkonfiguration nach Report-Design-Änderungen ohne manuellen Abgleich.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1172-1249 - Begründung: CheckReportDataParameters + UpdateFastreport, inkl. Diff-Logik für Name/Typ/Description.
Prüfidee: Parameter in FastReport-Designer umbenennen/Typ ändern, Report speichern, prüfen ob ReportDataParameters-Tabelle korrekt aktualisiert wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-18
Ebene: SyRS
Typ: funktional
Akteur: Sachbearbeiter (Angebot/Auftrag/Rechnung/Mahnung/Helpdesk)
Vorbedingung: Beleg wird per Mail versendet oder gedruckt, TextModule vom Typ „Anrede"/„Abrede" wird benötigt
Fakt: `TextModuleBL.GetTextModule(int,int,TextModuleType)` löst Textbausteine nach einer festen Prioritätsreihenfolge auf: 1) kundenspezifischer, aktiver Textbaustein (`CustomerI3D` passend, `State==1`, kleinste I3D bei Mehrfachtreffern), 2) benutzerspezifischer aktiver Textbaustein (`UserI3D` passend, größte I3D), 3) globaler Standard-Textbaustein (`CustomerI3D==0 && UserI3D==0`, größte I3D). Kommentare im Code verweisen auf Delphi-Kompatibilität der Sortierreihenfolge.
Aussage: Das System soll beim Ermitteln von Anrede-/Abrede-Textbausteinen eine dreistufige Priorität anwenden: kundenspezifisch vor benutzerspezifisch vor global, wobei bei Mehrfachtreffern eine dokumentierte, altsystem-kompatible Sortierregel (älteste vs. neueste I3D) gilt.
Ergebnis: Konsistente, personalisierbare Standardtexte in Belegen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:396-418 - Begründung: GetTextModule-Implementierung mit expliziten Kommentaren zur Delphi-Kompatibilität der Sortierung.
Prüfidee: Für denselben TextModuleType je einen kunden-, benutzer- und globalen Textbaustein anlegen, prüfen ob der kundenspezifische priorisiert wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-19
Ebene: SwRS
Typ: Daten / Konfiguration
Akteur: Sachbearbeiter, Administrator
Vorbedingung: -
Fakt: `TextModuleType` (Enum in `Centron.WebServices.Core`) definiert für jeden Belegtyp (Angebot, Auftrag, Lieferschein, Abholschein, Rechnung, Gutschrift) je eine „Anrede" (AN_*) und „Abrede" (AB_*) Variante, zusätzlich Mahnstufen (AP_MAHNUNG1-3), Helpdesk-Textbausteine getrennt nach intern/extern/andere (je Anrede/Abrede), sowie Prozess-Mailtexte für Anfrage, Bestellung, Wareneingang, Kalkulation, Rücksendung, Angebot, Auftrag, Lieferschein, Abholschein, Rechnung, Gutschrift, OPOS, Lieferantengutschrift (Präfix AP_).
Aussage: Das System soll für jeden relevanten Belegtyp und Kommunikationsanlass einen eigenen, konfigurierbaren Textbaustein-Typ vorsehen (mind. 30 unterschiedliche Verwendungszwecke), getrennt nach Anrede/Abrede bzw. reinem Prozesstext.
Ergebnis: Feingranulare Steuerung der Standardtexte je Geschäftsvorfall.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:75-155 - Begründung: Vollständige Aufzählung aller TextModuleType-Werte in GetFilteredTextModuleList.
- [KONTEXT] src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/TextModuleArea/TextModuleType.cs - Begründung: Enum-Definition selbst (Datei lokalisiert, Inhalt in diesem Lauf nicht mehr im Detail gelesen).
Prüfidee: Katalog aller TextModuleType-Werte aus der Enum-Datei extrahieren und mit Fachbereich abgleichen, welche im Web-Redesign noch benötigt werden.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-20
Ebene: SwRS
Typ: funktional (Platzhalterlogik)
Akteur: System (automatisiert)
Vorbedingung: Textbaustein wird in Beleg/Mail eingefügt (Anrede/Abrede)
Fakt: `ReplacementBL.ReplaceVariables` ersetzt Platzhalter in Klartext sowie – bei erkanntem RTF-Format (`source.IsRtf()`) – direkt im RTF-Dokumentmodell (`RichEditDocumentServer`), inkl. Ersetzung in Hyperlink-Zielen (`hyperLink.NavigateUri`). Es gibt einen Fast-Path: Enthält der Text den Platzhalter-Bezeichner nicht, wird keine Ersetzung durchgeführt.
Aussage: Das System soll Platzhalter sowohl in Klartext- als auch in RTF-formatierten Textbausteinen (inkl. in Hyperlinks) ersetzen können, ohne die RTF-Formatierung zu zerstören.
Ergebnis: Konsistente Platzhalterersetzung unabhängig vom Textformat.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Core/ReplacementBL.cs:39-96 - Begründung: Vollständige Implementierung inkl. RTF-Sonderpfad und Hyperlink-Behandlung.
Prüfidee: RTF-Textbaustein mit Platzhalter in einem Hyperlink anlegen (z. B. `mailto:@@KdEMail@@`), Ersetzung prüfen.
Konsolidierungshinweis: Basis für DOC-21.
Status: belegt
---
### Kandidat DOC-21
Ebene: SwRS
Typ: Daten (Platzhalterkatalog)
Akteur: Sachbearbeiter
Vorbedingung: Anrede-/Abrede-Textbaustein wird für einen Kundenauftrag/-anlage aufbereitet
Fakt: `SalutationAndAgreementReplacementBL.ReplaceSalutationAndAgreement` definiert einen Katalog von >45 Platzhaltern im Format `@@Bezeichner@@` (z. B. `@@KdNummer@@`, `@@KdName@@`, `@@AnsprechVorname@@`, `@@BearbeiterEMail@@`, `@@VertriebsgebietKurz@@`), wobei viele Platzhalter mit Suffix „2"/„3" (`AddSameAsLast`) denselben Wert für mehrfach vorkommende Platzhalter im selben Text bereitstellen. Werte werden aus Kunde, Adresse, Ansprechpartner, Vertriebsgebiet und Bearbeiter (Editor) sowie zugeordnetem Mitarbeiter (Adviser1) gezogen; leere/fehlende Referenzen liefern Leerstring statt Fehler.
Aussage: Das System soll einen festen, dokumentierten Katalog von Platzhaltern für Kunden-, Kontakt-, Vertriebsgebiets- und Bearbeiterdaten bereitstellen, mehrfaches Vorkommen desselben Platzhalters im Text unterstützen und bei fehlenden Referenzdaten robust mit Leerwerten statt Fehlern reagieren.
Ergebnis: Wiederverwendbare, ausfallsichere Personalisierung von Textbausteinen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/SalutationAndAgreementReplacementBL.cs:40-215 - Begründung: Vollständiger Platzhalterkatalog mit Datenquellen.
- [SEKUNDÄR] src/backend/Centron.BL/TextModuleArea/SalutationAndAgreementReplacementBL.cs:224-326 - Begründung: GetFrom*-Hilfsmethoden zeigen einheitliches Null-safe-Muster (Leerstring bei fehlender Referenz).
Prüfidee: Kundenanlage ohne hinterlegten Ansprechpartner verwenden, prüfen ob `@@AnsprechVorname@@` als Leerstring statt Exception im Ergebnistext erscheint.
Konsolidierungshinweis: Ergänzt DOC-20 (technischer Ersetzungsmechanismus); zusammen ergeben sie die vollständige Textbaustein-Platzhalterlogik.
Status: belegt
---
### Kandidat DOC-22
Ebene: SwRS
Typ: funktional / Mail-Integration
Akteur: Sachbearbeiter
Vorbedingung: Beleg (Angebot, Auftrag, Rechnung etc.) wird per E-Mail versendet
Fakt: `TextModuleBL.ReplaceReceiptMailVariables` unterscheidet über `receipt.GetAccount()` (Pattern-Matching auf `IsCustomer`), ob der Beleg einen Kunden- oder Lieferantenbezug hat, und nutzt entsprechend unterschiedliche Platzhaltersätze (`ReplaceCustomerTextBlockVariables` via `MailTextBlockRepository.GetCustomerTextBlockVariables` inkl. `MailTrackingDTO`-Einstellungen, bzw. `ReplaceMailSupplierVariables` via `GetSupplierTextBlockVariables`). Der Kontakt für die Mail wird über `SpecificLogics.Execute(receipt, f => f.GetContactForMail(receipt))` ermittelt.
Aussage: Das System soll bei E-Mail-Versand eines Belegs automatisch erkennen, ob es sich um einen Kunden- oder Lieferantenvorgang handelt, und den jeweils passenden Platzhaltersatz inkl. Mail-Tracking-Konfiguration anwenden.
Ergebnis: Korrekte Personalisierung unabhängig von Belegrichtung (Verkauf/Einkauf).
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:510-529 - Begründung: ReplaceReceiptMailVariables mit Pattern-Matching auf Account-Typ.
Prüfidee: Lieferantenbestellung und Kundenangebot jeweils per Mail versenden, prüfen ob korrekte Platzhaltergruppe angewendet wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-23
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (automatisiert), Administrator (Gerätepark/Drucker)
Vorbedingung: Externer docuFORM-Server (Multifunktionsdrucker-Fleet-Management) konfiguriert, OAuth2-Zugangsdaten vorhanden
Fakt: `Centron.Api.docuFORM` ist entgegen des generischen Namens **kein Dokumentengenerierungs-API**, sondern ein REST-Client für ein externes Drucker-/Multifunktionsgeräte-Fleet-Management-System („docuFORM"): Endpunkte für OAuth2-Autorisierung (`/auth/v2/token`, `/auth/v2/authorize`), Geräteliste (`/dfmserver/v2/devices`) und Zählerstände pro Gerät (`/dfmserver/v2/devices/{id}/counters`, optional mit UTC-Datum).
Aussage: Das System soll über eine dedizierte REST-Schnittstelle (OAuth2, Client Credentials/Auth Code) Gerätestammdaten und Zählerstände (Seiten-/Kopierzähler) eines externen Drucker-Fleet-Management-Systems abrufen können.
Ergebnis: Integration von Druck-/Kopierzählern (vermutlich für Abrechnung/Controlling) externer MFP-Flotten.
Belege:
- [PRIMÄR] Centron.Api.docuFORM/DocuFormRestApiClient.cs:1-131 - Begründung: Vollständige Client-Implementierung inkl. Auth-Flow und Device/Counter-Endpunkten.
- [PRIMÄR] Centron.Api.docuFORM/DocuFormRestApiConstants.cs:1-15 - Begründung: Endpunkt-Konstanten bestätigen Domäne „dfmserver" (Device Fleet Management).
- [SEKUNDÄR] Centron.Api.docuFORM/IDocuFormApiClient.cs:1-21 - Begründung: Interface bestätigt Methodenumfang (RequestAuthorization, RequestToken, GetAllDevices, GetDeviceCounters).
Prüfidee: Mit Fachbereich klären, wofür Gerätezählerstände in c-entron verwendet werden (Leasingabrechnung? Verbrauchsmaterial-Controlling?) — im BL-Code dieses Clusters kein Aufrufer dieser Schnittstelle gefunden.
Konsolidierungshinweis: -
Status: HYPOTHESE (fehlende Information: Kein Aufrufer/Consumer dieses API-Clients wurde in `Centron.BL` innerhalb des untersuchten Bereichs gefunden; Verwendungszweck und aufrufende Business-Logik sind unklar. Ggf. anderes Cluster — Administration/Gerätemanagement — zuständig.)
---
### Kandidat DOC-24
Ebene: SyRS
Typ: funktional (Zustandsautomat)
Akteur: Administrator (Reportverwaltung)
Vorbedingung: Report ist einer oder mehreren Reportgruppen zugeordnet
Fakt: `ReportDataBL.SetActivity` (zwei Überladungen) verwaltet den Aktivierungszustand eines Reports (`ReportData.State`, `ReportGroupsToReportData.State`) sowohl global als auch pro Gruppe. Beim Deaktivieren werden alle Standard-Zuweisungen entfernt (`ReportDataDefaultBL.RemoveAllDefaults`); wird ein Report in einer Gruppe als einziger aktiver Report aktiviert, wird er automatisch als Standard für Fax, Mail und Druck gesetzt (`SetDefault(..., ReportDefaultType.Fax/Mail/Print)`). `SetReportDeactivated` entfernt zusätzlich beim letzten Report einer Gruppe alle `ReportDataDefault`-Einträge und referenzierende `AccountPrintOption`/`VertragsArt.C2ReportI3D`-Verknüpfungen (`RemoveReportReferences`).
Aussage: Das System soll beim Aktivieren/Deaktivieren eines Reports innerhalb einer Reportgruppe automatisch dessen Standard-Zuordnungen (Druck/Mail/Fax) sowie abhängige Kunden-/Vertragsart-Verknüpfungen konsistent nachführen, insbesondere wenn es sich um den letzten aktiven Report einer Gruppe handelt.
Ergebnis: Widerspruchsfreie Standardreport-Konfiguration ohne verwaiste Referenzen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:303-326 - Begründung: SetActivity(ReportData, bool) mit automatischer Default-Zuweisung.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:507-583 - Begründung: RemoveReportReferences/SetReportDeactivated inkl. Bereinigung AccountPrintOption und VertragsArt.C2ReportI3D.
Prüfidee: Letzten aktiven Report einer Gruppe deaktivieren, prüfen ob zugehörige AccountPrintOption-Einträge sowie ReportDataDefault-Einträge entfernt werden.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat DOC-25
Ebene: SwRS
Typ: funktional (Druckparameter)
Akteur: Sachbearbeiter
Vorbedingung: Report wird gedruckt (nicht nur exportiert)
Fakt: `ReportDataBL.ConvertToSetting` bildet aus `ReportDataSettings`/`ReportDataBinSettings` ein `ReportPrintSettingDTO` mit granularen Druckparametern: Collate (Sortiert drucken), Duplex, Druckername, Farbdruck, Fax-Flag, Papierschacht (`PaperSourceRawKind`), Papierformat (`PaperSizeRawKind`), Kopienanzahl, Querformat, "Druckdialog anzeigen", "Druckereinstellungen verwenden", Skalierung, Seitengrößen-Art.
Aussage: Das System soll je Report und Reportgruppe granulare, persistente Druckeinstellungen (Papierschacht, Papierformat, Duplex, Farbe, Kopienanzahl, Skalierung, Sortierung, Querformat) verwalten können, die beim Drucken automatisch angewendet werden.
Ergebnis: Wiederholbare, konfigurierbare Druckausgabe ohne manuelle Neueinstellung je Druckvorgang.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1055-1075 - Begründung: ConvertToSetting-Mapping aller Druckparameter.
Prüfidee: Druckeinstellungen (z. B. Duplex + Schacht 2) für eine Reportgruppe konfigurieren, Druckvorgang auslösen und physische/simulierte Druckerparameter verifizieren.
Konsolidierungshinweis: -
Status: belegt
---
## Abdeckung
**Gelesen (vollständig oder in relevanten Ausschnitten):**
- `src/backend/Centron.BL/DocuBoard/*.cs` (alle 3 Dateien, kurz — stellte sich als Asset-Management heraus)
- `src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs` (vollständig)
- `src/backend/Centron.Entities/Entities/DocumentationArea/Documentation.cs`, `BaseDocumentation.cs`
- `src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs` (Zeilen 1–1260 vollständig gelesen; Rest ab 1261 — Indizierungsroutinen für .msg/.eml/txt — nicht mehr im Detail gelesen, nur angerissen)
- `src/backend/Centron.Entities/Entities/Administration/FileManagement/Document.cs` (vollständig)
- `src/backend/Centron.BL/WebServices/Administration/FileManagements/DocumentWebServiceBL.cs` (nur DMS-Sync-Ausschnitt, nicht vollständig)
- `src/backend/Centron.BL/Reporting/ReportsBL.cs` (vollständig)
- `src/backend/Centron.BL/ReportEngine/ReportDataBL.cs` (Zeilen 1–1387 von 2127 gelesen; Rest ab 1388 — u. a. weitere Archivierungs-/Hilfsmethoden — NICHT gelesen, Lücke)
- `src/backend/Centron.BL/ReportEngine/PdfExport/PdfExportSettingsBL.cs` (vollständig)
- `src/backend/Centron.BL/ReportEngine/PdfStategy/PdfStrategies.cs` (vollständig)
- `src/backend/Centron.BL/ReportEngine/ReplacementBLs/PdfExportFilenameReplacementBL.cs` (vollständig)
- `src/backend/Centron.BL/ReportEngine/ReportGroupBL.cs` (nur Zeilen 1–150 von vermutlich >700 Zeilen gelesen — GetExportFilename, GetAssetTypeFromGroup)
- `src/backend/Centron.BL/ReportEngine/CustomPdfGenerators/CustomZugferdPdfGenerator.cs` (vollständig, sehr kurz)
- `src/backend/Centron.BL/Core/ReplacementBL.cs` (vollständig)
- `src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs` (vollständig)
- `src/backend/Centron.BL/TextModuleArea/SalutationAndAgreementReplacementBL.cs` (vollständig)
- `src/backend/Centron.Entities/Entities/TextModuleArea/TextModule.cs` (vollständig)
- `Centron.Api.docuFORM/DocuFormRestApiClient.cs`, `DocuFormRestApiConstants.cs`, `IDocuFormApiClient.cs` (vollständig)
**Ausgelassen / nicht vertieft (bekannte Lücken):**
- `src/backend/Centron.BL/ReportEngine/ReportDataDefaultBL.cs`, `ReportDataQueryBL.cs`, `ReportDataQueryTagBL.cs`, `ReportDataBinSettingsBL.cs`, `ReportDataSettingsBL.cs`, `ReportUserBL.cs`, `ReportObjectsBL.cs`, `FastReportHelper.cs`, `HelpdeskHtmlTemplateManager.cs` — nur indirekt über Aufrufe in `ReportDataBL` erschlossen, nicht selbst gelesen.
- `src/backend/Centron.BL/ReportEngine/ImportExport/ReportDataExportBL.cs` / `ReportDataImportBL.cs` — Report-Im-/Export (z. B. für Vorlagenaustausch zwischen Mandanten) komplett ungeprüft; potenziell eigene SyRS-Anforderungen (Im-/Exportformat, Konfliktbehandlung).
- `src/backend/Centron.BL/ReportEngine/PdfStategy/DefaultPdfStrategy.cs`, `PdfCreatorPdfStrategy.cs`, `SevenPdfStrategy.cs`, `CustomPdfPrinterSettings.cs`, `IPdfStrategy.cs` — konkrete Strategie-Implementierungen nicht gelesen, nur über `PdfStrategies.cs` erschlossen.
- `src/backend/Centron.BL/ReportEngine/ReportObjects/Mappings/Kundenanlagen/*.cs` — Mapping-Details zwischen Kundenanlagen/Belegen und Report-Objekten nicht geprüft.
- `src/backend/Centron.BL/WebServices/DocuBoard/*.cs`, `Centron.Entities/Entities/DocuBoard/*.cs`, `Centron.DAO/Mappings/DocuBoard/*.cs` — nur oberflächlich zur Klärung der Namensbedeutung gesichtet (siehe DOC-01), keine tiefen Anforderungen daraus abgeleitet, da fachlich nicht Teil von „Dokumente/Reporting/Textbausteine".
- `src/backend/Centron.Interfaces/ReportEngine/DocuBoardReportEngine/*.cs` (ReportFilter, ReportOverviewFilter, ReportQueryFilter, ParameterValuePairSerializable) — nur Dateiliste gesichtet, Inhalte nicht gelesen; könnten weitere SwRS-Details zu Reportfiltern/-parametern liefern.
- `src/backend/Centron.BL/ReportEngine/Templates/HelpdeskHtmlTemplateManager.cs` + `HtmlHelpdeskTemplate.htm` — HTML-Vorlagenmechanismus für Helpdesk-Reports nicht untersucht (potenziell weiterer „Textbaustein"-artiger Mechanismus außerhalb TextModuleArea).
- `TextModuleType.cs` (Enum-Datei selbst, `src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/TextModuleArea/`) — nur lokalisiert, nicht mit vollständigem Enum-Inhalt gelesen; Katalog in DOC-19 aus den Verwendungsstellen in `TextModuleBL.cs` rekonstruiert, nicht aus der Originaldefinition.
- WPF-Client/UI-Code (XAML) für DocuBoard-Ansicht, Report-Designer-Oberfläche und Textbaustein-Editor wurde in diesem Lauf nicht einbezogen (Vorgabe: primär BL-Schicht) — UI-seitige Validierungen/Fehlermeldungen (z. B. Icon-Widgets, Preview-Dialoge) sind daher nicht erfasst.
- „Icons/Assets als Konfigurationsartefakte" (aus Aufgabenstellung) wurde nur am Rande über `GetImageIndexForDocumentType` (DocumentBL) touchiert; ein dediziertes Icon-/Asset-Verwaltungssystem wurde in den durchsuchten Verzeichnissen nicht gefunden — möglicherweise falsch verortet oder Teil eines anderen Clusters (z. B. Ribbon/UI-Konfiguration).
- `Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs` wurde nur referenziert (Aufrufstelle `IsZugferdEnabled()`), nicht selbst gelesen — Details zu ZUGFeRD-Validierung vermutlich im EDI/Rechnungswesen-Cluster.
- SharedDocument-/C-Sign-Signierprozess (`Centron.BL/Administration/Documents/Dsgvo/*`, SharedDocumentBL) wurde nur als Kontext für Löschsperren (DOC-06) herangezogen, nicht als eigenständiges Thema vertieft (vermutlich eigenes Cluster laut jüngstem Commit „C-Sign (WebOffer & Acceptance)").
@@ -0,0 +1,556 @@
# Cluster: Externe Integrationen & Schnittstellen (EDI, Versand, Zahlungsverkehr, Produktdaten, Webservices)
Rohbefunde für RRE nach ISO/IEC/IEEE 29148:2018. Quellcodebasis: CentronERP (C#/WPF/.NET, MSSQL).
Alle Pfade relativ zu `C:\DEV\MasterArbeit\QuellCode\CentronERP`, sofern nicht anders angegeben.
---
### Kandidat INT-01
Ebene: StRS
Typ: funktional
Akteur: Distributoren/Lieferanten (ALSO, Alltron, Komsa, Herweck, ITScope, EGIS), Einkaufsabteilung
Vorbedingung: Lieferant unterstützt elektronischen Belegaustausch (EDI)
Fakt: Das System automatisiert den Austausch von Bestellungen, Auftragsbestätigungen, Lieferscheinen und Rechnungen mit mehreren Distributoren über unterschiedliche EDI-Formate (OpenTrans 2.1, ALSO, ALSO CH, Herweck, Komsa, Alltron, ZUGFeRD).
Aussage: Das System soll den automatisierten, bidirektionalen elektronischen Belegaustausch (Bestellung, Auftragsbestätigung, Lieferschein, Rechnung) mit angebundenen Distributoren unterstützen, unabhängig vom jeweiligen lieferantenspezifischen Datenformat.
Ergebnis: Reduzierter manueller Erfassungsaufwand im Einkauf, schnellere Verfügbarkeit von Bestell- und Lieferstatus.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:754-829 (DownloadStartAsync) - Begründung: zentrale Einstiegsmethode, dispatcht je Lieferantenkonfiguration.
- [SEKUNDÄR] docs/reference/edi/edi-architecture.md:20,108-122 - Begründung: Architekturübersicht inkl. Formattabelle je Lieferant.
Prüfidee: Prüfen, ob für jeden aktiven Lieferanten-EDI-Vertrag ein vollständiger Order→Response→Delivery→Invoice-Zyklus im System nachvollziehbar ist.
Konsolidierungshinweis: Basis-Requirement für INT-02 bis INT-10.
Status: belegt
---
### Kandidat INT-02
Ebene: SyRS
Typ: nicht-funktional (Performance/Scheduling)
Akteur: System (Hintergrunddienst), Einkaufsabteilung
Vorbedingung: EDI-Lizenz aktiv, Lieferantenkonfigurationen vorhanden
Fakt: Ein ASP.NET-Core-Hintergrunddienst (`EdiDownloadService`) startet 1 Minute nach Systemstart und führt danach alle 30 Minuten automatisch den EDI-Download-Zyklus über alle konfigurierten Lieferanten aus.
Aussage: Das System soll EDI-Dokumente zyklisch (Standardintervall 30 Minuten) ohne Benutzerinteraktion von allen konfigurierten Lieferanten abrufen.
Ergebnis: Zeitnahe, planbare Aktualität der Einkaufsbelege ohne manuellen Anstoß.
Belege:
- [PRIMÄR] src/webservice/Centron.Host/AspNetCore/HostedServices/EdiDownloadService.cs:19-38 - Begründung: `GetExecutionInterval()` liefert fest `TimeSpan.FromMinutes(30)`, Startverzögerung 1 Minute.
Prüfidee: Prüfen, ob Intervall konfigurierbar sein soll (aktuell hartkodiert) und wie mit lang laufenden Zyklen (>30 Min.) umgegangen wird (Überlappung?).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-03
Ebene: SwRS
Typ: Schnittstelle
Akteur: System, Lieferant (FTP/SFTP-Server)
Vorbedingung: Verbindungsdaten (URL, Port, Zugangsdaten, Verzeichnis) je Lieferant konfiguriert
Fakt: `ClientConnectBL` unterstützt drei Übertragungsarten (FTP, FTPS, SFTP); bei FTPS wird `EncryptionMode = Explicit` und `ValidateAnyCertificate = true` gesetzt (Zertifikatsprüfung deaktiviert). SFTP nutzt `Renci.SshNet` mit `OperationTimeout`/`ConnectionInfo.Timeout` von jeweils 120 Minuten.
Aussage: Das System soll den Dateiabruf von Lieferanten wahlweise über FTP, FTPS (explizite TLS-Verschlüsselung) oder SFTP durchführen und dabei konfigurierbare Zugangsdaten je Lieferant verwenden.
Ergebnis: Flexible, lieferantenspezifische Anbindung; ABER Sicherheitsrisiko durch `ValidateAnyCertificate = true` (keine Zertifikatsvalidierung bei FTPS).
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:56-77,90-110,177-228 - Begründung: FTP/FTPS/SFTP-Implementierung inkl. Timeout- und Verschlüsselungseinstellungen.
Prüfidee: Sicherheitsreview: Warum wird bei FTPS jedes Zertifikat akzeptiert? Timeout von 120 Minuten je SFTP-Operation prüfen (ungewöhnlich lang, ggf. Workaround für langsame Lieferanten-Server).
Konsolidierungshinweis: Sicherheitsrelevant, ggf. Querverweis zu SEC-Cluster.
Status: belegt; Workaround (ValidateAnyCertificate=true wirkt wie bewusste Lockerung, Grund im Code nicht dokumentiert) [HYPOTHESE: fehlende Begründung für Zertifikatsausnahme]
---
### Kandidat INT-04
Ebene: SyRS
Typ: Fehlerbehandlung
Akteur: System
Vorbedingung: EDI-Download läuft im Produktivmodus (nicht Testmodus)
Fakt: Dateien, die mehr als 3-mal mit `EDILogState.Exception` fehlgeschlagen sind (ermittelt über SQL-Aggregation auf `EDIManagementLog`), werden bei künftigen Downloadläufen übersprungen ("Blacklist").
Aussage: Das System soll wiederholt fehlschlagende EDI-Dateien (>3 protokollierte Ausnahmen) automatisch von weiteren Verarbeitungsversuchen ausschließen, um Endlosschleifen und Systemlast zu vermeiden.
Ergebnis: Vermeidung wiederholter Fehlversuche; Kehrseite: Datei bleibt dauerhaft unverarbeitet, bis manuell eingegriffen wird.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:786,797,801,894-917 (GetDownloadWithError, badFiles.Where(f => f.ID > 3)) - Begründung: konkrete Schwelle und Blacklist-Filterlogik.
- [SEKUNDÄR] docs/reference/edi/edi-import-rules.md:160-204 - Begründung: dokumentierte Beschreibung des Blacklist-Mechanismus mit SQL-Beispiel.
Prüfidee: Prüfen, ob es eine UI/Funktion gibt, blacklistete Dateien manuell zurückzusetzen (Reprocessing).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-05
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: EDI-Datei erfolgreich heruntergeladen
Fakt: Für Rechnungen, Lieferscheine wird vor der Verarbeitung geprüft, ob `OrigFileName` bereits in `EDIInvoiceHead` bzw. `EDIDeliveryHead` vorhanden ist; nur neue Dateien werden verarbeitet (Duplikatsschutz).
Aussage: Das System soll bereits importierte EDI-Belege anhand des ursprünglichen Dateinamens eindeutig identifizieren und einen Doppelimport verhindern.
Ergebnis: Datenintegrität; keine doppelten Bestellungen/Rechnungen im System.
Belege:
- [SEKUNDÄR] docs/reference/edi/edi-import-rules.md:125-143 - Begründung: dokumentierter Mechanismus inkl. Codebeispiel `UsedFiles(config)`.
- [KONTEXT] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs (Tabellen EDIInvoiceHead/EDIDeliveryHead referenziert in LoadEDIInvoiceHeads/LoadDeliveryHeads, z.B. Zeilen 376-476) - Begründung: Zugriff auf dieselben Kopftabellen bestätigt Struktur.
Prüfidee: Verifizieren, ob Duplikatsprüfung auch bei Dateinamensänderung durch Lieferanten (z.B. Zeitstempel im Namen) robust bleibt.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-06
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Heruntergeladene Datei hat Endung `.zip`
Fakt: ZIP-Dateien werden serverseitig entpackt (`ZipExtract`), einzelne Inhalte werden als separate `EDIDistriFile`-Objekte weiterverarbeitet; Nicht-ZIP-Dateien werden direkt als Stream übernommen.
Aussage: Das System soll komprimierte EDI-Sammeldateien (ZIP) automatisch entpacken und deren Einzeldokumente wie regulär empfangene Dateien verarbeiten.
Ergebnis: Unterstützung lieferantenseitiger Batch-Zustellung ohne Mehraufwand für den Anwender.
Belege:
- [SEKUNDÄR] docs/reference/edi/edi-import-rules.md:67-91 - Begründung: dokumentierter Code-Ausschnitt zur ZIP-Verarbeitung.
Prüfidee: Prüfen, wie mit fehlerhaften/passwortgeschützten ZIP-Dateien umgegangen wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-07
Ebene: SyRS
Typ: funktional
Akteur: Einkaufsabteilung, System
Vorbedingung: ALSO-Auftragsbestätigung (OrderResponse) wurde importiert
Fakt: Beim Einlesen der ALSO-Auftragsbestätigung wird der Kopfsatz mit `NeedsUserValidation = true` markiert; ähnliche States (`EDIHeadState.Open/Ignored/Assigned`) steuern den Workflow bis zur manuellen Zuordnung zur c-entron-Bestellung.
Aussage: Das System soll importierte Auftragsbestätigungen, Lieferscheine und Rechnungen standardmäßig als prüfpflichtig kennzeichnen und erst nach manueller/regelbasierter Zuordnung zum ursprünglichen Bestellvorgang als abgeschlossen betrachten.
Ergebnis: Kontrollierte Übernahme externer Daten, Vermeidung automatischer Fehlbuchungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.Also.cs:38 (head.NeedsUserValidation = true) - Begründung: konkrete Kennzeichnung.
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:504-578 (SaveReceiptItemAssignments), 607-648 (UpdateEDIReceiptHead) - Begründung: Workflow zur Zuordnung/Freigabe von EDI-Positionen zu Bestellpositionen.
Prüfidee: Prüfen, ob alle Lieferanten-Handler `NeedsUserValidation` konsistent setzen oder ob es Ausnahmen (Vollautomatik) gibt.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-08
Ebene: StRS
Typ: funktional (Lizenzsteuerung)
Akteur: Vertrieb/Lizenzierung, Einkaufsabteilung
Vorbedingung: Kundenvertrag mit entsprechendem Lizenzmodul
Fakt: EDI-Funktionalität ist über drei getrennte Lizenz-GUIDs steuerbar: `EDI_General` (klassische Lieferanten-EDI), `EDI_ITScope`, `EDI_EGIS`. Ohne aktive Lizenz wird der jeweilige Verarbeitungszweig übersprungen.
Aussage: Das System soll die Nutzung der EDI-Anbindung (klassisches EDI, ITScope-Marktplatz, EGIS) getrennt lizenzierbar und pro Mandant aktivierbar/deaktivierbar machen.
Ergebnis: Differenzierte Vermarktung/Paketierung der Integrationsfunktionen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:777,978,1003,1115 - Begründung: `LicenseManager.Instance.HasLicense(LicenseGuids.EDI_*)`-Prüfungen an mehreren Verzweigungspunkten.
Prüfidee: Prüfen, ob in einer SaaS-Neuimplementierung ein äquivalentes Feature-Flag-/Tarifmodell für Integrationen vorgesehen werden soll.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-09
Ebene: SwRS
Typ: Sicherheit
Akteur: System, Administrator
Vorbedingung: Lieferanten-EDI-Konfiguration in der Datenbank gespeichert
Fakt: Zugangspasswörter der `SupplierEdiConfigurations` werden vor der Speicherung verschlüsselt (`AESCryptoLogic().DecryptText(...)` beim Laden) und beim Laden entschlüsselt.
Aussage: Das System soll Zugangsdaten (Passwörter) für externe EDI-/Lieferantenschnittstellen ausschließlich verschlüsselt in der Datenbank persistieren.
Ergebnis: Schutz sensibler Zugangsdaten bei Datenbankzugriff/-diebstahl.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:716-725 (GetSupplierEdiConfigurations, AESCryptoLogic) - Begründung: explizite Entschlüsselung beim Laden impliziert AES-Verschlüsselung bei Speicherung.
Prüfidee: Schlüsselverwaltung der AES-Verschlüsselung prüfen (Ort, Rotation) - im gesichteten Code nicht ersichtlich.
Konsolidierungshinweis: Sicherheitsrelevant, Querverweis SEC-Cluster.
Status: belegt; Detail zum Schlüsselmanagement [HYPOTHESE: Speicherort/Rotation des AES-Schlüssels nicht im gesichteten Code ersichtlich]
---
### Kandidat INT-10
Ebene: SyRS
Typ: Fehlerbehandlung
Akteur: System
Vorbedingung: ITScope-Bestellung wurde übertragen, aber Antwort/Status fehlerhaft
Fakt: Fehlerhafte ITScope-Deals (`ITScopeEDILog.State == LogKind.Error`) werden erneut verarbeitet, wenn `AttemtingNumber < 4` und die letzte Fehlermeldung älter als 12 Stunden ist (`CheckDealsWithError`).
Aussage: Das System soll fehlgeschlagene ITScope-Bestellübertragungen automatisiert bis zu 4 Mal erneut versuchen, mit einer Mindestwartezeit von 12 Stunden zwischen den Versuchen.
Ergebnis: Automatische Fehlertoleranz bei transienten Störungen des Marktplatz-Partners, ohne Endlos-Retry.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:920-932 (CheckDealsWithError) - Begründung: konkrete Bedingungen (AttemtingNumber<4, Date<Now.AddHours(-12)).
Prüfidee: Prüfen, ob 12h/4-Versuche konfigurierbar sein sollen oder als fixer Wert übernommen werden.
Konsolidierungshinweis: Vergleichbares Retry-Muster wie INT-04 (Blacklist), aber mit Zeit- statt reiner Zählschwelle.
Status: belegt
---
### Kandidat INT-11
Ebene: SwRS
Typ: Schnittstelle
Akteur: ITScope (Marktplatz-Distributor)
Vorbedingung: Gültiger ITScope API-Key und Benutzer-E-Mail konfiguriert
Fakt: Die Authentifizierung gegenüber der ITScope-API erfolgt per HTTP Basic Auth, wobei der Benutzername als `"{fest_kodiertes_Präfix}${userMail}"` zusammengesetzt wird (Präfix `"fjku6Zi0l8Dq"`); dieses Präfix ist sowohl in `ClientConnectBL.cs` als auch als Default-`accountId` in `ITscopeApi`-Konstruktor hartkodiert.
Aussage: Das System soll sich gegenüber der ITScope-API mittels HTTP-Basic-Authentifizierung (kombiniert aus Account-Kennung, Benutzer-E-Mail und API-Key) authentifizieren.
Ergebnis: Funktionierende Anbindung an ITScope; Risiko: fest im Quellcode hinterlegte Account-Kennung als Teil des Credentials.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:374-402 (ItScopeUploadHttpAsync, Zeile 384 "fjku6Zi0l8Dq") - Begründung: konkreter Header-Aufbau.
- [PRIMÄR] src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs:23-34 - Begründung: identisches Präfix als Default-Parameter im Konstruktor.
Prüfidee: Klären, ob "fjku6Zi0l8Dq" ein öffentlicher c-entron-Partner-Account bei ITScope oder ein sensibles Secret ist (Security-Review empfohlen).
Konsolidierungshinweis: Sicherheitsrelevant, Querverweis SEC-Cluster.
Status: belegt; Sicherheitsrisiko-Hinweis (hartkodierte Credential-Komponente im Quellcode)
---
### Kandidat INT-12
Ebene: SwRS
Typ: Schnittstelle
Akteur: EGIS (E-Invoicing-/Bestellplattform)
Vorbedingung: EGIS-Lizenz aktiv, Benutzerdaten konfiguriert
Fakt: Die Kommunikation mit EGIS erfolgt über synchrone HTTP-POST-Requests mit XML-Payload (`EgisSendHttpAsync`); die Antwort wird auf ein `TransactionHeader.Exception`-Element geprüft, um fachliche Fehler (nicht nur HTTP-Fehler) zu erkennen. Es existiert ein separater Test-Endpunkt (`EgisApi.CreateTest()`) mit festen Testzugangsdaten.
Aussage: Das System soll bei der EGIS-Anbindung sowohl technische (HTTP-Statuscode) als auch fachliche Fehler (EGIS-`TransactionHeader.Exception`) erkennen und dem Anwender differenziert melden.
Ergebnis: Klare Fehlerdiagnose bei EGIS-Kommunikation; Testmodus ohne Produktivzugangsdaten möglich.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:413-435,492-524 - Begründung: Prüfung auf `response.TransactionHeader.Exception`.
- [PRIMÄR] src/apis/Centron.APIs.EgisDataAccess/EgisApi.cs:32-54 - Begründung: Create()/CreateTest() mit getrennter Test-URL/-Zugangsdaten.
Prüfidee: Prüfen, ob EGIS-Fehlercodes vollständig auf nutzerverständliche Meldungen gemappt werden.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-13
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Rechnung als ZUGFeRD-PDF (PDF/A-3 mit eingebetteter XML) empfangen
Fakt: `ZUGFeRD_BL.ReadInvoice` extrahiert eingebettete XML-Anhänge (`CrossIndustryInvoice`) aus PDF-Dateien mittels `DevExpress.XtraPdf.PdfDocumentProcessor` und verarbeitet nur Anhänge mit Root-Element `CrossIndustryInvoice`.
Aussage: Das System soll hybride ZUGFeRD-Rechnungen (PDF mit eingebetteter strukturierter XML-Rechnung) automatisiert erkennen, die XML-Daten extrahieren und strukturiert weiterverarbeiten.
Ergebnis: Automatisierte Verarbeitung von E-Rechnungen im ZUGFeRD-Standard ohne manuelle Übertragung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/Zugferd/ZUGFeRD_BL.cs:38-59 - Begründung: konkrete Extraktion aus PDF-Dateianhang.
Prüfidee: Prüfen, welche ZUGFeRD-Profile (BASIC, COMFORT, EXTENDED) unterstützt werden und wie mit reinen PDF-Rechnungen ohne XML umgegangen wird (Fallback laut edi-architecture.md: `IsZUGFeRD = true`-Markierung).
Konsolidierungshinweis: Ergänzt INT-01 (Rechnungsformate).
Status: belegt
---
### Kandidat INT-14
Ebene: SwRS
Typ: Daten
Akteur: Rechnungsempfänger (Österreich, öffentliche Auftraggeber)
Vorbedingung: Ausgangsrechnung an österreichischen E-Rechnungs-Empfänger
Fakt: `EbInterfaceLogic.GenerateFile` erzeugt eine XML-Rechnung nach dem Standard ebInterface 4.3 (`http://www.ebinterface.at/schema/4p3/`) inkl. Rechnungsnummer, Steuer-, Liefer- und Zahlungsdaten.
Aussage: Das System soll ausgehende Rechnungen wahlweise im österreichischen ebInterface-4.3-Format als strukturierte XML-Datei erzeugen können.
Ergebnis: Compliance mit österreichischen E-Rechnungsanforderungen (z.B. an Behörden).
Belege:
- [PRIMÄR] src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs:20-77 - Begründung: Namespace, Struktur und Pflichtfelder des generierten XML.
Prüfidee: Prüfen, ob Validierung gegen offizielles ebInterface-XSD-Schema erfolgt und ob Versionierung (z.B. 5.0) geplant ist.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-15
Ebene: SyRS
Typ: funktional
Akteur: Finanzbuchhaltung, Bank (SEPA-Zahlungsverkehr)
Vorbedingung: Offene Lastschrift-/Überweisungsbelege vorhanden, Bankverbindung des Mandanten konfiguriert
Fakt: `PaymentTransactionBL` unterstützt fünf SEPA-Exportformat-Varianten (PAIN.008.001.01 STUZZA, PAIN.008.003.02, PAIN.008.001.02, PAIN.008.001.02 GBIC3, PAIN.008.001.08 GBIC4) und wählt die Bankverbindung des Mandanten aus bis zu vier hinterlegten Bankkonten (`PaymentTransactionUseMandatorBankForExport`).
Aussage: Das System soll Zahlungsdateien im SEPA-Lastschrift-/Überweisungsformat (mehrere PAIN.008-Varianten inkl. länderspezifischer Ausprägungen) für den Export an das Bankprogramm erzeugen können.
Ergebnis: Automatisierter Zahlungsverkehr ohne manuelle Bankerfassung, Unterstützung unterschiedlicher Bank-/Länderanforderungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/PaymentTransactions/PaymentTransactionBL.cs:56-66 (GetInterfaceList),132-196 (ExportInvoices),146-166 (Bankauswahl 1-4) - Begründung: konkrete Formatliste und Bankauswahl-Logik.
Prüfidee: Prüfen, welche SEPA-Version für Neukunden Standard sein soll und ob Formate wie PAIN.001 (Überweisung) getrennt abgedeckt sind.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-16
Ebene: SyRS
Typ: funktional (Geschäftsregel)
Akteur: Finanzbuchhaltung
Vorbedingung: SEPA-Export erfolgreich durchgeführt
Fakt: Nach erfolgreichem SEPA-Export werden Rechnungen als exportiert markiert (`SetInvoiceAsExported`), optional automatisch als bezahlt geschlossen (Einstellung `PaymentTransactionCloseInvoiceAfterExport`) und ein `IncomingPaymentLog`-Eintrag mit Bank-/Betragsdaten erzeugt; ein Rücknahme-Workflow (`ResetInvoiceExportedFlag`) macht den Export rückgängig, sofern noch kein Zahlungseingang verbucht wurde.
Aussage: Das System soll den Status "SEPA-exportiert" von Rechnungen nachvollziehbar protokollieren, optional automatisch abschließen und über einen kontrollierten Workflow wieder rücksetzbar machen.
Ergebnis: Nachvollziehbarkeit und Korrigierbarkeit des Zahlungsverkehrsprozesses.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/PaymentTransactions/PaymentTransactionBL.cs:233-288 (InvoiceExportDone), 296-345 (ResetInvoiceExportedFlag) - Begründung: konkrete Statuslogik und Protokollierung.
Prüfidee: Prüfen, ob Rücknahme nach bereits verbuchtem Zahlungseingang zulässig sein soll (Code bricht dies über `PaymentTransactionReturnedEmployeeI3D > 0` ab).
Konsolidierungshinweis: Ergänzt INT-15.
Status: belegt
---
### Kandidat INT-17
Ebene: SyRS
Typ: Schnittstelle
Akteur: Bank / Kontoinhaber (Online-Banking via PSD2)
Vorbedingung: finAPI-Zugang konfiguriert (Sandbox oder Live)
Fakt: `FinApiClient` bindet den Multibanking-Provider finAPI an: getrennte Sandbox-/Live-URLs, Access-Token mit Ablaufprüfung (`IsExpired()`) vor jedem Aufruf, WebForm-basierter Verbindungsaufbau (`ImportNewBankConnection`) mit URL-Redirect für die PSD2-Einwilligung des Endkunden, sowie asynchrone Status-Abfrage über `FinApiTask`/`WebFormInfo`.
Aussage: Das System soll Bankkonten und Kontoumsätze über den PSD2-konformen Multibanking-Dienstleister finAPI anbinden, inkl. nutzergeführtem Authentifizierungs-Flow (Web-Form) und tokenbasierter Sitzungsverwaltung.
Ergebnis: Automatisierter Kontoauszugs-/Umsatzabgleich ohne manuellen Excel-/MT940-Import.
Belege:
- [PRIMÄR] src/apis/Centron.APIs.FinAPI/FinApiClient.cs:27-32 (Sandbox/Live-Umschaltung), 149-172 (ImportNewBankConnection, WebForm-Redirect), 192-224 (Task-/WebForm-Statusabfrage), 49-66 (Access-Token-Prüfung) - Begründung: kompletter Authentifizierungs- und Verbindungs-Flow.
Prüfidee: Klären, ob Refresh-Token-Handling existiert oder der Nutzer bei Ablauf erneut den WebForm-Flow durchlaufen muss (im gesichteten Code kein Refresh-Mechanismus erkennbar).
Konsolidierungshinweis: -
Status: belegt; Refresh-Mechanismus [HYPOTHESE: kein Token-Refresh im gesichteten Code, ggf. an anderer Stelle implementiert]
---
### Kandidat INT-18
Ebene: SwRS
Typ: nicht-funktional (Performance)
Akteur: System
Vorbedingung: Kontoumsätze werden über finAPI geladen
Fakt: `GetAccountTransactions` lädt Kontoumsätze seitenweise mit fester Seitengröße von 500 Datensätzen (`TransactionsPerPage = 500`) und iteriert automatisch über alle vom Server gemeldeten Seiten (`Paging.PageCount`); der Standard-Abfragezeitraum für Einzelabfragen beträgt 12 Monate rückwirkend.
Aussage: Das System soll Kontoumsätze in Seiten von maximal 500 Datensätzen von finAPI abrufen und automatisch alle Seiten konsolidieren, um auch bei hohem Buchungsvolumen vollständige Ergebnisse zu liefern.
Ergebnis: Skalierbarkeit bei großen Umsatzmengen ohne Timeouts einzelner Anfragen.
Belege:
- [PRIMÄR] src/apis/Centron.APIs.FinAPI/FinApiClient.cs:266-292,332-367 - Begründung: konkrete Paginierungslogik und Konstante.
Prüfidee: Prüfen, ob bei sehr vielen Seiten ein Performance-/Timeout-Risiko besteht (keine Parallelisierung, sequentielle Abfrage).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-19
Ebene: SwRS
Typ: Schnittstelle
Akteur: Versanddienstleister GLS
Vorbedingung: GLS-Zugangsdaten (Benutzer/Passwort) hinterlegt
Fakt: `CentronGlsLogic.UploadShipment` sendet Sendungsdaten als JSON (DataContractJsonSerializer) per POST an `https://api.gls-group.eu/public/v1/shipments` (Produktiv) bzw. `https://api-qs.gls-group.eu/...` (Test); im Testmodus werden feste Zugangsdaten (`webapi`/`webapi`) verwendet. Ein Autorisierungsheader mit fest hinterlegtem Basic-Auth-Token (`Authorization: Basic dVUtG3lKSXJnKXRpVzertzpsRWluZ9NodA==`) wird zusätzlich zum dynamischen Credential-Objekt gesetzt.
Aussage: Das System soll GLS-Paketsendungen inkl. Versandlabel über die GLS-REST-API (JSON, Basic-Auth) erzeugen können, mit getrenntem Test- und Produktivendpunkt.
Ergebnis: Automatisierte Label-/Trackingnummer-Erzeugung für GLS-Sendungen aus dem ERP heraus.
Belege:
- [PRIMÄR] src/apis/Centron.Api.Gls/CentronGlsConsts.cs:5-17 - Begründung: Basis-URLs, Testzugangsdaten und hartkodierter Authorization-Header.
- [PRIMÄR] src/apis/Centron.Api.Gls/CentronGlsLogic.cs:93-151 (GetResponse) - Begründung: Aufbau des Requests inkl. Header/Credentials.
Prüfidee: Sicherheitsreview: Zweck des zusätzlichen fest hinterlegten `Authorization`-Headers klären (wirkt wie totes/veraltetes Legacy-Credential neben dynamischer `NetworkCredential`) - Secret-Leak-Risiko im Quellcode.
Konsolidierungshinweis: Sicherheitsrelevant, Querverweis SEC-Cluster.
Status: belegt; Sicherheitsrisiko-Hinweis (hartkodiertes Basic-Auth-Token im Quellcode)
---
### Kandidat INT-20
Ebene: SwRS
Typ: funktional (Geschäftsregel)
Akteur: Versandabteilung
Vorbedingung: Sendungsauftrag an GLS wird erstellt
Fakt: `DoValidateShipment` erzwingt vor dem Versand: SenderID und Sendungsdatum müssen gesetzt sein, maximal 50 Referenzen und maximal 30 Pakete pro Sendung sind zulässig (harte GLS-API-Limits, clientseitig vorab geprüft).
Aussage: Das System soll GLS-Sendungsaufträge vor der Übermittlung clientseitig auf Vollständigkeit und auf die GLS-Limits (max. 50 Referenzen, max. 30 Pakete je Sendung) validieren und bei Verstoß eine verständliche Fehlermeldung anzeigen.
Ergebnis: Vermeidung von serverseitig abgelehnten Versandaufträgen, schnelleres Feedback an den Benutzer.
Belege:
- [PRIMÄR] src/apis/Centron.Api.Gls/CentronGlsLogic.cs:60-91 (DoValidateShipment) - Begründung: konkrete Grenzwerte und Fehlermeldungstexte.
Prüfidee: Prüfen, ob diese Limits bei GLS-API-Änderungen zentral pflegbar sind (aktuell als Magic Numbers im Code).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat INT-21
Ebene: SwRS
Typ: Schnittstelle
Akteur: Versanddienstleister (Multi-Carrier über Shipcloud)
Vorbedingung: Shipcloud-API-Key konfiguriert
Fakt: `CentronShipcloudLogic` bindet den Multi-Carrier-Versanddienstleister Shipcloud über REST/JSON an: Basic-Auth mit Base64-kodiertem API-Key, `GetCarriersAsync` liefert verfügbare Frachtführer, `CreateShipmentAsync` erstellt Sendungen und liefert Tracking-Nummer, Tracking-URL, Label-URL und Preis zurück.
Aussage: Das System soll über Shipcloud als Aggregator mehrere Versanddienstleister (Carrier) einheitlich ansprechen und Sendungen inkl. Label, Tracking-Link und Versandkosten erzeugen können.
Ergebnis: Carrier-Unabhängigkeit; ein Integrationspunkt statt vieler direkter Carrier-Anbindungen.
Belege:
- [PRIMÄR] src/apis/Centron.Api.Shipcloud/CentronShipcloudLogic.cs:14-28 (Basic-Auth-Aufbau), 30-64 (GetCarriersAsync), 66-106 (CreateShipmentAsync) - Begründung: vollständiger Request-/Response-Zyklus mit Rückgabefeldern.
Prüfidee: Prüfen, ob Shipcloud GLS als eigene Direktanbindung (INT-19) ablöst oder parallel für andere Carrier eingesetzt wird (Konsolidierungsbedarf für Zielarchitektur).
Konsolidierungshinweis: Fachlich verwandt mit INT-19/INT-20 (Versand); ggf. für SaaS-Neuimplementierung auf einen einheitlichen Versand-Adapter (Shipcloud) konsolidieren.
Status: belegt
---
### Kandidat INT-22
Ebene: SwRS
Typ: Schnittstelle
Akteur: Produktdatenanbieter COP
Vorbedingung: COP-Zugangsdaten (Adresse, Benutzer, Passwort) konfiguriert
Fakt: `CopApi` kommuniziert klassisch SOAP-basiert (SOAPAction-Header, XML-Envelope, `urn:jsframework.dev`-Namespace) mit dem COP-Produktdatendienst; unterstützt Produktsuche per ID/EAN/Freitext, verwandte Produkte und Lieferantenzuordnung je Artikel.
Aussage: Das System soll Produktstammdaten (inkl. Beschreibungen, verwandte Artikel, Lieferantenzuordnungen) über die SOAP-Schnittstelle des Anbieters COP synchronisieren können.
Ergebnis: Reduzierter manueller Pflegeaufwand für Artikelstammdaten.
Belege:
- [PRIMÄR] src/apis/Centron.APIs.CopDataAccess/CopApi.cs:32-81,109-138,170-200 - Begründung: konkrete SOAP-Actions (getArticles, getArticlesSupplier, getArticlesRelated) und Transportmechanik.
Prüfidee: Prüfen, in welchem Turnus/Trigger die COP-Synchronisation angestoßen wird (im gesichteten Ausschnitt nicht erkennbar) [HYPOTHESE: Aufrufkontext/Turnus nicht ermittelt].
Konsolidierungshinweis: Vergleichbares Muster wie INT-23/INT-24 (weitere Produktdatenquellen).
Status: belegt; Trigger/Turnus [HYPOTHESE: fehlende Information zum Aufrufzeitpunkt]
---
### Kandidat INT-23
Ebene: SwRS
Typ: Schnittstelle
Akteur: Produktdatenanbieter ITScope
Vorbedingung: ITScope-API-Key konfiguriert
Fakt: `ITscopeApi` fragt neben Produktdaten (`GetProductByIdAsync`) auch das API-Key-Kontingent ab (`GetApiKeyQuotaAsync` gegen `.../info/quota`), was auf ein Rate-Limiting-Modell seitens ITScope hindeutet.
Aussage: Das System soll das verfügbare API-Kontingent (Quota) des ITScope-Zugangs abfragen können, um Ratenbegrenzungen des Anbieters zu berücksichtigen.
Ergebnis: Vermeidung von Kontingentüberschreitungen bei der Marktplatz-/Produktdatenanbindung.
Belege:
- [PRIMÄR] src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs:36-49 - Begründung: dedizierter Quota-Endpunkt.
Prüfidee: Prüfen, ob die Quota-Information im System aktiv ausgewertet wird (z.B. Drosselung) oder nur informativ abrufbar ist [HYPOTHESE: Verwendung der Quota-Antwort im UI/Batch nicht geprüft].
Konsolidierungshinweis: Ergänzt INT-11 (ITScope-Authentifizierung).
Status: belegt
---
### Kandidat INT-24
Ebene: SwRS
Typ: Schnittstelle
Akteur: Produktdatenanbieter Icecat
Vorbedingung: Icecat-Zugangsdaten (Benutzer/Passwort) konfiguriert
Fakt: `IcecatApi` fragt Produktdaten über eine einfache GET-Schnittstelle mit Query-Parametern (`prod_id`/`ean_upc`, `vendor`, `lang`) ab, authentifiziert per HTTP Basic Auth (ISO-8859-1-kodiert).
Aussage: Das System soll Produktdaten (inkl. mehrsprachiger Inhalte) über die Icecat-Produktdatenbank per EAN oder Hersteller-Produkt-ID abrufen können.
Ergebnis: Anreicherung von Artikeldaten (Beschreibungen, Bilder) ohne manuelle Recherche.
Belege:
- [PRIMÄR] src/apis/Centron.APIs.IcecatDataAccess/IcecatApi.cs:14-33 - Begründung: konkreter Request-Aufbau inkl. Sprachparameter.
Prüfidee: Prüfen, welche Sprachen/Länder unterstützt werden und ob Bilddaten mit heruntergeladen werden.
Konsolidierungshinweis: Vergleichbares Muster wie INT-22/INT-23 (weitere Produktdatenquellen) - für Zielarchitektur ggf. auf einheitlichen Produktdaten-Adapter konsolidieren.
Status: belegt
---
### Kandidat INT-25
Ebene: SwRS
Typ: Schnittstelle
Akteur: Distributor Komsa
Vorbedingung: Komsa-Zugangsdaten konfiguriert
Fakt: `KomsaArticleCheckAsync` fragt Produktverfügbarkeit/-preis live per HTTP GET gegen `https://partner.komsa.de/api/v1/product/{article}?customerId=...&amount=...` ab, authentifiziert per Basic Auth, wobei das Passwort-Feld aus `config.Additional` (nicht dem regulären Passwortfeld) stammt.
Aussage: Das System soll aktuelle Verfügbarkeit und Preise einzelner Artikel live beim Distributor Komsa abfragen können (Echtzeit-Verfügbarkeitsprüfung zusätzlich zum asynchronen EDI-Austausch).
Ergebnis: Aktuellere Verfügbarkeits-/Preisinformation im Bestellprozess als über tägliche/EDI-Stammdaten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:563-579 - Begründung: konkreter Endpunkt und Authentifizierungsaufbau.
Prüfidee: Klären, warum das Passwort im Feld `Additional` statt im regulären Passwortfeld der Konfiguration abgelegt ist (Konsistenzproblem im Datenmodell) [HYPOTHESE: Grund für Feldwahl nicht im Code ersichtlich].
Konsolidierungshinweis: -
Status: belegt; Datenmodell-Inkonsistenz [HYPOTHESE: unklare Feldsemantik "Additional" als Passwortfeld]
---
### Kandidat INT-26
Ebene: StRS
Typ: Schnittstelle
Akteur: Partner-/Drittsysteme, externe Anwendungen
Vorbedingung: Partnersystem verfügt über gültiges Ticket/Zugangsdaten
Fakt: C-ENTRON stellt selbst eine REST-artige Webservice-Schicht bereit (`CentronRestService`/`ICentronRestService`), über die externe Anwendungen per `Request<T>`/`Response<T>`-Konvention (ausschließlich POST, `[Authenticate]`-Attribut, ticketbasierte Anmeldung via `GetLoggedInUserByTicket`) auf Geschäftsobjekte zugreifen können; laut Entwicklerdokumentation auch per WSDL-Service-Reference nutzbar.
Aussage: Das System soll externen Anwendungen/Partnersystemen eine dokumentierte, authentifizierte Webservice-Schnittstelle (Request/Response-Kontrakt) zum lesenden und schreibenden Zugriff auf Geschäftsobjekte bereitstellen.
Ergebnis: C-ENTRON fungiert selbst als Integrationsplattform für Drittsysteme (nicht nur Konsument externer APIs).
Belege:
- [PRIMÄR] docs/guides/services/add-webservice-methods.md:32-66 - Begründung: dokumentierter, im Code verbindlich vorgeschriebener Webservice-Kontrakt (Namenskonvention, Attribute, Signatur).
Prüfidee: Prüfen, welche Authentifizierungsmechanismen (Ticket-Lebensdauer, Rotation) hinter `GetLoggedInUserByTicket` stehen und ob dies für eine SaaS-Neuimplementierung durch OAuth2/OIDC ersetzt werden soll.
Konsolidierungshinweis: Zentrale Anforderung für die Zielarchitektur (API-first für SaaS); Querverweis zu allen anderen INT-Kandidaten als "ausgehende" vs. diese als "eingehende" Integration.
Status: belegt; Authentifizierungsdetails [HYPOTHESE: Ticket-Mechanismus (Lebensdauer, Erneuerung) nicht im gesichteten Code verifiziert]
---
### Kandidat INT-27
Ebene: SyRS
Typ: nicht-funktional (Betrieb/Verfügbarkeit)
Akteur: Systemadministrator
Vorbedingung: Webservice wird als eigenständiger Dienst betrieben (Windows oder Linux)
Fakt: Der c-entron-Webservice läuft auf .NET 8, unterstützt HTTPS über ein PFX-Zertifikat (`WebServiceCertificateFilePath`/`WebServiceCertificatePassword` in `WebServiceConfig.xml`) und wird unter Linux typischerweise per systemd mit automatischem Neustart (`Restart=always`, `RestartSec=5`) betrieben.
Aussage: Das System soll die Webservice-Schnittstelle als eigenständigen, TLS-gesicherten Dienst mit automatischer Wiederherstellung nach Absturz bereitstellen und sowohl unter Windows als auch Linux betreibbar sein.
Ergebnis: Hohe Verfügbarkeit der Integrationsschicht auch bei transienten Fehlern/Abstürzen.
Belege:
- [SEKUNDÄR] docs/guides/services/web-service-on-linux.md:15-16,39-58,66-80 - Begründung: dokumentierte Betriebsanleitung mit konkreten Konfigurationswerten.
Prüfidee: Prüfen, ob es einen äquivalenten Health-Check/Watchdog unter Windows gibt (dokumentiert nur für Linux/systemd) [HYPOTHESE: Windows-Pendant nicht dokumentiert].
Konsolidierungshinweis: Ergänzt INT-26 (Webservice als Integrationsplattform) um Betriebssicht.
Status: belegt; Windows-Watchdog [HYPOTHESE: kein Beleg für äquivalenten Mechanismus unter Windows gefunden]
---
### Kandidat INT-28
Ebene: SwRS
Typ: Schnittstelle
Akteur: Drittsysteme (generische Webhook-Konsumenten, z.B. Ticket-/Automatisierungssysteme)
Vorbedingung: Ziel-URL für Webhook konfiguriert
Fakt: `WebHookClient` ist eine wiederverwendbare, generische Komponente für ausgehende HTTP-POST-Webhooks mit JSON-Payload, konfigurierbarem Timeout (Default 30 Sekunden) und einheitlicher Fehlerbehandlung (inkl. `TaskCanceledException` als Timeout-Fall).
Aussage: Das System soll ausgehende Ereignisbenachrichtigungen (Webhooks) an konfigurierbare externe Endpunkte mit definiertem Timeout und strukturierter Fehlerrückmeldung senden können.
Ergebnis: Generisches Integrationsmuster für Push-basierte Anbindung an beliebige Drittsysteme (z.B. DocBee-Ticketintegration).
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/Connectors/WebHookClient.cs:15-37,47-106 - Begründung: konkrete Timeout-Konfiguration und Fehlerbehandlungspfade.
Prüfidee: Prüfen, ob Retry-Logik für fehlgeschlagene Webhook-Zustellungen existiert (im gesichteten Code nicht erkennbar - einmaliger Versuch pro Aufruf).
Konsolidierungshinweis: -
Status: belegt; Retry-Verhalten [HYPOTHESE: kein Wiederholungsmechanismus im gesichteten Code erkennbar]
---
### Kandidat INT-29
Ebene: SyRS
Typ: Fehlerbehandlung
Akteur: System, Einkaufsabteilung
Vorbedingung: EDI-Verarbeitung eines Dokuments schlägt fehl
Fakt: Fehler werden über `EDILogBL` strukturiert protokolliert (u.a. `EDILogState.DownloadOK/DownloadError/Exception/TestException`), inkl. Dateiname, Kommentar und Ausnahmedetails; die Verarbeitung einzelner Konfigurationen erfolgt in try/catch-Blöcken je Lieferant, sodass ein Fehler bei einem Lieferanten die Verarbeitung der übrigen nicht blockiert.
Aussage: Das System soll Fehler bei der EDI-Verarbeitung pro Lieferant/Dokument isoliert protokollieren, sodass Störungen bei einzelnen Partnern die automatisierte Verarbeitung der übrigen Partner nicht beeinträchtigen.
Ergebnis: Robustheit des Gesamtprozesses gegenüber Einzelausfällen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs:778-810 (Schleife über Konfigurationen mit try/catch je Konfiguration, Logging via `_eDILogBL.WriteEdiDownloadLog`) - Begründung: konkrete Fehlerisolation je Lieferantenkonfiguration.
- [SEKUNDÄR] docs/reference/edi/edi-architecture.md:239-266 - Begründung: dokumentiertes Logging-Framework und Fehlerstrategien.
Prüfidee: Prüfen, ob es eine Eskalation/Benachrichtigung (z.B. E-Mail) an Administratoren bei wiederholten Fehlern gibt.
Konsolidierungshinweis: Grundlage für INT-04/INT-10 (konkrete Retry-/Blacklist-Ausprägungen).
Status: belegt
---
### Kandidat INT-30
Ebene: SwRS
Typ: Schnittstelle
Akteur: System, Distributor (Legacy-XML-Hub, z.B. "continue.de")
Vorbedingung: Lieferant erwartet HTTP-Upload statt FTP
Fakt: `UploadHttpAsync` unterscheidet fallweise die Authentifizierungsmethode: für den Host `xml-hub.continue.de` wird Basic Auth manuell mit ISO-8859-1-Kodierung gesetzt, für alle anderen Hosts `NetworkCredential`; zusätzlich wird ein fest hinterlegter, veralteter User-Agent-String (`"Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0)"`) mit Verweis auf ein Ticket (137585) gesendet, vermutlich um Kompatibilitätsprobleme beim Empfänger zu umgehen.
Aussage: Das System soll für HTTP-basierte Lieferanten-Uploads hostspezifische Authentifizierungs- und Kompatibilitätsanpassungen (z.B. User-Agent-Vortäuschung) unterstützen, wenn Standardverhalten vom Empfängersystem abgelehnt wird.
Ergebnis: Funktionierende Anbindung auch an technisch eingeschränkte/ältere Lieferantenschnittstellen; Kehrseite: Host-spezifische Sonderfälle im generischen Code erschweren Wartbarkeit.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs:305-361 (insb. Zeilen 313-326) - Begründung: konkrete Host-Sonderbehandlung und historischer Ticketverweis im Kommentar.
Prüfidee: Klären, ob diese Sonderbehandlung noch benötigt wird oder Altlast eines längst migrierten Partners ist.
Konsolidierungshinweis: -
Status: belegt; Workaround (dokumentiert im Code-Kommentar mit Ticketverweis)
---
### Kandidat INT-31
Ebene: SwRS
Typ: Daten
Akteur: Marktforschungsinstitut GfK
Vorbedingung: Verkaufsdaten für Meldezeitraum vorhanden
Fakt: `GfkExportBL` erstellt Exportdateien für GfK (Marktforschungsinstitut) auf Basis von Verkaufs-/Bestandsdaten (Abhängigkeiten zu `ReceiptBL`, `ArticleBL`, `ArticleStockBL`) und referenziert `FluentFTP`, was auf einen FTP-basierten Übertragungsweg hindeutet.
Aussage: Das System soll periodisch aufbereitete Verkaufs- und Bestandsdaten für die externe Marktforschungsauswertung (GfK) exportieren und übertragen können.
Ergebnis: Erfüllung von Meldepflichten/Branchenvereinbarungen gegenüber Marktforschungsinstituten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/GfkExport/GfkExportBL.cs:1-60 - Begründung: Konstruktor-Abhängigkeiten und Namensgebung belegen fachlichen Zweck; exakter Übertragungsweg/Format nicht vollständig gesichtet.
Prüfidee: Exportformat (Feldstruktur, Frequenz) und tatsächlichen Übertragungsweg (FTP-Zieladresse) im weiteren Verlauf detailliert prüfen.
Konsolidierungshinweis: -
Status: HYPOTHESE (Datei nur oberflächlich gesichtet; genaues Exportformat und Trigger/Frequenz nicht verifiziert)
---
## Abdeckung
### Vollständig/tief gesichtet (Primärbelege, mehrere Dateien/Methoden gelesen)
- `src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.cs` (Kernlogik, Zeilen 1-954 vollständig gelesen; Rest bis 2180 nicht mehr im Detail - Datei ist sehr groß, weitere Lieferanten-Handler-Methoden ab Zeile ~955 nicht mehr im Detail gesichtet)
- `src/backend/Centron.BL/EDI/SupplierEDI/ClientConnectBL.cs` (vollständig)
- `src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.Also.cs` (Auszug)
- `src/backend/Centron.BL/EDI/EDIGatewaySettingBL.cs` (vollständig)
- `src/backend/Centron.BL/EDI/Zugferd/ZUGFeRD_BL.cs` (Auszug)
- `src/backend/Centron.BL/DataExchange/PaymentTransactions/PaymentTransactionBL.cs` (vollständig)
- `src/backend/Centron.BL/DataExchange/Connectors/WebHookClient.cs` (vollständig)
- `src/backend/Centron.BL/DataExchange/GfkExport/GfkExportBL.cs` (Auszug, oberflächlich)
- `src/apis/Centron.Api.Gls/CentronGlsLogic.cs`, `CentronGlsConsts.cs` (vollständig)
- `src/apis/Centron.Api.Shipcloud/CentronShipcloudLogic.cs` (vollständig)
- `src/apis/Centron.APIs.FinAPI/FinApiClient.cs` (vollständig)
- `src/apis/Centron.APIs.CopDataAccess/CopApi.cs` (vollständig)
- `src/apis/Centron.APIs.ITscopeDataAccess/ITscopeApi.cs` (Auszug, erste 150 Zeilen)
- `src/apis/Centron.APIs.IcecatDataAccess/IcecatApi.cs` (Auszug)
- `src/apis/Centron.APIs.EgisDataAccess/EgisApi.cs` (Auszug)
- `src/apis/Centron.Api.EbInterface/EbInterfaceLogic.cs` (Auszug, erste 150 Zeilen)
- `src/webservice/Centron.Host/AspNetCore/HostedServices/EdiDownloadService.cs` (vollständig)
- `docs/reference/edi/edi-architecture.md`, `docs/reference/edi/edi-import-rules.md` (vollständig)
- `docs/guides/services/add-webservice-methods.md` (Auszug), `docs/guides/services/web-service-on-linux.md` (Auszug)
### Nur knapp gestreift / nicht tief analysiert (geringere fachliche Priorität lt. Auftrag)
- `src/backend/Centron.BL/EDI/Alltron/AlltronOrderBL.cs`, `EDI/ALSO/AlsoOrderBL.cs`, `EDI/AlsoCH/AlsoOrderCH_BL.cs`, `EDI/Komsa/KomsaOrderBL.cs`, `EDI/Concerto/ConcertoOrderBL.cs`, `EDI/Opentrans21/*`, `EDI/EGIS/EgisOrderBL.cs`, `EDI/EGIS/EgisOrderConfirmBL.cs`, `EDI/EGIS/EgisWarenkorbBL.cs` - Struktur nur über Verzeichnislisting und Dokumentation (edi-architecture.md) erschlossen, keine Zeilenanalyse. Fachliche Kernaussagen (Formatunterstützung je Lieferant) sind über INT-01 und die Dokumentation abgedeckt.
- `src/backend/Centron.BL/EDI/SupplierEDI/SupplierEdiBL.Alltron.cs`, `.Herweck.cs`, `.Komsa.cs`, `.Opentrans.cs`, `.AlsoCH.cs` - nicht gelesen, nur `.Also.cs` als Referenzbeispiel für das Partial-Class-Muster.
- `src/backend/Centron.BL/EDI/EDICommonBL.cs`, `EDILogBL.cs`, `EDI/Import/*` - nicht im Detail gelesen (nur indirekt über Verwendung in SupplierEdiBL.cs erschlossen).
- `src/backend/Centron.Gateway/*` (XSD-/generierte Parserklassen für ALSO, Alltron, AlsoCH, EGIS, Concerto) - nur Verzeichnisstruktur gesichtet, keine Inhaltsanalyse (generierte/Schema-Dateien, geringer eigenständiger Anforderungsgehalt).
- `src/backend/Centron.BL/DataExchange/BookKeeping/*` (Buchhaltungsexport/-import) - nicht gesichtet, thematisch an der Grenze zu diesem Cluster (eher Rechnungswesen-Cluster).
- `src/backend/Centron.BL/DataExchange/DocuForm/DocuFormApiSettingsBL.cs`, `Connectors/DocBeeTicket*.cs`, `Connectors/DocBeeConnectorConfigurationBL.cs` - nur Dateiname/Zweck erschlossen (Ticket-/Dokumenten-Konnektoren), nicht gelesen.
- `src/backend/Centron.BL/DataExchange/Rmm/RmmConnectionSettingsBL.cs`, `TanssInterfaces/TanssBL.cs`, `TelekomDive/TelekomDiveBL.cs` - nicht gelesen, nur Namen/Verzeichnis erfasst (vermutlich RMM-/Telekommunikations-Anbindungen, ggf. für separaten Cluster relevant).
- `src/backend/Centron.BL/Gateway/CustomGatewayBL.cs` - nicht gelesen.
- `src/backend/Centron.BL/Integrations/EsCustomerGroupBL.cs`, `EsRoleBL.cs` - nicht gelesen (Name deutet auf "Employee Self-Service"/Portal-Integration hin, nicht auf externe Partner).
- `src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/*`, `ZugferdExportItem.cs`, `ZugferdExportPositionItem.cs` - nicht gelesen (Ausgangsrechnungs-Export, ergänzend zu INT-13/INT-14).
- `src/backend/Centron.BL/WebServices/*` (großer Bestandteil, u.a. Accounts, Administration/AccessTokens) - nur Verzeichnisstruktur und `AccessTokenWebServiceBL.cs`-Pfad ermittelt, Inhalt nicht gelesen; primär interner Anwendungs-Webservice, nur am Rand relevant für "externe Integration" (siehe INT-26).
- `src/webservice/Centron.Controllers/*`, `Centron.Host/*` (restliche Controller/Services außer EdiDownloadService), `Centron.Host.Console`, `Centron.Host.WindowsService`, `c-entron.misc.ConnectionManager/*` - nur Verzeichnisstruktur gesichtet, nicht inhaltlich analysiert.
- `src/backend/Centron.Gateway/Concerto/*`, `EDI_Also/*.xsd`, `EDI_AlsoCH/*`, `EDI_EGIS/*` (XSD-Schemadateien) - nicht inhaltlich geprüft.
### Bekannte Lücken
1. Kein vollständiger Blick auf alle Lieferanten-Partial-Classes (Alltron/Herweck/Komsa/Opentrans/AlsoCH) - Detailregeln je Format (z.B. AlsoCH Swiss-ESR-Handling, Herweck Dual-Struktur-Fallback laut Doku) nur sekundär über `edi-architecture.md` belegt, nicht primär im Code verifiziert.
2. Keine Analyse der Datenbankschema-Details (Tabellenstruktur `EDIInvoiceHead` etc.) über die in der Dokumentation genannten Spalten hinaus.
3. Sicherheitsrelevante Funde (INT-03, INT-09, INT-11, INT-19) sind technische Beobachtungen aus dem Code; eine Bewertung, ob es sich um aktive Produktivrisiken oder tote/Test-Artefakte handelt, konnte im Rahmen dieser Recherche nicht abschließend vorgenommen werden - Empfehlung: gezieltes Security-Review dieser vier Fundstellen.
4. RMM-, Telekom- und Docuboard/DocBee-Konnektoren (`Rmm`, `TanssInterfaces`, `TelekomDive`, `Connectors/DocBee*`) wurden aus Zeitgründen und mangels erkennbarer fachlicher Kernbedeutung für den Auftrag (EDI/Versand/Zahlungsverkehr) nicht vertieft - bei Bedarf gesonderte Nachrecherche empfohlen.
5. GfK-Export (INT-31) nur oberflächlich gesichtet, als einziger Kandidat mit Status HYPOTHESE gekennzeichnet.
6. Die Restdatei `SupplierEdiBL.cs` (ca. 1200 weitere Zeilen ab Zeile 955) wurde nicht mehr im Detail gelesen; dort liegen vermutlich weitere EGIS-/ITScope-spezifische Verarbeitungsmethoden (`CheckSingleEgisAsync` u.a., laut Signaturen ab Zeile 952 sichtbar), die für eine vollständige Spezifikation noch auszuwerten wären.
@@ -0,0 +1,531 @@
# Cluster LOG - Lager, Logistik & Produktion (Rohbefunde RRE)
Recherche-Agent für Reverse Requirements Engineering an CentronERP. Rohbefunde, keine finalen IDs. Alle Pfade relativ zu
`C:\DEV\MasterArbeit\QuellCode\CentronERP`.
---
### Kandidat LOG-01
Ebene: SwRS
Typ: funktional
Akteur: Lagermitarbeiter, System (Wareneingang/Warenausgang)
Vorbedingung: Artikel existiert; Buchung einer Mengenänderung (Zu-/Abgang) wird ausgelöst
Fakt: `ArticleStockBL.IncreaseArticleStock` bricht die Bestandsbuchung stillschweigend ab (kein Fehler, kein Log), wenn `Article.ScanBarcode == false` ist NICHT der Fall — tatsächlich umgekehrt: Barcodes/Seriennummern werden bei Artikeln ohne `ScanBarcode` NICHT für die Bestandsführung berücksichtigt; die eigentliche Mengenbuchung erfolgt aber immer über `_repository.UpdateArticleStock(...)`. Der Kommentar im Code besagt explizit: "If the article has not 'ScanBarcode' active, the barcodes are only 'additionally' but they dont influence the article stock".
Aussage: Das System soll bei der Bestandsführung zwischen seriennummernpflichtigen Artikeln (mengenbasierte Fortschreibung zusätzlich über Barcodes) und nicht-seriennummernpflichtigen Artikeln (nur mengenbasierte Fortschreibung) unterscheiden.
Ergebnis: Konsistente Bestandsmenge auch bei Artikeln, die keine Einzel-Rückverfolgung per Seriennummer benötigen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/StockManagement/ArticleStockBL.cs:52-61 (IncreaseArticleStock) - Begründung: Kommentar und Codepfad zeigen explizit die Sonderbehandlung von ScanBarcode für die Bestandsfortschreibung.
Prüfidee: Bestandsbuchung für Artikel mit ScanBarcode=false und ScanBarcode=true vergleichen; prüfen ob Barcode-Zustand bei false wirklich keinen Einfluss auf `ARTIK.Menge`/`NebenlagerArtikel.Bestand` hat.
Konsolidierungshinweis: Ergänzt LOG-11/LOG-12 (SN-Pflicht-Constraints).
Status: belegt
---
### Kandidat LOG-02
Ebene: SwRS
Typ: funktional
Akteur: System (Wareneingang/Einkauf)
Vorbedingung: Wareneingang/Rechnung bucht eine Menge zu einem Artikel; Artikel hat keine Sonderpreisvereinbarung (`SpecialAgreementI3D`)
Fakt: `ArticleStockBL.UpdateArticlePurchasePrice` berechnet den neuen Einkaufspreis abhängig von `Article.NoMixedEk` (`FixedPurchasePrice` = keine Änderung, `LastPurchasePrice` = letzter EK übernehmen, sonst gewichteter Mischpreis `((oldPrice*oldQty)+additionalAmount)/quantity`), inkl. Fracht-/Versicherungsanteil (`FreightAmount`, `InsuranceAmount`) und kaufmännischer Rundung (`MidpointRounding.AwayFromZero`) auf `Article.Precision`.
Aussage: Das System soll den Artikel-Einkaufspreis bei Wareneingangsbuchungen automatisch nach konfigurierbarer Preisermittlungsart (Fixpreis / letzter EK / gleitender Mischpreis) inkl. Fracht- und Versicherungskosten neu berechnen.
Ergebnis: Korrekte Bewertung des Lagerbestands zu Einstandspreisen für Kalkulation und Bilanzierung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/StockManagement/ArticleStockBL.cs:74-149 (UpdateArticlePurchasePrice) - Begründung: vollständige Preislogik inkl. Rundung und Spezialfall Sonderpreisvereinbarung.
Prüfidee: Wareneingang mit unterschiedlichen `NoMixedEk`-Einstellungen durchspielen und resultierenden EK sowie Rundung verifizieren.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-03
Ebene: SwRS
Typ: Daten / funktional
Akteur: Lagermitarbeiter (Umbuchung)
Vorbedingung: Umbuchung eines Artikels zwischen zwei Lagern (Rebooking) wird protokolliert
Fakt: `StockBL.WriteStockRebookLog` validiert vor dem Schreiben: ArtikelI3D > 0, Datum (Default = jetzt falls `DateTime.MinValue`), Mitarbeiter darf nicht null sein, Quell- und Ziellager (`FromStore`/`ToStore`) dürfen nicht null sein.
Aussage: Das System soll Lagerumbuchungen nur protokollieren, wenn Artikel, Mitarbeiter sowie Quell- und Ziellager eindeutig angegeben sind.
Ergebnis: Lückenlose, prüfbare Nachverfolgbarkeit von Lagerumbuchungen (Audit-Trail).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:82-110 (WriteStockRebookLog) - Begründung: explizite Validierungsblöcke mit Fehlermeldungen.
Prüfidee: Rebooking ohne Mitarbeiter/ohne Ziellager auslösen und erwartete Fehlermeldung prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-04
Ebene: SyRS
Typ: funktional / Daten
Akteur: Lagerverwaltung (RMA-Prozess), System
Vorbedingung: RMA-Lager (Kunde/Eigen/Versand/Auftrag) sind über globale Einstellungen konfiguriert
Fakt: `StockBL.LoadOpenWarehouses` liest vier konfigurierbare RMA-Speziallager (`RMACustomerStorage`, `RMAOwnStorage`, `RMASendStorage`, `RMAOrderStorage`) aus den Anwendungseinstellungen und schließt sie aus der Liste "offener" Lager aus. `InventoryBL.GetSecondaryStocks` sperrt zusätzlich einzelne dieser Lager für die Inventur abhängig von separaten Lock-Flags (`RMALockCustomerStorage` etc.).
Aussage: Das System soll RMA-Sonderlager als geschlossene/gesperrte Lager von der allgemeinen Lagerauswahl sowie optional von der Inventur ausschließen können.
Ergebnis: Vermeidung fehlerhafter Bestandsbuchungen bzw. Inventurerfassungen in RMA-Prozesslagern.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:55-75 (LoadOpenWarehouses) - Begründung: konkrete Settings-Keys und Filterlogik.
- [SEKUNDÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:245-291 (GetSecondaryStocks) - Begründung: analoge, aber granularere Sperrlogik pro Lock-Flag für Inventuren.
Prüfidee: RMA-Lager konfigurieren, Lock-Flag umschalten und prüfen ob Lager in Inventur-Auswahl erscheint/verschwindet.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-05
Ebene: SyRS
Typ: funktional
Akteur: Lagermitarbeiter (Inventur)
Vorbedingung: Eine Inventur (`Inventory`/`Inventory2`) wird angelegt, bearbeitet oder abgeschlossen
Fakt: Zustandsautomat `InventoryState`: Open(0) / Deleted(1) / Closed(2) / OpenWithoutBC(3) / ClosedWithoutBC(4). `InventoryBL.AddInventory` setzt bei Neuanlage je nach Flag `withoutSerial` entweder `Open` oder `OpenWithoutBC`. `InventoryBL.DeleteInventory` togglet zwischen Open/OpenWithoutBC → Deleted und zurück (kein echtes Löschen). `InventoryNewBL.CloseInventory` verweigert erneutes Schließen bereits geschlossener Inventuren ("wurde schon abgeschlossen") und mappt Open→Closed bzw. OpenWithoutBC→ClosedWithoutBC.
Aussage: Das System soll Inventuren über einen definierten Zustandsautomat (offen/ohne-Seriennummer-offen → geschlossen/ohne-Seriennummer-geschlossen, alternativ gelöscht) führen und ein erneutes Schließen bereits geschlossener Inventuren verhindern.
Ergebnis: Nachvollziehbarer, konsistenter Lebenszyklus von Inventurvorgängen.
Belege:
- [PRIMÄR] src/webservice/Centron.WebServices.Core/Entities/Warehousing/InventoryManagement/InventoryState.cs:6-18 (enum InventoryState)
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:75-109 (AddInventory, DeleteInventory)
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryNewBL.cs:312-324 (CloseInventory)
Prüfidee: Inventur zweimal schließen versuchen; erwartete Fehlermeldung "wurde schon abgeschlossen" prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-06
Ebene: SyRS
Typ: Sicherheit / funktional
Akteur: Lagermitarbeiter mit Inventur-Rechten
Vorbedingung: Neue Inventur oder Inventurgruppe wird angelegt/gelöscht
Fakt: Rechteprüfungen über `UserRightsConst.Purchase.Inventory.{CREATE_INVENTORY, DROP_INVENTORY, CREATE_INVENTORY_GROUP, DELETE_INVENTORY_GROUP, REMOVE_ARTICLE_FROM_INVENTORY_GROUP}`; zusätzlich Namenspflicht (nicht leer, eindeutig je Inventur) und ein Gruppenname muss innerhalb einer Inventur eindeutig sein.
Aussage: Das System soll das Anlegen/Löschen von Inventuren und Inventurgruppen an spezifische Benutzerrechte binden und eindeutige, nicht-leere Namen erzwingen.
Ergebnis: Kontrollierter Zugriff auf Inventurfunktionen, keine Namenskollisionen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:75-109,137-144,196-241,573-604 (AddInventory, IsvalidInventoryName, CreateInventoryGroup, IsValidInventoryGroupName, DeleteGroup)
Prüfidee: Benutzer ohne CREATE_INVENTORY-Recht versuchen lassen, eine Inventur anzulegen → erwartete Fehlermeldung "Sie haben nicht die benötigten Rechte."
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-07
Ebene: SyRS
Typ: funktional / Validierung
Akteur: Lagermitarbeiter (Inventurerfassung)
Vorbedingung: Artikel wird in einer offenen Inventur erfasst
Fakt: `InventoryBL.AddArticle` liefert Fehler "Dieser Artikel muss mit Seriennummer erfasst werden!", wenn `article.ScanBarcode == true`, kein Barcode übergeben wurde und die Inventur offen ist (`inventory.State == InventoryState.Open`). Bei Erfassung per Barcode wird die Menge automatisch auf 1 gesetzt (`amount = 1`).
Aussage: Das System soll die Erfassung seriennummernpflichtiger Artikel in einer offenen Inventur ohne Seriennummer verhindern und je erfasster Seriennummer eine Menge von genau 1 buchen.
Ergebnis: Korrekte, prüfbare Bestandszählung für seriennummernpflichtige Artikel.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:379-399 (AddArticle)
Prüfidee: SN-pflichtigen Artikel ohne Barcode in offener Inventur erfassen → Fehlermeldung erwarten.
Konsolidierungshinweis: verwandt mit LOG-01/LOG-11.
Status: belegt
---
### Kandidat LOG-08
Ebene: SwRS
Typ: Validierung
Akteur: Lagermitarbeiter (Inventurerfassung per Barcode)
Vorbedingung: Ein Barcode/Seriennummer wird während einer Inventur gescannt
Fakt: `InventoryBL.CheckBcSetting` verweigert die Erfassung, wenn der Barcode-Status `InDeliveryList` ("Diese Seriennummer befindet sich in einem Lieferschein!"), `InInvoice` ("... in einer Rechnung!") oder `InIntake` ("... in einem Wareneingang der noch nicht gebucht wurde.") ist, oder wenn der Barcode in derselben Inventur bereits erfasst wurde ("Die Seriennummer wurde bei dieser Inventur bereits erfasst!").
Aussage: Das System soll das Erfassen von Seriennummern in einer Inventur verhindern, wenn diese bereits in einem offenen Geschäftsvorgang (Lieferschein, Rechnung, ungebuchter Wareneingang) gebunden sind oder bereits in der laufenden Inventur gezählt wurden.
Ergebnis: Verhinderung von Doppelzählungen und inkonsistenten Bestandskorrekturen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:479-532 (CheckBcSetting) - Begründung: enthält zusätzlich einen auskommentierten historischen Regelsatz (SKA 2015-11-17) zu Mehrfachvergabe gleicher Seriennummern, der bewusst verworfen wurde.
Prüfidee: Barcode mit Status InInvoice in Inventur scannen → erwartete Fehlermeldung.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-09
Ebene: SyRS
Typ: funktional
Akteur: System (Inventurabschluss), Lagermitarbeiter
Vorbedingung: Ein oder mehrere Lager werden im Rahmen einer Inventur abgeschlossen (`CloseStorages`)
Fakt: `InventoryBL.CloseStorages` läuft transaktional (`Session.StartTransaction()`/`CommitTransaction()`/`RollbackTransaction()`) pro Lager: (1) für gezählte, nicht in DB gespeicherte Artikel wird eine `InventoryArticleCheck` (Vorher-/Nachher-Menge, EK) erzeugt, (2) Barcodes mit Status `LostAtStocktaking` werden zurück auf `InStock` gesetzt, (3) Hauptlager-/Nebenlagerbestand wird über `ArticleStockBL.UpdateArticleStock` aktualisiert oder ein neuer `SecondaryStockArticle`-Datensatz angelegt, (4) bei Komplettinventur werden nicht gescannte Artikel in die Inventurbuchungstabelle geschrieben und deren Barcodes auf "verloren bei Inventur" gesetzt, (5) ein Log-Eintrag ("hat am ... eine Komplettinventur/Teilinventur für das Lager ... durchgeführt.") wird erzeugt, (6) das Lager wird als `InventoryClosedStorage` markiert.
Aussage: Das System soll den Inventurabschluss je Lager als atomare Transaktion durchführen, die Bestandskorrekturen, Barcode-Statusänderungen sowie eine Protokollierung (Wer/Wann/Welches Lager/Vollständig oder Teilinventur) umfasst.
Ergebnis: Konsistenter, nachvollziehbarer Bestandsabgleich nach einer Inventur.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:797-944 (CloseStorages) - Begründung: vollständige, mehrstufige Transaktionslogik mit expliziten SQL-/Log-Aufrufen.
Prüfidee: Teilinventur eines Nebenlagers abschließen und Bestandsänderung, Barcode-Status sowie Log-Eintrag im UI/DB verifizieren.
Konsolidierungshinweis: Ergänzt LOG-05 (State-Machine der Inventur selbst).
Status: belegt
---
### Kandidat LOG-10
Ebene: SwRS
Typ: funktional / nicht-funktional (Datenintegrität)
Akteur: Lagermitarbeiter (manuelle Inventurkorrektur)
Vorbedingung: Eine Bestandskorrektur zwischen zwei Lagern/Gruppen wird nachträglich vorgenommen (`InventoryArticleCorrection`)
Fakt: Die Methode liest Artikeldaten per Raw-SQL (`SELECT ... FROM dbo.ARTIK ... LEFT OUTER JOIN dbo.NebenlagerArtikel ...`), verweigert die Korrektur für seriennummernpflichtige Artikel ("Diese Funktion unterstützt keine Seriennummer Artikel!") und für Artikel ohne Lagerbuchung (`changeStock != "J"` → "Artikel unterstützt keine Lagerbuchung!"). Bestandsänderungen erfolgen anschließend über direkte `UPDATE dbo.ARTIK SET Menge = Menge ± @Quantity` bzw. `UPDATE dbo.NebenlagerArtikel SET Bestand = Bestand ± @Quantity` Statements statt über die reguläre BL-Bestandsbuchung (`ArticleStockBL`).
Aussage: Das System soll manuelle Inventur-Bestandskorrekturen nur für nicht-seriennummernpflichtige, lagerbuchungsrelevante Artikel zulassen.
Ergebnis: Verhinderung inkonsistenter Bestände bei manuellen Korrekturen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs:1085-1390 (InventoryArticleCorrection)
Prüfidee: Korrektur für SN-pflichtigen Artikel anstoßen → erwartete Fehlermeldung; parallel prüfen ob Bestandsänderung konsistent mit Werten aus `ArticleStockBL` bleibt (Umgehung der zentralen Buchungslogik als Risiko).
Konsolidierungshinweis: -
Status: belegt; Workaround (Bestandsänderung per Raw-SQL statt zentraler BL-Buchungsroutine — Risiko für Web-Neuimplementierung, da Business-Regeln der zentralen Buchung hier nicht greifen)
---
### Kandidat LOG-11
Ebene: SwRS
Typ: Validierung
Akteur: Artikelverwaltung
Vorbedingung: Ein bestehender Artikel (`I3D > 0`) mit vorhandenem Lagerbestand soll bzgl. Seriennummernpflicht (`ScanBarcode`) geändert werden
Fakt: `ArticleBL` (private Validierung vor Speichern) verweigert die Änderung mit "Die Änderung der Seriennummernpflicht ist nicht erlaubt, wenn der Artikel einen Lagerbestand hat.", sobald `ScanBarcode` als "dirty" erkannt wird (`IsDirtyProperty`) und `ArticleStockInfo.Quantity != 0` in irgendeinem Lager existiert.
Aussage: Das System soll die nachträgliche Änderung der Seriennummernpflicht eines Artikels verhindern, solange ein Lagerbestand ungleich Null vorhanden ist.
Ergebnis: Verhinderung inkonsistenter Bestandsführung beim Wechsel zwischen mengen- und seriennummernbasierter Bestandsverwaltung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ArticleBL.cs:1536-1549 - Begründung: expliziter Prüfblock mit Kommentar "Prevent changing SN-Pflicht ... when article has existing stock".
Prüfidee: Artikel mit Bestand > 0 speichern und ScanBarcode-Flag umschalten → Fehlermeldung erwarten.
Konsolidierungshinweis: Ergänzt LOG-01/LOG-07.
Status: belegt
---
### Kandidat LOG-12
Ebene: SwRS
Typ: Validierung
Akteur: Artikelverwaltung
Vorbedingung: Globale Einstellung "BearingRrelatedSerialNumbers" aktiv; Artikel mit geänderter Seriennummernpflicht wird gespeichert
Fakt: `ArticleBL.CheckSerialnumberQuantityEqualsStockQuantity` vergleicht je Lager die Anzahl vorhandener Seriennummern (`BarcodeBL.GetBarcodesThroughPaging`) mit der gebuchten Lagermenge (`ArticleStockInfo.Quantity`); bei Abweichung wird "Die Anzahl an Seriennummer für das Hauptlager/Lager {Name} stimmen nicht mit der Anzahl an Artikel im Lager überein." zurückgegeben.
Aussage: Das System soll bei aktivierter lagerbezogener Seriennummernprüfung sicherstellen, dass Anzahl erfasster Seriennummern und gebuchte Lagermenge je Lager übereinstimmen.
Ergebnis: Erkennung von Inkonsistenzen zwischen Mengen- und Seriennummernbestand.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ArticleBL.cs:1553-1559,1572-1622 (CheckSerialnumberQuantityEqualsStockQuantity, CheckArticleStockInfos)
Prüfidee: Setting aktivieren, Anzahl Seriennummern künstlich von Lagermenge abweichen lassen, Speichern testen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-13
Ebene: SyRS
Typ: Sicherheit
Akteur: Lagermitarbeiter mit Buchungsrechten
Vorbedingung: Lagerbestandsbuchung (Zugang/Abgang/Umbuchung/Negativbuchung) wird durchgeführt
Fakt: Getrennte Benutzerrechte: `UserRightsConst.Purchase.StockList.BOOK_TO_STOCK` (Zubuchen), `BOOK_FROM_STOCK` (Abbuchen), `TRANSFER_STOCK` (Umbuchen), `BOOK_ARTICLE_STOCK_INTO_NEGATIVE` (Bestand ins Negative buchen), `CHANGE_SERIALNUMBER_REQUIRED_FLAG`.
Aussage: Das System soll Lagerbuchungsarten (Zugang, Abgang, Umbuchung, Negativbestand, Änderung SN-Pflicht) über granulare, unabhängig vergebbare Benutzerrechte steuern.
Ergebnis: Feingranulare Zugriffskontrolle auf kritische Bestandsvorgänge.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ArticleBL.cs:108-121 (Ermittlung der Settings-Flags)
- [SEKUNDÄR] src/backend/Centron.Interfaces/Warehousing/ArticleManagement/ArticleManagementUiSettings.cs:65-70 (Property HasUserArticleNegativBookingRight mit Kommentar "Right: Artikel - Bestände ins Negative buchen")
Prüfidee: Benutzer ohne BOOK_ARTICLE_STOCK_INTO_NEGATIVE-Recht versuchen lassen, Bestand negativ zu buchen.
Konsolidierungshinweis: -
Status: belegt; [HYPOTHESE: konkrete Stelle, an der die Negativbuchung tatsächlich technisch verhindert wird (DB-Constraint vs. BL-Check), wurde in diesem Cluster nicht abschließend lokalisiert]
---
### Kandidat LOG-14
Ebene: SyRS
Typ: Daten
Akteur: System (Bestands-/Belegverwaltung)
Vorbedingung: Barcode/Seriennummer durchläuft den Warenfluss
Fakt: `BarcodeState`-Enum mit >20 Zuständen: None, InStock, InOrder, InDeliveryList, InInvoice, InRMA, InSendBack, InRepairInput, InRequest, InMasterDataList, LostAtStocktaking, AssignedToOrder, AssignedToDeliveryList, AssignedToPickupList, AssignedToInvoice, AssignedToCreditVoucher, ReplacementArticle, ExchangedArticle, Deactivated, ManuallyBookedOut, InIntake, InStockOrder, AssignedToStockOrder, Scrapped, ConditionChanged.
Aussage: Das System soll den Lebenszyklus jeder Seriennummer/jedes Barcodes über einen fein granularen Zustandsautomat abbilden, der Lagerzugehörigkeit, Zuordnung zu Belegen (Auftrag, Lieferschein, Rechnung, Gutschrift, Abholliste) sowie Sonderzustände (RMA, Reparatur, Inventurverlust, Verschrottung) unterscheidet.
Ergebnis: Lückenlose Rückverfolgbarkeit einzelner Exemplare über den gesamten Warenfluss.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Warehousing/BarcodeState.cs:6-35 (enum BarcodeState)
Prüfidee: Zustandsübergangsdiagramm aus Code-Nutzungsstellen (BarcodeBL, InventoryBL, ReceiptBarcodeBL) rekonstruieren und mit Fachanwendern validieren.
Konsolidierungshinweis: Basis für LOG-07, LOG-08, LOG-15.
Status: belegt
---
### Kandidat LOG-15
Ebene: SwRS
Typ: Validierung
Akteur: System (Auftragskommissionierung)
Vorbedingung: Ein Barcode/Seriennummer soll einer Auftragsposition zugeordnet werden
Fakt: `BarcodeBL.UpdateBarcodeSetInOrderState` gibt einen Fehler zurück ("The barcode ({Serialnumber}) is already assigned to an order ({OrderNumber})"), wenn der Barcode bereits einer anderen Auftragsposition zugeordnet ist (`OrderPositionI3D > 0`) und sein Status nicht `InStock` ist. Ist der Barcode bereits exakt derselben Position zugeordnet, wird kein Fehler ausgelöst (Idempotenz).
Aussage: Das System soll verhindern, dass ein Barcode/eine Seriennummer gleichzeitig mehreren Aufträgen zugeordnet wird.
Ergebnis: Eindeutige 1:1-Zuordnung von Seriennummern zu Aufträgen, Vermeidung von Doppelverkäufen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/BarcodeBL.cs:73-120 (UpdateBarcodeSetInOrderState)
Prüfidee: Barcode einem Auftrag zuweisen, dann Zuweisung zu einem zweiten Auftrag versuchen → Fehler erwarten.
Konsolidierungshinweis: verwandt mit LOG-14.
Status: belegt
---
### Kandidat LOG-16
Ebene: SyRS
Typ: funktional
Akteur: System (Teil-Kommissionierung von Aufträgen)
Vorbedingung: Ein Auftrag wird teilweise oder vollständig kommissioniert; Kommissionierungssätze (`PartialCommissionOrder`) existieren
Fakt: Zustandsautomat `PartialCommissionOrderState`: Deleted(0), Incomplete(1), Complete(2), Partly(3), Delivered(4), IncompleteButInStock(5). `PartialCommissionOrderBL.DeterminePartialCommissionOrderState` berechnet den Status aus den Positionsmengen: alle Positionen mit `QuantityInDeliveryList >= TargetQuantity` → Delivered; alle Positionen `CurrentQuantity == TargetQuantity` → Complete; irgendein Fortschritt (`CurrentQuantity > 0` oder `QuantityInDeliveryList > 0`) → Partly; sonst Incomplete. Bereits gelöschte Sätze bleiben Deleted.
Aussage: Das System soll den Bearbeitungsstatus einer Teil-Kommissionierung automatisch aus dem Verhältnis von kommissionierter, gelieferter und Zielmenge je Position ableiten.
Ergebnis: Transparenter, automatisch konsistenter Fortschrittsstatus der Kommissionierung ohne manuelle Statuspflege.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Warehousing/Commissions/PartialCommissionOrderState.cs:11-26 (enum)
- [PRIMÄR] src/backend/Centron.BL/Warehousing/Commissions/PartialCommissionOrderBL.cs:304-324 (DeterminePartialCommissionOrderState)
Prüfidee: Teil-Kommissionierung mit 2 Positionen anlegen, eine davon vollständig kommissionieren/liefern, Status prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-17
Ebene: StRS/SyRS
Typ: funktional
Akteur: Vertrieb/Lager (Auftragsabwicklung)
Vorbedingung: Ein Auftrag mit aktiven Teil-Kommissionierungssätzen wird in einen Lieferschein überführt
Fakt: `PartialCommissionOrderBL.HasPartialCommissionOrdersForItems` prüft, ob mindestens eine der zu liefernden Auftragspositionen zu einem aktiven (weder gelöschten noch gelieferten) Teil-Kommissionierungssatz gehört — laut Code-Kommentar zur Warnung des Anwenders, dass Teil-Kommissionierungssätze beim direkten Umwandeln eines Auftrags in einen Lieferschein ignoriert werden (Ticket 165243).
Aussage: Das System soll den Anwender warnen, wenn beim Erzeugen eines Lieferscheins aus einem Auftrag aktive Teil-Kommissionierungssätze für betroffene Positionen bestehen, die dabei ignoriert würden.
Ergebnis: Vermeidung von Fehllieferungen bzw. inkonsistenter Kommissionsdaten durch Umgehung des Teil-Kommissionierungs-Workflows.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/Commissions/PartialCommissionOrderBL.cs:100-129 (HasPartialCommissionOrdersForItems, inkl. XML-Doc-Kommentar mit Ticketreferenz)
Prüfidee: Auftrag mit aktivem Teil-Kommissionierungssatz direkt in Lieferschein umwandeln und auf Warnhinweis prüfen.
Konsolidierungshinweis: Verknüpft Cluster LOG mit Vertriebs-/Auftragscluster (Lieferschein-Erstellung).
Status: belegt
---
### Kandidat LOG-18
Ebene: SyRS
Typ: funktional
Akteur: System (Benachrichtigung nach Kommissionierung)
Vorbedingung: Kommissionierung eines Auftrags wurde durchgeführt; E-Mail-Benachrichtigung ist gemäß Logistikeinstellungen konfiguriert
Fakt: `OrderCommissionBL.ComposeCommissionOrderEmail` unterdrückt den E-Mail-Versand vollständig, wenn (a) der Auftrag als Direktlieferung markiert ist und `SendCommissionEmailWhenDirectDelivery=false`, oder (b) `SendEmailOnlyWhenFullyCommissioned=true` und die Kommissionierung nicht vollständig ist und der Versand nicht manuell ausgelöst wurde (`sendEmailManually=false`), oder (c) die Einstellung `PickSendEmail=SendNoEmail` ist. Empfängerermittlung kombiniert Standardempfänger (Auftragsersteller, Innen-/Außendienst, Techniker 1/2) mit global oder auftragsspezifisch konfigurierten Zusatzempfängern (`UseCustomCommissionMailRecipients`, `OrderSpecificCommissionMailSetting`).
Aussage: Das System soll den Versand von Kommissionierungs-Benachrichtigungen anhand konfigurierbarer Regeln (Direktlieferung, Vollständigkeitsgrad, globale/auftragsspezifische Empfängerlisten) steuern.
Ergebnis: Bedarfsgerechte, konfigurierbare Information der Beteiligten über den Kommissionierungsfortschritt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/Commissions/OrderCommissionBL.cs:202-385 (ComposeCommissionOrderEmail und Hilfsmethoden)
Prüfidee: Verschiedene Settings-Kombinationen (Direktlieferung ja/nein, Vollständig ja/nein) durchspielen und E-Mail-Erzeugung/-Unterdrückung prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-19
Ebene: SyRS
Typ: Sicherheit
Akteur: Lagermitarbeiter (Kommissionierung)
Vorbedingung: Zugriff auf Kommissionierungsmodul bzw. Generierung neuer Seriennummern innerhalb der Kommissionierung
Fakt: Rechteprüfungen `UserRightsConst.Logistic.Commissioning.ID` ("Der angemeldete Benutzer hat nicht das Recht um auf die Kommissionierung zuzugreifen.") und `UserRightsConst.Logistic.Commissioning.GENERATE_BARCODES` ("... nicht das Recht, neue Seriennummern in der Kommissionierung zu generieren."), zusätzlich `CREATE_PARTIAL_COMMISSION_FOR_ORDER` / `DELETE_PARTIAL_COMMISSION_FOR_ORDER`.
Aussage: Das System soll den Zugriff auf das Kommissionierungsmodul sowie sensible Teilfunktionen (Barcode-Neugenerierung, Anlegen/Löschen von Teil-Kommissionierungssätzen) über dedizierte Benutzerrechte absichern.
Ergebnis: Rollenbasierte Zugriffskontrolle auf Kommissionierungsfunktionen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/Commissions/OrderCommissionBL.cs:429-441 (HasUserRightsTooAccessCommissionModule, HasUserRightTooGenerateNewBarcodesInCommissionModule)
- [SEKUNDÄR] src/backend/Centron.BL/Warehousing/Commissions/PartialCommissionOrderBL.cs:135,170 (Rechteprüfungen CREATE/DELETE_PARTIAL_COMMISSION_FOR_ORDER)
Prüfidee: Benutzer ohne Kommissionierungs-Recht am Modul anmelden lassen und Fehlermeldung/Zugriffsverweigerung prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-20
Ebene: StRS/SyRS
Typ: funktional / Lizenzierung
Akteur: Produktionsplaner
Vorbedingung: Zugriff auf jegliche Produktionsfunktion (Maschinen, Stücklisten, Fertigungsaufträge)
Fakt: Praktisch jede Methode in `ProductionBL`, `ProductionOrderBL` und `ArticleProductionBL` prüft zu Beginn `LicenseManager.Instance.HasLicense(LicenseGuids.ProductionManagement)`; bei fehlender Lizenz wird je nach Methode entweder eine `Exception` mit der Meldung "Sie besitzen nicht die Lizenz für das Produktionsmanagement" geworfen oder (bei einigen Lesemethoden in `ArticleProductionBL`) stillschweigend ein leeres Objekt/eine leere Liste zurückgegeben.
Aussage: Das System soll sämtliche Produktionsmanagement-Funktionen (Maschinen, Maschinenarten, Standorte, Stücklisten, Fertigungsschritte, Fertigungsaufträge) an eine separate Lizenz binden.
Ergebnis: Produktionsmanagement als optional lizenzierbares Modul, klar abgegrenzt von der Basis-Warenwirtschaft.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Production/ProductionBL.cs:29-30,39-40,49-50,105-106,115-116,126-127,166-167,177-178,185-186,226-227,236-237,246-247,256-257 (wiederholte Lizenzprüfung)
- [SEKUNDÄR] src/backend/Centron.BL/Warehousing/ArticleProduction/ArticleProductionBL.cs:34-35,44-45,55-56,75-76 (uneinheitliches Verhalten: teils Exception, teils leeres Ergebnis)
Prüfidee: Produktionsfunktionen ohne gültige ProductionManagement-Lizenz aufrufen und Verhalten (Exception vs. leeres Ergebnis) je Methode dokumentieren.
Konsolidierungshinweis: -
Status: belegt; [HYPOTHESE: uneinheitliches Fehlerverhalten (Exception vs. leere Liste) wirkt wie technische Inkonsistenz, nicht wie bewusste fachliche Anforderung — für Web-Neuimplementierung zu klären, ob Sonderfall gewünscht ist]
---
### Kandidat LOG-21
Ebene: SwRS
Typ: Daten
Akteur: Produktionsplaner
Vorbedingung: Stücklisten- und Fertigungsauftragsstruktur für einen zu produzierenden Artikel wird gepflegt
Fakt: Entitätshierarchie: `ArticleProductionMaterial` (Materialbedarf/Stückliste je `ProducedArticleI3D`) und `ArticleProductionStep` (Fertigungsschritte je Artikel, sortiert über `SortOrder`) bilden die Vorlage; `ArticleProductionOrder` mit `ArticleProductionOrderStepItem` (sortierte Schritt-Positionen je Auftrag, referenziert `MachineI3D`/`MachineKindI3D`) bilden den konkreten Fertigungsauftrag.
Aussage: Das System soll Fertigungsaufträge auf Basis wiederverwendbarer Stücklisten (Materialbedarf) und Fertigungsschritt-Vorlagen je zu produzierendem Artikel erzeugen können.
Ergebnis: Standardisierte, wiederverwendbare Produktionsdefinitionen als Grundlage für konkrete Fertigungsaufträge.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ArticleProduction/ArticleProductionBL.cs:28-118 (ArticleProductionMaterial), 121-210 (ArticleProductionStep), 214-455 (ArticleProductionOrder/StepItem)
Prüfidee: Stückliste für Artikel A anlegen, Fertigungsauftrag erzeugen, prüfen ob Schrittreihenfolge (SortOrder) korrekt übernommen wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-22
Ebene: SyRS
Typ: funktional
Akteur: Produktionsmitarbeiter (RFID-Zeiterfassung an der Maschine)
Vorbedingung: Mitarbeiter meldet sich per RFID-Token an einem Fertigungsschritt an/ab
Fakt: `ArticleProductionBL.SetArticleProductionOrderStepItemTime` löst über `EmployeeRfidTokenBL` den Mitarbeiter anhand des RFID-Tokens auf (Exception "Employee Rfid Token not found" falls unbekannt), beendet automatisch alle offenen Zeiterfassungen dieses Mitarbeiters (`OnlyWithOutEndTime=true` → `EndTime = jetzt`) und startet – sofern `request.OnlyStop == false` – eine neue Zeiterfassung (`ArticleProductionOrderStepItemTime`) mit Verknüpfung zu einem oder mehreren Fertigungsschritt-Positionen (`ArticleProductionOrderStepItemTimeDataRecording`).
Aussage: Das System soll je Mitarbeiter immer nur eine aktive Zeiterfassung an einem Fertigungsschritt zulassen; ein neuer RFID-Scan soll automatisch die vorherige offene Zeiterfassung desselben Mitarbeiters beenden, bevor eine neue gestartet wird.
Ergebnis: Korrekte, überschneidungsfreie Arbeitszeiterfassung je Mitarbeiter in der Fertigung (Basis für Nachkalkulation/Lohnfertigung).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ArticleProduction/ArticleProductionBL.cs:457-506 (SetArticleProductionOrderStepItemTime)
Prüfidee: Mitarbeiter an Schritt A anmelden, danach ohne Abmeldung an Schritt B anmelden → prüfen, ob Zeit an Schritt A automatisch mit Endzeit versehen wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-23
Ebene: SwRS
Typ: Daten
Akteur: Produktionsplaner
Vorbedingung: Maschinenpark wird für die Fertigungsplanung gepflegt
Fakt: Stammdatenhierarchie `ProductionMachine` (referenziert `ProductionMachineKind`, `ProductionMachineLocation`), `ProductionMachineKind` mit `ProductionMachineKindStepsDescription` (Schrittbeschreibungen je Maschinenart) sowie hierarchische `ProductionMachineLocation` (`ParentProductionMachineLocationI3D` für Standort-Baumstruktur). Filterung u.a. nach `IsActive`, Name/Volltext, übergeordnetem Standort.
Aussage: Das System soll Maschinen mit Maschinenart, hierarchischem Standort und art-spezifischen Standard-Fertigungsschritten als Stammdaten verwalten.
Ergebnis: Strukturierte Maschinen-/Standortstammdaten als Grundlage der Fertigungsauftragsplanung (Maschinenzuordnung, Kapazität).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Production/ProductionBL.cs:23-301 (Machine/MachineKind/MachineLocation inkl. Filter- und Speichermethoden)
Prüfidee: Maschinenstandort-Hierarchie mit 2 Ebenen anlegen und Filterung nach übergeordnetem Standort prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-24
Ebene: SyRS
Typ: Daten / nicht-funktional (Nachvollziehbarkeit)
Akteur: Servicetechniker/Administration (Geräteverwaltung)
Vorbedingung: Ein Kundengerät (`AccountDevice`) wird angelegt, geändert oder gelöscht
Fakt: `AccountDeviceBL.SaveAccountDevice` setzt bei Neuanlage `CreatedDate`/`CreatedByI3D`, bei jeder Speicherung `ChangedDate`/`ChangedByI3D`, und schreibt anschließend über `WriteAccountDeviceLog` einen Log-Eintrag ("Das Gerät wurde erstellt von {ShortSign}" bzw. "... aktualisiert von ..."). `DeleteAccountDevice` führt ein Soft-Delete durch (`IsDeleted=true`, `DeletedDate`, `DeletedByI3D`) statt physischem Löschen, ebenfalls protokolliert ("Das Gerät wurde gelöscht").
Aussage: Das System soll Geräteänderungen (Anlage, Änderung, Löschung) durch Soft-Delete und ein vollständiges, mitarbeiterbezogenes Änderungsprotokoll nachvollziehbar machen.
Ergebnis: Auditierbare Gerätehistorie ohne Datenverlust durch physisches Löschen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Devices/AccountDeviceBL.cs:42-107 (SaveAccountDevice, DeleteAccountDevice, WriteAccountDeviceLog)
Prüfidee: Gerät löschen, danach prüfen ob Datensatz weiterhin in DB vorhanden ist (nur `IsDeleted=true`) und ob Log-Eintrag erzeugt wurde.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-25
Ebene: SyRS
Typ: Daten / Schnittstelle
Akteur: Servicetechniker (Ticketbearbeitung mit Gerätebezug)
Vorbedingung: Ein Kundengerät ist einem oder mehreren Support-Tickets zugeordnet
Fakt: `AccountDeviceBL.SearchAccountDevices` filtert Geräte optional über `AccountDeviceToTicket`-Mapping nach `TicketI3D`; `GetTicketI3DsForAccountDevices` liefert umgekehrt alle Tickets zu einer Menge von Geräten. Standardmäßig werden gelöschte Geräte ausgeblendet (`IncludeDeleted == false` filtert `IsDeleted == false`).
Aussage: Das System soll Kundengeräte vollständig mit Support-Tickets verknüpfen können (n:m-Beziehung) und gelöschte Geräte standardmäßig aus Trefferlisten ausblenden.
Ergebnis: Durchgängige Nachverfolgbarkeit "welches Gerät steckt in welchem Ticket" für Service/Helpdesk.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Devices/AccountDeviceBL.cs:109-174 (SearchAccountDevices, GetTicketI3DsForAccountDevices)
Prüfidee: Gerät zwei Tickets zuordnen, per TicketI3D-Filter suchen und Ergebnis verifizieren.
Konsolidierungshinweis: Schnittstelle zum Support-/Ticket-Cluster (nicht Bestandteil dieses Clusters, nur referenziert).
Status: belegt
---
### Kandidat LOG-26
Ebene: StRS/SyRS
Typ: funktional
Akteur: Einkauf/Disposition
Vorbedingung: Artikelbestand unterschreitet den konfigurierten Mindestbestand in Haupt- oder Nebenlager
Fakt: `OrderSuggestionListBL` ermittelt per SQL Bestellvorschläge, indem der aktuelle Bestand (`cvw_ArticleCount.cnt`) je Artikel/Lager mit `Mindestbestand` (+ Bestellungen in Zulieferung, `IsNull(ab.duration,0)`) verglichen wird — getrennt für Hauptlager (`WarehouseI3D = -1`, Quelle `ARTIK.Mindestbestand`) und Nebenlager (Quelle `NebenlagerArtikel.Mindestbestand`). Artikel müssen zusätzlich `Abbuchung = 'J'` (Bestandsführung aktiv) oder `IsObligatoryBooking = 1` erfüllen.
Aussage: Das System soll automatisch Bestellvorschläge generieren, wenn der Lagerbestand (Haupt- oder Nebenlager) unter den je Lager konfigurierbaren Mindestbestand fällt, unter Berücksichtigung bereits laufender Zulieferungen.
Ergebnis: Automatisierte Nachbestellung zur Vermeidung von Fehlbeständen (Basis für Beschaffungsprozess).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:139-158,425-436,860-870 (SQL-Logik Mindestbestand vs. cvw_ArticleCount, getrennt Haupt-/Nebenlager)
Prüfidee: Artikel mit Mindestbestand 10 auf Bestand 5 senken, Bestellvorschlagsliste generieren und Aufnahme des Artikels prüfen.
Konsolidierungshinweis: Grenzfall zum Einkaufscluster (Purchasing) — hier nur die lagerseitige Bestandsschwelle als Auslöser dokumentiert.
Status: belegt
---
### Kandidat LOG-27
Ebene: SwRS
Typ: funktional / Datenintegrität
Akteur: Lagerverwaltung (Stammdatenpflege Lagerplätze)
Vorbedingung: Ein Lagerplatz (`StoragePlace`) wird deaktiviert (gelöscht)
Fakt: `StoragePlaceBL.SaveOrUpdateStoragePlace` erkennt `storagePlace.State == 0` (Löschung/Deaktivierung) und deaktiviert transaktional (`Session.WithTransaction`) alle zugehörigen `StorageArea`-Datensätze (`State = 0`) über `StorageAreaBL`.
Aussage: Das System soll bei Deaktivierung eines Lagerplatzes automatisch alle zugeordneten Lagerbereiche (StorageArea) kaskadierend deaktivieren.
Ergebnis: Verhinderung verwaister, aktiver Lagerbereiche unter einem deaktivierten Lagerplatz.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/StockManagement/StoragePlaceBL.cs:35-59 (SaveOrUpdateStoragePlace)
Prüfidee: Lagerplatz mit 2 Lagerbereichen deaktivieren und prüfen, ob beide Bereiche automatisch auf State=0 gesetzt werden.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-28
Ebene: SyRS
Typ: Daten
Akteur: System (Filialverwaltung)
Vorbedingung: Eine Filiale (Branch) hat ein zugeordnetes Standardlager
Fakt: `StockBL.GetDefaultWarehouseI3DFromBranch` liest über `BranchStock` (Filter `BranchI3D` + `IsDefault == 1`) das Standardlager einer Filiale aus; `GetWarehouseI3DToBranch` liefert die vollständige Filiale-zu-Lager-Zuordnung als Liste.
Aussage: Das System soll jeder Filiale genau ein Standardlager zuordnen können, das für filialbezogene Warenbewegungen automatisch vorbelegt wird.
Ergebnis: Automatische, filialkorrekte Lagerzuordnung ohne manuelle Auswahl im Regelfall.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs:133-151 (GetDefaultWarehouseI3DFromBranch, GetWarehouseI3DToBranch)
Prüfidee: Filiale mit zwei Lagern verknüpfen (eines als Default) und prüfen, ob genau das Default-Lager zurückgegeben wird.
Konsolidierungshinweis: Schnittstelle zum Cluster Organisationsstruktur/Filialen (nicht Bestandteil dieses Clusters).
Status: belegt; [HYPOTHESE: fachliche Konsequenz bei fehlendem oder mehrfachem Default-Lager je Filiale (Datenintegrität IsDefault) nicht im Code ersichtlich]
---
### Kandidat LOG-29
Ebene: SwRS
Typ: Validierung
Akteur: Servicetechniker/Assetverwaltung (Gerätezustand)
Vorbedingung: Ein Gerätezustand (`BarcodeCondition`, z. B. Zustands-/Konditionsstufe eines Assets) wird angelegt oder geändert
Fakt: `BarcodeConditionBL.ValidateBarcodeCondition` erzwingt `0 <= ConditionInPercent <= 100`; ein deaktivierter Zustand (`IsActive == false`) darf nicht gleichzeitig Standard (`IsDefault`) sein; wird ein Zustand als Standard markiert, werden alle anderen automatisch als Nicht-Standard gesetzt (genau ein aktiver Default). Ist kein Default vorhanden und ein neuer aktiver Zustand wird angelegt, wird dieser automatisch zum Default.
Aussage: Das System soll sicherstellen, dass zu jedem Zeitpunkt höchstens ein aktiver Gerätezustand als Standardzustand markiert ist und der Prozentwert eines Zustands im gültigen Bereich 0-100 liegt.
Ergebnis: Konsistente, eindeutige Konditions-/Zustandsstammdaten für Assets/Geräte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Warehousing/BarcodeConditionBL.cs:20-80 (SaveOrUpdateBarcodeCondition, ValidateBarcodeCondition)
Prüfidee: Zweiten Zustand als Default markieren und prüfen, ob der vorherige Default automatisch zurückgesetzt wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat LOG-30
Ebene: SyRS
Typ: Schnittstelle (Kontext)
Akteur: Versandabwicklung
Vorbedingung: Ein Paket/eine Sendung wird an einen Versanddienstleister übergeben
Fakt: Im Quellbaum existieren dedizierte API-Integrationsprojekte `src/apis/Centron.Api.Gls` und `src/apis/Centron.Api.Shipcloud` für die Anbindung an die Versanddienstleister GLS sowie (über Shipcloud als Multi-Carrier-Aggregator) weitere Paketdienste. Diese wurden im Rahmen dieses Clusters nur oberflächlich referenziert, nicht tiefenanalysiert (Aufgabenstellung: Analyse durch anderen Agenten).
Aussage: Das System soll Sendungen über Schnittstellen zu externen Versanddienstleistern (GLS, weitere über Shipcloud) erzeugen und deren Status verfolgen können.
Ergebnis: Automatisierte Versandetikettenerstellung und Sendungsverfolgung.
Belege:
- [KONTEXT] src/apis/Centron.Api.Gls (Projektverzeichnis) - Begründung: Vorhandensein eines dedizierten API-Projekts belegt die Schnittstelle, Inhalt nicht im Detail geprüft.
- [KONTEXT] src/apis/Centron.Api.Shipcloud (Projektverzeichnis) - Begründung: analog.
Prüfidee: Detailanalyse der beiden API-Projekte (Statusmapping, Label-Erzeugung, Fehlerbehandlung) durch den zuständigen Speditions-/Schnittstellen-Agenten.
Konsolidierungshinweis: Nur als Platzhalter/Verweis - Detailauswertung liegt außerhalb dieses Clusters (siehe Aufgabenstellung).
Status: HYPOTHESE (Begründung fehlender Information: keine Tiefenanalyse der API-Projekte im Rahmen dieses Clusters durchgeführt)
---
## Abdeckung
**Gelesen (vollständig oder in wesentlichen Teilen):**
- src/backend/Centron.BL/Warehousing/StockManagement/ArticleStockBL.cs (vollständig)
- src/backend/Centron.BL/Logistics/Warehousing/StockBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/InventoryManagement/InventoryNewBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/CommissioningManagement/CommissioningBL.cs (vollständig, sehr klein)
- src/backend/Centron.BL/Production/ProductionBL.cs (vollständig)
- src/backend/Centron.BL/Production/ProductionOrderBL.cs (vollständig)
- src/backend/Centron.BL/Devices/AccountDeviceBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/StockManagement/StoragePlaceBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/StockManagement/StorageAreaBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/Commissions/OrderCommissionBL.cs (vollständig)
- src/backend/Centron.BL/Warehousing/Commissions/PartialCommissionOrderBL.cs (Kernteil, ca. 350 von >600 Zeilen)
- src/backend/Centron.BL/Warehousing/ArticleProduction/ArticleProductionBL.cs (Kernteile, Struktur- und Zeiterfassungslogik vollständig gelesen)
- src/backend/Centron.BL/Warehousing/BarcodeBL.cs (Auszug, erste ~120 Zeilen; Datei ist sehr groß)
- src/backend/Centron.BL/Warehousing/BarcodeConditionBL.cs (Auszug)
- src/backend/Centron.BL/Warehousing/ArticleBL.cs (gezielte Ausschnitte zu ScanBarcode/SN-Pflicht, negative Buchungsrechte; Datei ist sehr groß, >4000 Zeilen, nicht vollständig gelesen)
- src/backend/Centron.BL/Logistics/LogisticSettings/LogisticSettingsBL.cs (Auszug)
- src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs (nur per Grep referenziert, nicht vollständig gelesen)
- src/backend/Centron.BL/Sales/Receipts/DeliveryLists/ReceiptDeliveryListBL.cs (vollständig, sehr klein)
- src/backend/Centron.BL/Sales/Receipts/SupplierDeliveryLists/SupplierDeliveryListBL.cs (vollständig - leer/Platzhalter)
- Enums: BarcodeState.cs, InventoryState.cs, ReceiptState.cs, PartialCommissionOrderState.cs, InventoryArticle.cs (CloseState) - vollständig gelesen
**Nur oberflächlich referenziert (laut Aufgabenstellung nicht tiefenanalysiert):**
- src/apis/Centron.Api.Gls, src/apis/Centron.Api.Shipcloud (Versanddienstleister-Schnittstellen)
**Bewusst ausgelassen / nicht erreicht (Lücken):**
- src/backend/Centron.BL/Warehousing/ArticleManagement/* (AdditionalArticleBL, ArticleBranchAccountBL, ArticleEANCodeBL, ArticleFreeSpecificationBL, ArticleHistoryBL, ArticleImportBL, EnvironmentalProtectionBL, ProductFamilyBL, WorkSafetyBL) - nicht gelesen, potenziell weitere Anforderungen zu Artikelstammdaten/Umweltschutz/Arbeitssicherheit.
- src/backend/Centron.BL/Warehousing/ActionPriceBL.cs, ArticleLogBL.cs, ArticleUnitBL.cs, ArticleUnitHelper.cs, ArticleVariableBL.cs, ArticleVolumePricesBL.cs, ArticleWorkItemBL.cs, BarcodeHistoryBL.cs, CostCenterBL.cs, CostObjectBL.cs, External/*, GeneralArticleBL.cs, SecondStockArticleBL.cs, TaxBL.cs, InventoryManagement/MaterialGroupBL.cs, StockManagement/PartListArticleBL.cs - nicht gelesen (Zeit-/Umfangsgründe); primär Kalkulations-/Stammdatenthemen, geringeres Risiko fachlich zentraler Prozessregeln.
- ArticleBL.cs wurde nur gezielt (Grep-gestützt) an einzelnen Stellen gelesen, nicht komplett; die Datei ist mit >4000 Zeilen der zentrale, aber sehr umfangreiche Artikel-Manager - weitere Kandidaten (v.a. zu Preisfindung, Materialgruppen-Constraints, Mietartikel/Portalartikel-Sonderlogik ab Zeile ~1270-1310) sind dort zu erwarten und wurden nicht vollständig gehoben.
- Centron.Entities/Centron.DAO wurden nicht gezielt nach DB-Constraints (Check Constraints, Trigger) für Bestandstabellen (`ARTIK`, `NebenlagerArtikel`) durchsucht; Aussagen zur Negativbuchung (LOG-13) beruhen nur auf Rechte-Flags, nicht auf verifizierten DB-seitigen Schranken.
- DeliveryListSpecificLogic / DeliveryListBL (Sales/CustomerAssets/DeliveryLists) wurden nicht gelesen; ein klassischer Lieferschein-Statusautomat (analog ReceiptState: Active/Completed/Canceled, gefunden in src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs) konnte daher nur oberflächlich über ReceiptState referenziert, nicht im Detail für Lieferscheine nachgewiesen werden - potenzielle Lücke, ggf. Überschneidung mit Auftrags-/Vertriebscluster.
- ArticleProductionBL.cs wurde nicht vollständig gelesen (Datei umfasst weitere Bereiche zu ArticleProductionOrderStepInfo, DataRecording-Filterausdrücke ab Zeile ~550+), die für Detailanforderungen zur Fertigungsauftrags-Datenerfassung relevant sein könnten.
- Keine Analyse von XAML/UI-Schichten (WPF-Views) für Lager/Produktion; alle Befunde stammen aus der Business-Logic-Schicht (Centron.BL) und Interfaces/Entities. UI-Texte/Fehlermeldungen wurden nur so weit erfasst, wie sie direkt im BL-Code als String-Literale vorkommen.
@@ -0,0 +1,461 @@
# Rohbefunde Cluster CENTRONNEXUS (Ticket-/Helpdesk-Anwendung, ExternalHelpdesk-Anbindung)
Quelle: RRE an CentronERP (C#/WPF/XAML, MSSQL, Blazor-Host `CentronNexus`, `CentronNexus.Host`, `CentronNexus.OutlookAddIn`).
Alle Pfade relativ zu `C:\DEV\MasterArbeit\QuellCode\CentronERP`, sofern nicht anders angegeben.
---
### Kandidat NEX-01
Ebene: SyRS
Typ: Daten
Akteur: Support-Mitarbeiter, Kunde
Vorbedingung: Ein Ticket (`Helpdesk`-Entität) existiert.
Fakt: `Helpdesk.HelpdeskState` referenziert eine konfigurierbare Lookup-Tabelle `HelpdeskState` (kein fester Enum). Der Status "geschlossen" wird nicht hart codiert, sondern über eine ApplicationSetting bestimmt (`HelpdeskSettingsBL.GetClosedHelpdeskState()` / `HelpdeskStatusBL.GetClosedHelpdeskStatus()`), auf die u.a. `HelpdeskBL.CheckUserRigths`, `HelpdeskCloseBL`, `HelpdeskSearchBL`, `DataSecurityBL`, `ScheduleBL` zugreifen.
Aussage: Das System soll Ticket-Status als konfigurierbare, vom Administrator definierbare Statuswerte abbilden, wobei genau ein Status als "Ticket geschlossen" markierbar ist und systemweit als Referenz für Berechtigungs-, Auswertungs- und Automatisierungslogik dient.
Ergebnis: Flexible Status-Konfiguration statt starrer State-Machine; zentrale Sonderrolle "geschlossen".
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskState.cs:1-16 - Entität HelpdeskState (Lookup, kein Enum), Felder IsDeactivated, ServiceBoardWebColor, ServiceBoardWebIcon
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:433,489 - Vergleich `entity.HelpdeskState == new HelpdeskSettingsBL(Session).GetClosedHelpdeskState()`
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs:92,112,123,308 - mehrfache Verwendung von GetClosedHelpdeskState beim Schließen
Prüfidee: Testen, ob beim Ändern der "geschlossen"-Status-Zuordnung in den Einstellungen alle abhängigen Module (Rechteprüfung, Statistik, Eskalation) konsistent reagieren.
Konsolidierungshinweis: Verwandt mit NEX-02 (Statuswechsel-Historie), NEX-05 (Kundenfreigabe-Sonderstatus NULL).
Status: belegt
---
### Kandidat NEX-02
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ein bestehendes Ticket wird gespeichert (Update, kein Neuanlage).
Fakt: `HelpdeskBL.SetHelpdeskAction()` vergleicht beim Speichern den alten (`HelpdeskCompact.HelpdeskStateI3D`) mit dem neuen Status und erzeugt bei Abweichung automatisch einen `HelpdeskHistory`-Eintrag ("Status wurde geändert", inkl. alter und neuer Statusname) über `HelpdeskHistoryBL.SaveHelpdeskAction`. Dieselbe Methode protokolliert auch Änderungen am Fälligkeitsdatum und setzt dabei `EscalationLevel = 0` zurück.
Aussage: Das System soll bei jeder Statusänderung eines Tickets automatisch einen Historieneintrag mit altem und neuem Statusnamen erzeugen und bei Änderung des Fälligkeitsdatums die Eskalationsstufe zurücksetzen.
Ergebnis: Lückenlose Nachvollziehbarkeit von Statuswechseln; Eskalationszähler wird bei Fristverlängerung neutralisiert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:558-609 - Methode `SetHelpdeskAction`
Prüfidee: Ticket-Status ändern und prüfen, ob HelpdeskHistory-Eintrag mit korrektem Text erzeugt wird; Fälligkeitsdatum ändern und EscalationLevel prüfen.
Konsolidierungshinweis: Ergänzt NEX-01, NEX-08 (Eskalationsstufen).
Status: belegt
---
### Kandidat NEX-03
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket wird neu angelegt oder bearbeitet (Bearbeiter-/Editorenliste ändert sich).
Fakt: `HelpdeskBL.SaveHelpdeskEmployees()` synchronisiert die Editoren-Liste eines Tickets (`HelpdeskEditor`/`HelpdeskEditorSaveable`) gegen die übergebene Zielmenge: neue Mitarbeiter werden hinzugefügt, entfernte gelöscht. Ist die Zielliste leer, wird zwingend der aktuelle Benutzer als einziger Editor gesetzt ("Helpdesks always need at least 1 editor").
Aussage: Das System soll sicherstellen, dass jedem Ticket mindestens ein Bearbeiter (Editor) zugewiesen ist; wird keine Zuweisung übergeben, soll automatisch der ausführende Mitarbeiter als Bearbeiter gesetzt werden.
Ergebnis: Kein Ticket ohne Bearbeiter; Zuweisungsänderungen werden diffbasiert persistiert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:849-884 - Methode `SaveHelpdeskEmployees(Helpdesk, int[], AppUser)`, Kommentar Zeile 857-859
Prüfidee: Ticket ohne explizite Bearbeiterzuweisung speichern und prüfen, dass der anlegende Mitarbeiter automatisch als Editor gesetzt wird.
Konsolidierungshinweis: Zusammenhang mit NEX-04 (Zuweisungsbenachrichtigung) und NEX-11 (Abteilungs-Zuweisung).
Status: belegt
---
### Kandidat NEX-04
Ebene: SyRS
Typ: Schnittstelle
Akteur: Support-Mitarbeiter
Vorbedingung: Editorenliste eines Tickets ändert sich (Hinzufügen/Entfernen eines Bearbeiters).
Fakt: `NexusNotificationsBL.SaveForwardTicketNotifications()` vergleicht alte und neue Editorenliste eines `Helpdesk`; für jeden neu hinzugefügten Editor wird eine Benachrichtigung `NexusNotificationType.TicketAssigned`, für jeden entfernten `TicketUnassigned` erzeugt (außer für den ausführenden Benutzer selbst) und per `NotificationsHubHelper.SendNexusNotification` (Action-Delegate, an SignalR-Hub gebunden) in Echtzeit verteilt.
Aussage: Das System soll bei Zuweisung oder Entzug der Bearbeiterrolle eines Tickets die betroffenen Mitarbeiter (außer dem Verursacher) in Echtzeit per Push-Benachrichtigung informieren.
Ergebnis: Echtzeitbenachrichtigung bei Ticketzuweisung/-abgabe über NexusNotifications + Hub.
Belege:
- [PRIMÄR] src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:133-174 - Methode `SaveForwardTicketNotifications`
- [PRIMÄR] src/webservice/Centron.WebServices.Core/Entities/NexusNotifications/NexusNotificationType.cs:8-9 - `TicketAssigned = 11`, `TicketUnassigned = 12`
- [SEKUNDÄR] src/backend/Centron.BL/NexusNotifications/NotificationsHubHelper.cs:1-10 - statisches Action-Delegate als Hub-Kopplung (Dependency Inversion, Hub selbst nicht in diesem Cluster lokalisiert)
Prüfidee: Bearbeiter zu Ticket hinzufügen/entfernen, prüfen ob betroffene Mitarbeiter (nicht aber der Verursacher) eine TicketAssigned/TicketUnassigned-Notification erhalten.
Konsolidierungshinweis: Bündelt mit NEX-05 bis NEX-07 (weitere Notification-Typen) zu einer generischen "Notification-Engine"-Anforderung in der Konsolidierung.
Status: belegt
---
### Kandidat NEX-05
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter, Systemadministrator
Vorbedingung: Änderung an Priorität, Status, Beschreibung oder interner Notiz eines Tickets.
Fakt: `NexusNotificationsBL.SaveTicketChangedNotifications()` prüft eine Liste geänderter Properties (`changedProperties`) und löst je nach betroffenem Feld spezifische Benachrichtigungsmethoden aus: `SavePriorityChangedNotifications` (Typ `TicketPriorityChanged`, inkl. neuem Fälligkeitsdatum im Text), `SaveStatusChangedNotifications` (`TicketStatusChanged`), `SaveDescriptionChangedNotifications`/`SaveInternalNoteChangedNotifications` (`TicketChanged`, ohne informAll). Empfängerermittlung erfolgt über `SaveSimpleTicketNotifications`: alle aktuellen Editoren plus optional verantwortliche Person, abzüglich des Verursachers (außer `informAll=true`).
Aussage: Das System soll bei Änderungen an Priorität, Status, Beschreibung oder interner Notiz eines Tickets die zuständigen Bearbeiter und ggf. die verantwortliche Person automatisch benachrichtigen, mit feldspezifischem Benachrichtigungstext.
Ergebnis: Differenzierte Änderungsbenachrichtigung je Feldtyp.
Belege:
- [PRIMÄR] src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:253-318 - `SaveTicketChangedNotifications` und Feld-spezifische Methoden
- [PRIMÄR] src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:181-233 - Empfängerlogik `SaveSimpleTicketNotifications`
Prüfidee: Priorität eines Tickets ändern und prüfen, ob Benachrichtigungstext das neue Fälligkeitsdatum enthält; interne Notiz ändern und prüfen dass "informAll" nicht greift (Verursacher wird nicht benachrichtigt).
Konsolidierungshinweis: Teil der Notification-Engine-Gruppe (siehe NEX-04).
Status: belegt
---
### Kandidat NEX-06
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ein Kommentar wird zu einem Ticket erfasst.
Fakt: `NexusNotificationsBL.SaveCommentOnTicketNotifications()` extrahiert per Regex `\[(?<name>@[^\]]+):(?<id>\d+)\]` Mitarbeiter-Erwähnungen ("Mentions") aus dem Kommentartext, bestimmt zusätzlich alle Ticket-Editoren, den Autor eines referenzierten Ursprungskommentars sowie die verantwortliche Person als Empfänger und weist je nach Fall den Notification-Typ `MentionedInComment`, `CommentReceivedOnComment` oder `CommentReceivedOnTicket` zu. Der Verursacher wird von der Empfängerliste ausgeschlossen.
Aussage: Das System soll beim Kommentieren eines Tickets erwähnte Mitarbeiter (@Mention-Syntax) sowie alle Bearbeiter, den Autor eines referenzierten Kommentars und die verantwortliche Person differenziert benachrichtigen.
Ergebnis: Mention-basierte, kontextsensitive Kommentarbenachrichtigung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:320-383 - Methode `SaveCommentOnTicketNotifications`, Regex Zeile 329
Prüfidee: Kommentar mit `[@Mustermann:123]`-Syntax erfassen und prüfen, dass Mitarbeiter I3D 123 Notification vom Typ MentionedInComment erhält, nicht aber CommentReceivedOnTicket zusätzlich.
Konsolidierungshinweis: Teil der Notification-Engine-Gruppe (NEX-04).
Status: belegt
---
### Kandidat NEX-07
Ebene: SyRS
Typ: Schnittstelle
Akteur: Kunde, Support-Mitarbeiter
Vorbedingung: E-Mail oder Dokument wird einem Ticket zugeordnet.
Fakt: `NexusNotificationsBL.SaveEmailOnTicketNotifications()` erzeugt Notification-Typ `EmailReceivedOnTicket` mit `informAll: true` (informiert auch den Verursacher), `SaveDocumentOnTicketNotifications()` erzeugt `DocumentReceivedOnTicket` (ohne informAll). Beide nutzen den E-Mail-Betreff bzw. Dokumentnamen (auf 400 Zeichen gekürzt) als Notification-Text.
Aussage: Das System soll beim Eingang einer E-Mail oder eines Dokuments an einem Ticket alle zugewiesenen Mitarbeiter automatisch benachrichtigen, wobei bei E-Mail-Eingang auch der auslösende Benutzer selbst informiert wird.
Ergebnis: Automatische Information bei neuen Ticket-Anhängen/E-Mails.
Belege:
- [PRIMÄR] src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs:385-393 - `SaveEmailOnTicketNotifications`, `SaveDocumentOnTicketNotifications`
Prüfidee: E-Mail per Outlook-Add-In an Ticket anhängen (siehe NEX-14) und prüfen, dass Notification auch beim ausführenden Mitarbeiter selbst erscheint (informAll=true).
Konsolidierungshinweis: Teil der Notification-Engine-Gruppe (NEX-04); Bezug zu NEX-14 (Outlook E-Mail-Anhang).
Status: belegt
---
### Kandidat NEX-08
Ebene: SyRS
Typ: funktional
Akteur: Systemadministrator, Support-Mitarbeiter
Vorbedingung: Ticket mit gesetzter Priorität, Eskalationstyp konfiguriert (`eskalationTypen`, `TicketPriorityI3D`), Fälligkeitsdatum überschritten.
Fakt: `EscalationBL.DoEscalation()` liest offene Eskalationseinträge (`eskalationen` verknüpft mit `todoliste`/`hlpdsk_requests`, Filter `IsNull(hs.Status,0)=0`, d.h. Status noch nicht geschlossen) und berechnet über `CheckEskalationStage`/`ShouldEscalated` bis zu drei Eskalationsstufen (Stunden1-3, `EscalationSa`/`EscalationSo` für Wochenend-Berücksichtigung, Geschäftszeiten `GeschaeftsZeitVon/Bis`). Bei Fälligkeit wird `SendEscalation` aufgerufen, welches E-Mails an konfigurierbare Empfängergruppen sendet (`EscalationReceiversEnum`: Editor, Supervisor, Adviser, Manager je Eskalationsstufe individuell konfigurierbar über `Stage1Receivers`/`Stage2Receivers`/`Stage3Receivers`), danach wird `hlpdsk_requests.EscalationLevel` per Raw-SQL auf die erreichte Stufe gesetzt.
Aussage: Das System soll überfällige Tickets anhand priorisierungsabhängiger, mehrstufiger Eskalationsregeln (bis zu 3 Stufen, konfigurierbare Wartezeiten, Geschäftszeiten- und Wochenendlogik) automatisch erkennen, die konfigurierten Empfänger (Bearbeiter/Vorgesetzter/Kundenberater/Eskalationsverantwortlicher) per E-Mail benachrichtigen und die erreichte Eskalationsstufe am Ticket vermerken.
Ergebnis: Mehrstufige, zeitgesteuerte Eskalationsautomatik mit konfigurierbarem Empfängerkreis je Stufe.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/Escalation/EscalationBL.cs:223-298 - `DoEscalation`
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/Escalation/EscalationBL.cs:313-426 - `ShouldEscalated`, `CheckEskalationStage` (Geschäftszeit-/Wochenendberechnung)
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/Escalation/EscalationBL.cs:770-799,913-921 - `SetRecipients` (EscalationReceiversEnum je Stufe), `UpdateTicket` (EscalationLevel-Update per Raw-SQL)
- [KONTEXT] src/backend/Centron.Entities/Entities/CustomerArea/Support/Helpdesk.cs:126 - Feld `EscalationLevel` am Ticket
Prüfidee: Ticket mit Priorität und Eskalationstyp anlegen, Fälligkeitsdatum in Vergangenheit setzen, Eskalationslauf simulieren (`TestEscalation`) und prüfen, ob Stufe 1 korrekt berechnet und E-Mail an konfigurierte Empfänger versendet wird.
Konsolidierungshinweis: Eskalationsmechanismus ist generisch (auch für Angebote/Aufträge/Rechnungen nutzbar) - für RRE-Zwecke auf Ticket-Pfad (`CentronObjectKindNumeric.HelpdeskClass`) fokussiert; ggf. mit übergreifendem Eskalations-Cluster konsolidieren, falls ein anderer Agent dieses Thema global behandelt.
Status: belegt
---
### Kandidat NEX-09
Ebene: SwRS
Typ: Daten
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket wird neu angelegt, Priorität ist gesetzt/verändert, kein manuelles Fälligkeitsdatum vorhanden.
Fakt: `HelpdeskBL.GetDueDateFromPriority()` berechnet das Fälligkeitsdatum additiv aus `HelpdeskPriority.DueDateDelayInHours`, wobei außerhalb konfigurierter Geschäftszeiten (`OfficeHourFrom`/`OfficeHourTo`) auf den nächsten Geschäftstag verschoben wird; Samstage/Sonntage werden übersprungen, falls `EscalationSa`/`EscalationSo` der Priorität `false` sind.
Aussage: Das System soll das Fälligkeitsdatum eines Tickets automatisch aus der gewählten Priorität unter Berücksichtigung konfigurierter Geschäftszeiten und arbeitsfreier Wochenendtage berechnen, sofern kein Fälligkeitsdatum explizit gesetzt wurde.
Ergebnis: Automatische, prioritätsabhängige SLA-Fristberechnung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:780-827 - `GetDueDateFromPriority`
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:762-765 - Aufruf bei Ticket-Neuanlage in `DoUpdateDefaultHelpdeskFields`
Prüfidee: Ticket kurz vor Geschäftszeitende mit Priorität (DueDateDelayInHours > verbleibende Stunden) anlegen und prüfen, ob Fälligkeit korrekt auf nächsten Geschäftstag verschoben wird.
Konsolidierungshinweis: Grundlage für NEX-08 (Eskalation), da EscalationLevel bei DueDate-Änderung zurückgesetzt wird (NEX-02).
Status: belegt
---
### Kandidat NEX-10
Ebene: StRS
Typ: funktional
Akteur: Kunde (Web-Account), Support-Mitarbeiter
Vorbedingung: Kunde erstellt Ticket über CentronNexus-Weboberfläche (Web-Account-Login).
Fakt: `HelpdeskCustomerBL.SaveNewSimpleTicketWebAccount()` prüft für den Kundenaccount, ob "Freigabewesen" (`CustomerData.CustomerApprovalEnabledSBO`) aktiv ist. Ist es aktiv und der Benutzer kein `CUSTOMERADMINISTRATOR`, wird `ticket.HelpdeskState = null` gesetzt ("make sure the state is reseted, to have a normal flow of rejecting or accepting ticket"); ist Freigabewesen deaktiviert oder der Benutzer Administrator, wird sofort der konfigurierte Default-Status (`AppSettingsConst.HelpdeskAfterOpenDefaultState`) gesetzt. Ein Ticket mit `HelpdeskState == null` erscheint laut Code-Kommentar in `HelpdeskCustomerBL.SaveNewSimpleTicket` (Zeile 128-131) NICHT in der regulären Ticketliste, sondern gilt als rein interne Kundennotiz, bis ein Kunden-IT-Admin sie eskaliert.
Aussage: Das System soll es Kunden ermöglichen, neue Tickets über ein Kundenportal zu erstellen; ist für den Kunden ein internes Freigabeverfahren (Freigabewesen) aktiviert, soll ein neu erstelltes Ticket zunächst ohne sichtbaren Status (interne Vorstufe) angelegt und erst nach interner Freigabe für den Support sichtbar geschaltet werden.
Ergebnis: Zweistufiger Kunden-Ticket-Erstellungsprozess mit optionalem internen Freigabe-Gate.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:466-493 - Freigabewesen-Prüfung in `SaveNewSimpleTicketWebAccount`
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:126-141 - Kommentar/Logik zu HelpdeskState==null in `SaveNewSimpleTicket`
Prüfidee: Kundenkonto mit aktivem Freigabewesen ein Ticket anlegen lassen und prüfen, dass es nicht im Standard-Ticket-Board erscheint, bis ein interner Nutzer es freigibt (Statuszuweisung).
Konsolidierungshinweis: [HYPOTHESE-Ergänzung] Der konkrete "Freigabe"-Workflow-Schritt (welche Aktion setzt HelpdeskState final?) wurde in diesem Cluster nicht lokalisiert (evtl. Teil des CRM/Sales-Clusters). Mit dortigem Rechercheergebnis abgleichen.
Status: belegt; Freigabe-Zielaktion nicht vollständig lokalisiert (siehe Konsolidierungshinweis)
---
### Kandidat NEX-11
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter, Systemadministrator
Vorbedingung: Ticket wird aus einer Vorlage (`TicketPattern`) erzeugt, Vorlage referenziert eine Abteilung.
Fakt: `HelpdeskCustomerBL.AssignEditorsFromDepartment()` ersetzt die Standard-Editorenliste (die sonst nur den Ticket-Ersteller enthält) durch alle Mitarbeiter der in der Vorlage (`TicketPattern.DepartmentI3D`) hinterlegten Abteilung (`EmployeeDepartmentBL.GetEmployeeIDsFromDepartment`).
Aussage: Das System soll bei der Ticketerstellung über eine vordefinierte Vorlage (Ticket-Pattern) mit hinterlegter Abteilung automatisch alle Mitarbeiter dieser Abteilung als Bearbeiter zuweisen und dabei die Standard-Editorenzuweisung überschreiben.
Ergebnis: Regelbasierte, abteilungsbezogene Massen-Zuweisung von Bearbeitern bei Vorlagen-basierter Ticketerstellung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs:109-111,238-256 - `AssignEditorsFromDepartment`
Prüfidee: Ticket über Vorlage mit hinterlegter Abteilung X anlegen und prüfen, dass alle aktiven Mitarbeiter der Abteilung X (und nur diese) als Editoren gesetzt werden.
Konsolidierungshinweis: Ergänzt NEX-03 (Mindest-Editor-Regel) und NEX-13 (Auto-Ticket-Vorlagen bei Bestellungen, aus docs/features).
Status: belegt
---
### Kandidat NEX-12
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter (Web-Konfiguration)
Vorbedingung: Automatische Ticketerstellung aus Bestellungen ist konfiguriert; mehrere Vorlagen (`HelpdeskCreationTemplate`) sind angelegt.
Fakt: Laut Feature-Dokumentation verwaltet `HelpdeskCreationTemplateBL` Vorlagen für die automatische Helpdesk-Erstellung aus Bestellpositionen, mit Business-Regeln: nur eine Vorlage kann gleichzeitig `IsStandard=true` sein; die aktuell als Standard markierte Vorlage kann nicht gelöscht werden; Löschung erfolgt als Soft-Delete (`IsDeleted`). Felder je Vorlage: Typ, Kategorie/Unterkategorien, Priorität, Status, Bearbeiter, Verantwortlicher, `CreateSeparateTicketsMode` (Single/Group/Custom), `SendEmailToProcessor`, `CreateTicketForAll`, `OpenAfterwards`, `OnlyInternal`.
Aussage: Das System soll es erlauben, mehrere benannte Vorlagen für die automatische Ticketerstellung aus Bestellungen zu definieren, davon genau eine als Standardvorlage zu markieren, und beim Löschen einer als Standard markierten Vorlage die Aktion zu verweigern.
Ergebnis: Konfigurierbare, wiederverwendbare Presets für automatisierte Ticket-Erzeugung aus dem ERP-Bestellprozess.
Belege:
- [SEKUNDÄR] docs/features/automatic-helpdesk-creation-templates.md:159-172 ("Business Rules": nur eine Standardvorlage, Standardvorlage nicht löschbar, Soft-Delete) - Feature-Dokumentation, Code der Klassen HelpdeskCreationTemplateBL/-Maps in diesem Rechercheumfang nicht separat gegengelesen
- [KONTEXT] docs/features/automatic-helpdesk-creation-templates.md:373-406 - DB-Schema `HelpdeskCreationTemplate` mit Feldliste
Prüfidee: Zwei Vorlagen anlegen, eine als Standard setzen, Löschversuch der Standardvorlage durchführen und Fehlermeldung/Ablehnung prüfen; zweite Vorlage als Standard setzen und prüfen, dass automatisch nur noch diese `IsStandard=true` hat.
Konsolidierungshinweis: Ergänzt NEX-11 (Abteilungszuweisung bei Mustern); ggf. Überschneidung mit ERP-Bestellungs-Cluster (Trigger-Seite "aus Bestellung") - dort ggf. gegenprüfen.
Status: belegt (Dokumentationsbasis, Code nicht tiefengeprüft) - [HYPOTHESE] Exakte Implementierungsdetails (z.B. ob CreateSeparateTicketsMode/Custom tatsächlich Positionsauswahl unterstützt) sollten gegen HelpdeskCreationTemplateBL.cs verifiziert werden, diese Datei wurde in diesem Lauf nicht gelesen.
---
### Kandidat NEX-13
Ebene: SyRS
Typ: Schnittstelle
Akteur: Support-Mitarbeiter
Vorbedingung: Outlook-Add-In ist installiert und mit CentronERP verbunden; eine E-Mail ist im Vorschaufenster geöffnet.
Fakt: `ManageTicketTab.razor` (`ExtractTicketNumber`/`ExtractHelpdeskNumberFromSubject`) versucht, aus dem E-Mail-Betreff per Regex (`\d+`) eine Ticketnummer zu extrahieren. Primär wird ein konfigurierbares Schlüsselwort (`HelpdeskSettings.HelpdeskLocateKeyword`) und ein Suchradius (`HelpdeskLocateSearchWidth`) verwendet (Nummer vor oder nach dem Schlüsselwort, mit Prioritäts-/Distanzbewertung); als Fallback werden reservierte Wörter ("c-ticket", "helpdesk", "ticket") gesucht und die nächstgelegene Zahl im Betreff zugeordnet.
Aussage: Das System soll im Outlook-Add-In beim Öffnen einer E-Mail automatisch versuchen, anhand eines konfigurierbaren Schlüsselworts (oder ersatzweise reservierter Schlüsselwörter) und der nächstgelegenen Zahl im Betreff die zugehörige Ticketnummer zu erkennen und das zugehörige Ticket automatisch anzuzeigen.
Ergebnis: Automatisches Ticket-Matching im Outlook-Add-In basierend auf E-Mail-Betreff-Heuristik.
Belege:
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:311-337,368-411 - `OnParametersSetAsync`, `ExtractTicketNumber`, `GetKeywordDistance`
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:564-605 - Fallback `ExtractHelpdeskNumberFromSubject` mit reservierten Wörtern
Prüfidee: E-Mail mit Betreff "Re: Ticket 4711 - Anfrage" öffnen und prüfen, dass automatisch Ticket 4711 geladen wird; Betreff ohne erkennbares Schlüsselwort aber mit Zahl testen (Fallback-Pfad).
Konsolidierungshinweis: Ergänzt NEX-14 (Live-Update-Kanal), NEX-15 (E-Mail-Anhang an Ticket).
Status: belegt
---
### Kandidat NEX-14
Ebene: SyRS
Typ: Schnittstelle
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket ist im Outlook-Add-In geladen.
Fakt: `ManageTicketTab.SetupLiveUpdate()` registriert über `TicketUpdateService.ListenForTicketChanges(Helpdesk.I3D)` Live-Update-Handler für die Felder StatusI3D, PriorityI3D, TypeI3D, CategoryI3D, AddressContact, ResponsiblePersonI3D, EditorI3Ds, AdditionalText2, ShortDescription, Description, Version; Änderungen am Server (vermutlich über SignalR-Hub, analog zu NexusNotifications) aktualisieren die Anzeige im Add-In ohne manuellen Reload (`InvokeAsync(StateHasChanged)`).
Aussage: Das System soll Änderungen an einem im Outlook-Add-In angezeigten Ticket (Status, Priorität, Typ, Kategorie, Kontakt, Verantwortlicher, Bearbeiter, Kurz-/Langbeschreibung, Zusatztext, Version) in Echtzeit an das Add-In pushen, ohne dass der Anwender die Ansicht manuell aktualisieren muss.
Ergebnis: Echtzeit-Synchronisation des Ticket-Zustands zwischen Web/ServiceBoard und Outlook-Add-In.
Belege:
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:450-550 - `SetupLiveUpdate` mit vollständiger Feldliste
Prüfidee: Ticket im ServiceBoard-Web-Client bearbeiten (z.B. Status ändern), während dasselbe Ticket im Outlook-Add-In angezeigt wird, und prüfen, dass Statusanzeige ohne Neuladen aktualisiert wird.
Konsolidierungshinweis: [HYPOTHESE] Der konkrete Transportmechanismus (SignalR-Hub-Name, Verbindung zu `NotificationsHubHelper`) wurde nicht im Detail verifiziert - `TicketUpdateService`-Implementierung liegt außerhalb der gelesenen Dateien.
Status: belegt; Transportmechanismus als HYPOTHESE (Implementierungsdatei nicht gelesen)
---
### Kandidat NEX-15
Ebene: SyRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket ist im Outlook-Add-In geladen, E-Mail im Vorschaufenster geöffnet.
Fakt: Über die Aktion "E-Mail an Ticket anhängen" (`AddSelectedEmailToFetchedTicket`) wird das Wurzelverzeichnis (`DirectoryReferenceKind.RootDirI3D`) des Tickets ermittelt (`GetDirectoryReference`) und ein `AttachmentDialog` zum Hochladen der ausgewählten E-Mail geöffnet.
Aussage: Das System soll es dem Support-Mitarbeiter ermöglichen, eine im Outlook-Add-In ausgewählte E-Mail direkt dem Dokumentenverzeichnis eines geladenen Tickets hinzuzufügen.
Ergebnis: Direkte E-Mail-zu-Ticket-Dokumentenablage aus Outlook heraus.
Belege:
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:766-787 - `AddSelectedEmailToFetchedTicket`
Prüfidee: E-Mail im Outlook-Add-In auswählen, "Anhängen"-Aktion ausführen und im ServiceBoard prüfen, dass Dokument im Ticket-Wurzelverzeichnis erscheint.
Konsolidierungshinweis: Ergänzt NEX-07 (DocumentReceivedOnTicket-Notification wird vermutlich dadurch ausgelöst, in diesem Lauf nicht bis zum Aufrufer zurückverfolgt).
Status: belegt
---
### Kandidat NEX-16
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Outlook-Add-In zeigt Kontakt-/E-Mail-Kontext eines Kunden; Mitarbeiter-Favoritenliste ist gepflegt.
Fakt: `EmployeeFavorites.razor` erlaubt das Markieren von Mitarbeitern als Favoriten (`CentronService.CreateEmployeeFavorits`) und zeigt für jeden (Favoriten-)Mitarbeiter Live-Statistiken (`GetHelpdeskStatisticFromEmployee`: `AllOpenHelpdesks`, `HelpdesksInWork`, `HelpdesksClosedToday`, `NewHelpdesksFromToday`) als gestapelten Fortschrittsbalken an. Über den Button "Weiterleiten" wird das aktuelle Ticket per `CentronService.ForwardHelpdeskV3` an den gewählten Mitarbeiter weitergeleitet, inkl. optionalem Statuswechsel (`NewHelpdeskStateI3D`) gemäß konfigurierten Weiterleitungs-Einstellungen (`HelpdeskAfterForwardDefaultStateI3D`).
Aussage: Das System soll dem Support-Mitarbeiter im Outlook-Add-In eine Übersicht favorisierter Kollegen mit deren aktueller Ticket-Auslastung anzeigen und die direkte Weiterleitung des aktuellen Tickets inkl. automatischem Statuswechsel an einen ausgewählten Kollegen ermöglichen.
Ergebnis: Auslastungsbasierte, komfortable Ticket-Weiterleitung direkt aus Outlook.
Belege:
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/EmployeeFavorites.razor:280-323 - Statistikanzeige (`GetHelpdeskPercentage`, `OnExpandEmployeeAccordianItem`)
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/EmployeeFavorites.razor:366-416 - `ForwardNow` mit `ForwardHelpdeskRequestV3DTO`, `NewHelpdeskStateI3D`
Prüfidee: Ticket an favorisierten Mitarbeiter weiterleiten und prüfen, dass (a) Editorenliste den neuen Mitarbeiter enthält (siehe NEX-03/04), (b) Status gemäß konfiguriertem `HelpdeskAfterForwardDefaultStateI3D` gesetzt wird, (c) Outlook-Mail-Entwurf mit Ticketinhalt vorbereitet wird.
Konsolidierungshinweis: Kombiniert NEX-03 (Editor-Zuweisung), NEX-04 (Notification) und Statuswechsel (NEX-01/02) in einem UI-Workflow.
Status: belegt
---
### Kandidat NEX-17
Ebene: SyRS
Typ: Sicherheit
Akteur: Kunde (Web-Account)
Vorbedingung: Kunde ist über Web-Account eingeloggt, ruft ein Ticket ab.
Fakt: `HelpdeskBL.GetHelpdeskRequestWithRightCheck()` implementiert eine mehrstufige Sichtbarkeitsprüfung: `ShowHelpdeskRight.None/OnlyOwn/OnlyOwnBranch/All`. Für Web-Accounts wird zusätzlich zwischen Single- und Multi-Web-Account unterschieden (`WebAccountBL.IsMultiWebAccount`): bei Multi-Web-Accounts wird geprüft, ob der Kontakt aktiv verknüpft ist (`WebAccountContactLink.IsActive`), bei Single-Accounts direkter Abgleich von `ContactPerson.I3D`/`Customer.I3D` mit dem WebAccount. Zusätzlich gilt: Ist `helpdesk.IsOnlyInternalVisible = true`, wird das Ticket für Web-Account-Logins grundsätzlich als "nicht gefunden" behandelt (Zeile 140-143), unabhängig vom Rechtelevel.
Aussage: Das System soll den Zugriff auf Tickets für Kunden-Logins strikt auf eigene bzw. für den Web-Account freigegebene Tickets beschränken (Rechtestufen "nur eigene", "alle des Kunden") und als "nur intern sichtbar" markierte Tickets für Kunden-Logins vollständig verbergen.
Ergebnis: Mandantenfähige, mehrstufige Zugriffskontrolle auf Ticketebene inkl. Multi-Kontakt-Web-Accounts.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:140-231 - `GetHelpdeskRequest`, `GetHelpdeskRequestWithRightCheck`
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:233-291 - `GetLoggedInUserShowHelpdeskRight` (WebAccountRightsConst SHOWONLYOWNREQUESTS, WEBRIGHT_SHOWONLYNOTIFYTICKETS, SHOWALLEREQUESTS, CUSTOMERADMINISTRATOR)
Prüfidee: Als Web-Account mit Recht "nur eigene Anfragen" versuchen, ein fremdes Ticket per direkter I3D-URL abzurufen, erwartete Fehlermeldung "Kein Recht für diese Operation" bzw. "Ticket nicht gefunden" bei IsOnlyInternalVisible=true.
Konsolidierungshinweis: Grundlegend für StRS-Sicherheitsanforderung "Mandantentrennung"; ggf. mit übergreifendem Security-Cluster (WebAccount-Rechte) konsolidieren.
Status: belegt
---
### Kandidat NEX-18
Ebene: SwRS
Typ: Sicherheit
Akteur: Support-Mitarbeiter
Vorbedingung: Mitarbeiter hat das Recht `ASSIGN_HELPDESK_ONLY_TO_OWN_DEPARTMENTS`; verantwortliche Person eines Tickets wird geändert.
Fakt: `HelpdeskBL.CheckUserRigths()` prüft, falls das Recht gesetzt ist und `ResponsiblePerson` als "dirty" markiert ist (NHibernate `IsDirtyProperty`), ob die neue verantwortliche Person einer Abteilung angehört, der auch der ausführende Mitarbeiter angehört (`EmployeeDepartmentBL.GetDepartmentAsList`); andernfalls wird die Änderung mit Fehlermeldung abgelehnt.
Aussage: Das System soll optional einschränken können, dass ein Mitarbeiter die verantwortliche Person eines Tickets nur auf Mitglieder der eigenen Abteilung(en) setzen darf.
Ergebnis: Feingranulare, abteilungsbezogene Zuweisungsbeschränkung als Sicherheitsregel.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:454-463 - Abteilungsprüfung in `CheckUserRigths`
Prüfidee: Mitarbeiter mit gesetztem Recht versucht, verantwortliche Person aus fremder Abteilung zu setzen; erwartete Fehlermeldung "Die verantwortliche Person muss zu einer Ihrer Abteilungen gehören."
Konsolidierungshinweis: Ergänzt NEX-11 (automatische Abteilungszuweisung von Editoren) um eine manuelle Einschränkung für ResponsiblePerson.
Status: belegt
---
### Kandidat NEX-19
Ebene: SwRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket wird geschlossen (`HelpdeskCloseBL.CloseHelpdesk`).
Fakt: `HelpdeskCloseBL.CloseHelpdesk()` prüft zunächst über `CanCloseHelpdesk`, ob das Schließen zulässig ist, löscht anschließend alle offenen ToDo-Einträge des Tickets (`_toDoBL.DeleteHelpdeskToDos`) und setzt erst danach `HelpdeskState = closedState`. Die Methode nutzt `HelpdeskSettingsBL.GetClosedHelpdeskState()` als Zielstatus (siehe NEX-01).
Aussage: Das System soll beim Schließen eines Tickets zunächst dessen Zulässigkeit prüfen, alle noch offenen Wiedervorlagen (ToDo-Einträge) des Tickets automatisch entfernen und danach den konfigurierten "geschlossen"-Status setzen.
Ergebnis: Definierter Abschluss-Workflow inkl. Aufräumen abhängiger ToDo-Einträge.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs:120-140 - `CloseHelpdesk(AppUser, int, ...)`
Prüfidee: Ticket mit offener Wiedervorlage schließen und prüfen, dass die Wiedervorlage entfernt und der Status korrekt auf den konfigurierten "geschlossen"-Zustand gesetzt wird.
Konsolidierungshinweis: [HYPOTHESE] `CanCloseHelpdesk`-Regeln (z.B. Pflichtfelder, offene Timer) wurden in diesem Lauf nicht im Detail gelesen (Datei nur teilweise, Zeilen 1-140 von >300); genauere Ablehnungsgründe sollten nachrecherchiert werden.
Status: belegt; Detailregeln von CanCloseHelpdesk als HYPOTHESE (Datei nicht vollständig gelesen)
---
### Kandidat NEX-20
Ebene: SyRS
Typ: Schnittstelle
Akteur: Systemadministrator
Vorbedingung: ExternalHelpdesk-Anbindung für einen Kunden/Standort ist konfiguriert.
Fakt: Die Entität `ExternalHelpdeskConfiguration` (Felder `CustomerI3D`, `CustomerSiteI3D`, `TicketReleaseSystemEnabled`, `AllowHelpdeskCreation`, `AllowCloseHelpdesks`) wird über `ExternalHelpdeskConfigurationBL` verwaltet (Filterung nach I3Ds/CustomerI3D/CustomerSiteI3D, Speichern als Liste, Löschen per Filter). Die eigentliche Synchronisations-/Übertragungslogik zu einem externen Helpdesk-System wurde in den durchsuchten Verzeichnissen NICHT gefunden (nur Konfigurationsverwaltung).
Aussage: Das System soll pro Kunde bzw. Kundenstandort konfigurierbar machen, ob ein externes Ticket-Freigabesystem aktiv ist, ob externe Helpdesk-Ticketerstellung erlaubt ist und ob das externe System Tickets schließen darf.
Ergebnis: Kundenspezifische Freigabe-/Berechtigungsmatrix für externe Helpdesk-Integration.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/ExternalHelpdesk/ExternalHelpdeskConfiguration.cs:1-11 - Felddefinition
- [PRIMÄR] src/backend/Centron.BL/ExternalHelpdesk/ExternalHelpdeskConfigurationBL.cs:19-68 - CRUD/Filter-BL
- [SEKUNDÄR] src/webservice/Centron.WebServices.Core/Entities/ExternalHelpdesk/ExternalHelpdeskConfigurationDTO.cs:14-19 - identische Felder als DTO (Web-Service-Schnittstelle vorhanden)
Prüfidee: Konfiguration für einen Kunden mit `AllowCloseHelpdesks=false` anlegen und über die (nicht in diesem Cluster lokalisierte) externe Schnittstelle versuchen, ein Ticket zu schließen - erwartete Ablehnung.
Konsolidierungshinweis: [HYPOTHESE] Es wurde in `src/backend/Centron.BL/ExternalHelpdesk`, `Centron.WebServices.Core` (nur DTO) und den Startpunkten keine Business-Logik gefunden, die diese Flags tatsächlich AUSWERTET (z.B. beim Ticket-Erstellen/Schließen prüft). Fehlende Information: Wo/wie wird `AllowHelpdeskCreation`/`AllowCloseHelpdesks`/`TicketReleaseSystemEnabled` zur Laufzeit konsultiert? Nachrecherche in Controllern/WebServices außerhalb der vorgegebenen Startpunkte nötig.
Status: HYPOTHESE (Konfigurationsmodell belegt, Auswertungslogik nicht lokalisiert)
---
### Kandidat NEX-21
Ebene: SyRS
Typ: Daten
Akteur: Support-Mitarbeiter
Vorbedingung: Mitarbeiter legt eine eigene oder globale Ticket-Ansicht (Filter/Spalten) an.
Fakt: `NexusTicketViewBL` verwaltet `NexusTicketView`-Entitäten mit Unterstützung für persönliche Ansichten (`CreatedByI3D`+`CreatedByObjectKind`, getrennt für Employee/WebAccount da beide Bereiche denselben I3D-Zahlenraum teilen laut Code-Kommentar), globale/geteilte Ansichten (`IsGlobal`, `GlobalViewI3D` als Verweis auf die Quelle), Standard-Ansicht je Nutzer (`IsDefault`, exklusiv - beim Setzen einer neuen Default-Ansicht werden alle anderen zurückgesetzt) sowie Duplizieren, Umbenennen (inkl. Propagation an alle Referenzen einer globalen Ansicht) und Löschen (bei globaler Ansicht: entweder eigene Referenz löschen oder Konfiguration in eine private Kopie übernehmen).
Aussage: Das System soll es Support-Mitarbeitern ermöglichen, eigene und global geteilte Ticket-Ansichten (Filter/Konfiguration) zu erstellen, zu duplizieren, umzubenennen, als Standardansicht zu markieren (exklusiv je Benutzer) und zu löschen, wobei bei global geteilten Ansichten eine Umbenennung an alle referenzierenden Nutzer weitergegeben wird.
Ergebnis: Persönliches und organisationsweites Ticket-View-Management (vergleichbar mit gespeicherten Suchen/Filtern im Kanban-/Listen-Board).
Belege:
- [PRIMÄR] src/backend/Centron.BL/NexusTicketViews/NexusTicketViewBL.cs:121-235 - `RenameTicketView`, `SetTicketViewToDefault`, `DuplicateTicketView`, `DeleteGlobalView`, `AddGlobalViewAsOwn`
- [PRIMÄR] src/backend/Centron.BL/NexusTicketViews/NexusTicketViewBL.cs:16-43 - GetUserI3D/GetCreatedByObjectKind (Employee vs. WebAccount Unterscheidung)
Prüfidee: Globale Ansicht umbenennen und prüfen, dass alle privaten Referenzen (GlobalViewI3D-Verweise) automatisch den neuen Namen zeigen; Standardansicht wechseln und prüfen, dass exakt eine Ansicht `IsDefault=true` hat.
Konsolidierungshinweis: Eigenständiges SwRS-Feature, ggf. mit ServiceBoard/Kanban-Cluster (CachedTicketList) konsolidieren, falls dort ebenfalls behandelt.
Status: belegt
---
### Kandidat NEX-22
Ebene: StRS
Typ: funktional
Akteur: Support-Mitarbeiter
Vorbedingung: Ticket-Board (ServiceBoard) im Kanban-Modus, neues Ticket wird geöffnet/bearbeitet.
Fakt: Der Enum `HelpdeskAfterOpenAction { Reject, Accept }` im CachedTicketList-Modul deutet auf einen Annahme-/Ablehnungs-Workflow beim Öffnen neuer Tickets im ServiceBoard hin (analog zum in NEX-10 beschriebenen kundenseitigen Freigabewesen, hier vermutlich support-seitig).
Aussage: Das System soll es dem Support-Mitarbeiter ermöglichen, ein neu eingegangenes Ticket im ServiceBoard explizit anzunehmen oder abzulehnen.
Ergebnis: Annahme-/Ablehnungsschritt als Teil des Ticket-Eingangs-Workflows im Web-Board.
Belege:
- [PRIMÄR] src/nexus/CentronNexus/ServiceBoard/CachedTicketList/Enums/HelpdeskAfterOpenAction.cs:1-7 - Enum-Definition
Prüfidee: Neues Ticket im ServiceBoard öffnen, "Annehmen"/"Ablehnen"-Aktion ausführen und Auswirkung auf Status/Editorenliste dokumentieren.
Konsolidierungshinweis: [HYPOTHESE] Der Enum wurde isoliert gefunden; die konsumierende UI-/BL-Logik (wo `HelpdeskAfterOpenAction` ausgewertet wird) liegt außerhalb der gelesenen Dateien in diesem Lauf. Fehlende Information: konkreter Aufrufkontext, Auswirkung von Reject (Ticket löschen? Status zurücksetzen? Rückmeldung an Kunden?).
Status: HYPOTHESE (nur Enum-Fund, Verwendungskontext nicht verifiziert)
---
### Kandidat NEX-23
Ebene: SyRS
Typ: Schnittstelle
Akteur: Support-Mitarbeiter
Vorbedingung: Neues Ticket wird über Outlook-Add-In angelegt (`CreateNewTicket`-Komponente, referenziert in ManageTicketTab.razor).
Fakt: Der Button "Neues Ticket" (`CreateNewTicket`-Komponente) übergibt `AccountI3D`, `MailSubject` (aus der geöffneten E-Mail) als Parameter und löst nach Erstellung `OnTicketCreated` aus, welches per `HandleTicketCreated`/`UpdateTicketData` sofort die Detailansicht des neuen Tickets im Add-In lädt.
Aussage: Das System soll es ermöglichen, direkt aus dem Outlook-Add-In heraus ein neues Ticket für den im E-Mail-Kontext erkannten Kunden-Account zu erstellen, wobei der E-Mail-Betreff automatisch als Vorbelegung übernommen wird.
Ergebnis: Nahtlose Ticketerstellung aus dem E-Mail-Kontext ohne Kontextwechsel.
Belege:
- [PRIMÄR] src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor:50-57,218-225,844-847 - Einbindung `CreateNewTicket` mit `MailSubject`/`AccountI3D`, `HandleTicketCreated`
Prüfidee: E-Mail mit Betreff öffnen, "Neues Ticket" im Add-In anlegen, prüfen dass Betreff korrekt vorbelegt und Kunde aus E-Mail-Kontext korrekt zugeordnet wird.
Konsolidierungshinweis: Ergänzt NEX-13 (Betreff-Parsing) und NEX-10 (Ticket-Erstellungslogik allgemein). Die `CreateNewTicket`-Komponente selbst wurde in diesem Lauf nicht gelesen (liegt vermutlich in CentronNexus.Shared, außerhalb Startpunkte).
Status: belegt; Detailkomponente `CreateNewTicket` nicht gelesen (HYPOTHESE bzgl. exakter Feldvorbelegung)
---
### Kandidat NEX-24
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator
Vorbedingung: Integritätsprüfung von Ticketdaten (z.B. Migrations-/Wartungslauf).
Fakt: `HelpdeskBL` implementiert ein Fingerprint-Verfahren (`UpdateFingerprint`/`CreateFingerprint`/`ValidateFingerprint`, HMAC-artig mit festem Salt "Wow, you are really not supposed to decompile the c-entron source-code.") über `ChangedDate`, das bei jedem Speichern aktualisiert wird. `GetCountOfInvalidFingerprints()`/`CreateMissingFingerprints()` erlauben Audits bzw. Nachpflege fehlender/inkonsistenter Fingerprints.
Aussage: Das System soll für jedes Ticket bei jeder Änderung einen kryptografischen Fingerabdruck über das Änderungsdatum erzeugen und speichern, um nachträgliche Direktmanipulationen der Datenbank (unter Umgehung der Anwendungslogik) erkennbar zu machen.
Ergebnis: Manipulationserkennung auf Datenebene für Ticket-Datensätze.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs:966-1004 - Fingerprint-Region
Prüfidee: Ticket per Anwendung ändern (Fingerprint wird aktualisiert), anschließend `ChangedDate` per Direkt-SQL manipulieren und `GetCountOfInvalidFingerprints()` ausführen - erwartet: Datensatz wird als ungültig erkannt.
Konsolidierungshinweis: Eher generisches ERP-Datenintegritätsmuster als Nexus-spezifisch; ggf. mit übergreifendem Datensicherheits-Cluster konsolidieren, hier aber am Ticket-Beispiel dokumentiert.
Status: belegt
---
### Kandidat NEX-25
Ebene: StRS
Typ: nicht-funktional
Akteur: Support-Mitarbeiter, Systemadministrator
Vorbedingung: CentronNexus-Web-Anwendung wird betrieben (separater Host `CentronNexus.Host`, konfigurierbar über `CentronNexusSettingsDTO`).
Fakt: `CentronNexusBL` verwaltet zentrale Betriebseinstellungen: `CentronNexusUrl` (Basis-URL der Nexus-Instanz), `ServiceBoardOnlineUrl` (separate URL für das Web-Board, referenziert auch im Outlook-Add-In als Ziel-Link, siehe NEX-13/16-Kontext `serviceboard/ticket/{I3D}`), sowie `UseNexusForPublicWebForms` (Umschalter, ob öffentliche Webformulare über CentronNexus statt eines Altsystems bedient werden).
Aussage: Das System soll CentronNexus als eigenständig konfigurierbare Web-Anwendung mit eigener Basis-URL betreiben, wobei Systemadministratoren zentral festlegen können, ob öffentliche Web-Formulare (Kundenanfragen) über CentronNexus abgewickelt werden.
Ergebnis: CentronNexus als austauschbare, eigenständig adressierbare Webkomponente im Gesamtsystem CentronERP.
Belege:
- [PRIMÄR] src/backend/Centron.BL/CentronNexus/CentronNexusBL.cs:19-54 - `GetCentronNexusSettings`/`UpdateCentronNexusSettings`
Prüfidee: `UseNexusForPublicWebForms` umschalten und prüfen, dass öffentliche Formulare (z.B. Kontaktformular) danach tatsächlich CentronNexus statt Altsystem ansprechen.
Konsolidierungshinweis: Grundlegende Architektur-/Deployment-Anforderung; ggf. mit Web-Konfigurations-Cluster (WebAccountConfig, HostConfig) konsolidieren.
Status: belegt
---
## Abdeckung
**Gelesene Dateien (vollständig oder in wesentlichen Teilen):**
- src/backend/Centron.BL/CentronNexus/CentronNexusBL.cs
- src/backend/Centron.BL/ExternalHelpdesk/ExternalHelpdeskConfigurationBL.cs
- src/backend/Centron.BL/NexusNotifications/NexusNotificationsBL.cs (vollständig)
- src/backend/Centron.BL/NexusNotifications/NotificationsHubHelper.cs
- src/backend/Centron.BL/NexusTicketViews/NexusTicketViewBL.cs (vollständig)
- src/backend/Centron.BL/Sales/Support/HelpdeskBL.cs (vollständig, 1043 Zeilen)
- src/backend/Centron.BL/Sales/Support/HelpdeskCustomerBL.cs (vollständig, 805 Zeilen)
- src/backend/Centron.BL/Sales/Support/Escalation/EscalationBL.cs (Zeilen 1-931 von 1257; Rest ab 932 - v.a. `GetEscalationStatisticPreviewFromHelpdeskByEscalationID` und Folgemethoden - NICHT gelesen)
- src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs (nur Zeilen 1-140 von >300; Rest NICHT gelesen)
- src/backend/Centron.Entities/Entities/CustomerArea/Support/Helpdesk.cs, HelpdeskState.cs, HelpdeskEditor.cs, HelpdeskHistory.cs
- src/backend/Centron.Entities/Entities/ExternalHelpdesk/ExternalHelpdeskConfiguration.cs
- src/webservice/Centron.WebServices.Core/Entities/NexusNotifications/NexusNotificationType.cs
- src/nexus/CentronNexus.OutlookAddIn/Ticket/ManageTicketTab.razor (vollständig)
- src/nexus/CentronNexus.OutlookAddIn/Ticket/EmployeeFavorites.razor (vollständig)
- src/nexus/CentronNexus/ServiceBoard/CachedTicketList/Enums/HelpdeskAfterOpenAction.cs
- src/nexus/CentronNexus/Configuration/CustomerPortalConfig.cs
- docs/features/automatic-helpdesk-creation-templates.md (vollständig)
**Ausgelassene bzw. nur oberflächlich gestreifte Bereiche (bekannte Lücken):**
- `src/nexus/CentronNexus` (830+ .cs-Dateien insgesamt): nur ein kleiner Ausschnitt (ServiceBoard/CachedTicketList/Enums, Configuration) betrachtet; `ServiceBoard/CachedTicketList/Model/*` (Kanban-Buckets, Filter, TicketListItem, TicketView), `WebOffer`/`WebCart`, `Management/TicketPatterns`, `Settings/*`, `Office/*`, `DocumentSigning/*` NICHT im Detail gelesen.
- `src/nexus/CentronNexus.Host`: nur Program.cs als Vorhandensein registriert, Inhalt NICHT gelesen (SignalR-Hub-Konfiguration, Middleware, Auth-Pipeline unbekannt).
- `src/nexus/CentronNexus.OutlookAddIn`: nur `Ticket/*` (2 von vielen Unterordnern: Belege, CRM, Customer, Document, Model, OfficeDialog, Shared) gelesen. `CreateNewTicket`-Komponente (referenziert in ManageTicketTab.razor) NICHT lokalisiert/gelesen.
- `src/backend/Centron.BL/ExternalHelpdesk`: enthält nur 1 BL-Datei (reine CRUD-Konfigurationsverwaltung); die tatsächliche Synchronisations-/Übertragungslogik zu einem externen Ticketsystem sowie die Laufzeit-Auswertung der Flags `AllowHelpdeskCreation`/`AllowCloseHelpdesks`/`TicketReleaseSystemEnabled` wurde NICHT gefunden (evtl. in Controllern/WebServices außerhalb der vorgegebenen Startpunkte, oder das Feature ist nur teilweise implementiert/vorbereitet).
- `HelpdeskCreationTemplateBL.cs`, `HelpdeskCreationTemplateWebServiceBL.cs`, `AutoHelpdeskCreationOrderSettingsViewModel.cs` (referenziert in docs/features/automatic-helpdesk-creation-templates.md) wurden NICHT direkt gelesen; NEX-12 basiert ausschließlich auf der Feature-Dokumentation (SEKUNDÄR-Beleg).
- `HelpdeskStatusBL.cs`, `HelpdeskSettingsBL.cs`, `HelpdeskSearchBL.cs`, `UpdateHelpdeskBL.cs`, `HelpdeskConnectionNumberBL.cs`, `HelpdeskPatternBL.cs`, `HelpdeskSendMailBL.cs` wurden nur über Grep-Treffer referenziert, nicht vollständig gelesen - enthalten vermutlich weitere Status-/Zuweisungs-/Mail-Regeln.
- `TicketUpdateService` (Live-Update-Client im Outlook-Add-In, siehe NEX-14) - Implementierung nicht lokalisiert/gelesen.
- Datenbankschema/Migrationsskripte (`hlpdsk_requests`, `hlpdsk_status`, `hlpdsk_request_bearbeiter`, `eskalationen`, `eskalationTypen`) nur indirekt über Raw-SQL-Strings in EscalationBL erschlossen, keine direkte Schemaprüfung (z.B. CREATE-TABLE-Skripte) durchgeführt.
- Rechte-Konstanten (`WebAccountRightsConst`, `UserRightsConst.Sales.Customer.Helpdesk.*`) wurden nur an Verwendungsstellen zitiert, nicht vollständig aufgelistet.
**Ungeklärte/offene Punkte für Konsolidierung (siehe auch [HYPOTHESE]-Markierungen oben):**
1. Wo genau greift der externe Helpdesk (ExternalHelpdesk) technisch auf CentronERP zu (REST-Endpunkt? Webhook? Polling?) - NEX-20.
2. Konkreter Freigabe-Workflow-Schritt, der ein Ticket mit `HelpdeskState == null` final in einen sichtbaren Status überführt - NEX-10.
3. Verwendungskontext von `HelpdeskAfterOpenAction` (Reject/Accept) - NEX-22.
4. Exakter Transportmechanismus von `TicketUpdateService` (Live-Update im Add-In) - NEX-14.
@@ -0,0 +1,756 @@
# Rohbefunde Cluster VERTRIEB & EINKAUF (SALES)
Quelle: `C:\DEV\MasterArbeit\QuellCode\CentronERP` (nur gelesen, nicht verändert)
RRE-Cluster: Angebote, Aufträge, Bestellungen, Produktmatrix/Konfiguration, Handelsware/Warenpools
Architektur-Hinweis: Angebote, Aufträge, Lieferscheine, Rechnungen, Gutschriften, Abhollisten, Verträge, Bestellungen (Lieferant),
Wareneingänge, Lieferanten-Rechnungen/-Gutschriften sind als polymorphes "Receipt"-System (`IReceiptBase`, `ReceiptBL`,
`IReceiptSpecificLogic`, je eine `*SpecificLogic`-Klasse pro Belegart) implementiert. Zentrale Speicher-/Validierungspipeline:
`Centron.BusinessLogic.Sales.Receipts.ReceiptBL.SaveReceipt<T,TReceiptItem>()`
(`src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs`, ca. 11.400 Zeilen).
---
### Kandidat SALES-01
Ebene: SyRS
Typ: funktional (Zustandsautomat)
Akteur: Vertrieb, Einkauf, System
Vorbedingung: Ein Beleg (Angebot, Auftrag, Bestellung, Lieferschein, Rechnung, Gutschrift, Abholliste, Vertrag) existiert.
Fakt: Alle Belegarten teilen sich denselben Status-Enum `ReceiptState` mit genau drei Werten: Active ("offen"),
Completed ("abgeschlossen"), Canceled ("storniert").
Aussage: Das System soll für alle Belegarten (Angebote, Aufträge, Bestellungen etc.) einheitlich genau die drei Zustände
"offen", "abgeschlossen" und "storniert" unterstützen.
Ergebnis: Einheitlicher, belegartübergreifender Lebenszyklus-Zustand als Basis für Reporting, Auto-Close-Logik und Weiterleitung.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 - enum ReceiptState { Active=1 "offen", Completed=2 "abgeschlossen", Canceled=3 "storniert" }, per [Description]-Attribut belegt und im gesamten Receipt-Framework verwendet.
Prüfidee: Zustandsübergänge (offen→abgeschlossen, offen→storniert, Reaktivierung) je Belegart in UI/DB nachvollziehen.
Konsolidierungshinweis: Basis für SALES-04, SALES-05 (Auto-Close-Logik), SALES-13 (Warenkorb-Status als Sonderfall).
Status: belegt
---
### Kandidat SALES-02
Ebene: SyRS
Typ: funktional (Workflow/Belegkette)
Akteur: Vertrieb
Vorbedingung: Ein Angebot mit Positionen liegt vor.
Fakt: `OfferSpecificLogic.CanBeForwardedFrom()` liefert ein leeres Array (Angebote sind Startpunkt der Kette),
`CanBeForwardedInto()` liefert `{OrderClass, DeliveryListClass, InvoiceClass}`.
`OrderSpecificLogic.CanBeForwardedFrom()` liefert `{OfferClass}`, `CanBeForwardedInto()` liefert
`{DeliveryListClass, InvoiceClass, ContractClass}`.
Aussage: Das System soll ein Angebot nur in Auftrag, Lieferschein oder Rechnung weiterleiten lassen, und einen Auftrag
nur aus einem Angebot heraus erzeugen sowie nur in Lieferschein, Rechnung oder Vertrag weiterleiten lassen.
Ergebnis: Erzwungene, belegartspezifische Vorwärtsverkettung (Belegfluss) im Vertriebsprozess.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:313-314 - CanBeForwardedFrom()=[], CanBeForwardedInto()=[OrderClass, DeliveryListClass, InvoiceClass]
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:256-257 - CanBeForwardedFrom()=[OfferClass], CanBeForwardedInto()=[DeliveryListClass, InvoiceClass, ContractClass]
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:1350-1375 - CanForwardReceiptsInto() schneidet die erlaubten Zielarten über alle ausgewählten Quellbelege.
Prüfidee: Versuch, einen Auftrag direkt (ohne Angebot) oder ein Angebot aus einer Rechnung zu erzeugen, muss von der UI verhindert werden.
Konsolidierungshinweis: Ergänzt durch SALES-03 (Einkaufsseite).
Status: belegt
---
### Kandidat SALES-03
Ebene: SyRS
Typ: funktional (Workflow/Belegkette)
Akteur: Einkauf
Vorbedingung: Eine Bestellung (SupplierOrder) existiert.
Fakt: `SupplierOrderSpecificLogic.CanBeForwardedFrom()` liefert ein leeres Array, `CanBeForwardedInto()` liefert
ausschließlich `{SupplierDeliveryList}`. `CanInsertNewAndExternalArticles()=false`, `SupportsMultipleBranches()=false`.
Aussage: Das System soll eine Lieferantenbestellung ausschließlich in einen Wareneingang (SupplierDeliveryList)
weiterleiten lassen und keine neuen/externen Artikel direkt in der Bestellung anlegen lassen; eine Bestellung
ist genau einer Filiale zugeordnet.
Ergebnis: Eingeschränkte, kontrollierte Beschaffungskette (Bestellung → Wareneingang) ohne Freitext-Artikelanlage.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:296-298 - CanBeForwardedFrom()=[], CanBeForwardedInto()=[SupplierDeliveryList]
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:291-294,633-636 - CanInsertNewAndExternalArticles()=false, SupportsMultipleBranches()=false
Prüfidee: Prüfen, ob UI das Anlegen neuer Artikel in der Bestellmaske tatsächlich unterbindet.
Konsolidierungshinweis: Gegenstück zu SALES-02.
Status: belegt
---
### Kandidat SALES-04
Ebene: SwRS
Typ: funktional (Konfigurierbare Geschäftsregel)
Akteur: Vertrieb, System
Vorbedingung: Ein Angebot wird gespeichert, dessen Positionen (teilweise) in Folgebelege übernommen wurden.
Fakt: `OfferSpecificLogic.CustomAutomaticallyCloseReceiptLogic()` liest die Einstellung
`AppSettingsConst.CloseOfferAutomatically` mit drei Werten: 1=nie schließen, 2=schließen sobald irgendeine
Position teilweise übernommen wurde, 3=erst schließen wenn alle Positionen vollständig übernommen wurden
(Menge >= QuantityComplete für jede Position).
Aussage: Das System soll konfigurierbar steuern, ob und wann ein Angebot automatisch auf "abgeschlossen" gesetzt wird,
nachdem seine Positionen in Aufträge/Lieferscheine/Rechnungen übernommen wurden.
Ergebnis: Administrierbare Auto-Close-Regel für Angebote, verhindert manuelles Nachpflegen des Angebotsstatus.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:245-281 - Switch über AppSettingsConst.CloseOfferAutomatically (1/2/3), inkl. Berechnung der je Position bereits verarbeiteten Menge via NamedQuery GetQuantityProcessedForOffer.
Prüfidee: Setting auf jeden der drei Werte stellen und Teil-/Vollübernahme eines Angebots in einen Auftrag testen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-05
Ebene: SwRS
Typ: funktional (Geschäftsregel)
Akteur: Vertrieb, System
Vorbedingung: Ein Auftrag wird gespeichert bzw. sein Ursprungsbeleg (Angebot) aktualisiert.
Fakt: `OrderSpecificLogic.CanBeAutomaticallyOpened()` verweigert automatisches Wiederöffnen, wenn der Benutzer den
Status zuvor manuell geändert hat (`AutoCloseOrOpenSituation.SaveReceiptUserChangedStateManually` → false),
erlaubt es aber in allen anderen Fällen; `CanBeAutomaticallyClosed()` liefert für Aufträge generell `true`.
Bei Angeboten ist es umgekehrt: `CanBeAutomaticallyOpened()=false` immer, `CanBeAutomaticallyClosed()` nur bei
`UpdateOriginReceipt`, nicht beim Speichern selbst.
Aussage: Das System soll eine manuelle Statusänderung durch den Sachbearbeiter respektieren und einen Beleg nicht
automatisch wieder öffnen, wenn der Nutzer ihn bewusst geschlossen hat; automatisches Öffnen/Schließen soll
je Belegart unterschiedlich (Auftrag: ja, Angebot: eingeschränkt) erlaubt sein.
Ergebnis: Konsistentes Zusammenspiel aus automatischer und manueller Statuspflege ohne Überschreiben bewusster Nutzerentscheidungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:233-240 - CanBeAutomaticallyOpened/Closed für Order
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:288-297 - CanBeAutomaticallyOpened/Closed für Offer, mit Kommentar "When saving a Offer, it should not get automatically closed"
Prüfidee: Auftrag manuell schließen, dann Ursprungsangebot ändern → Auftrag darf nicht automatisch wieder öffnen.
Konsolidierungshinweis: Ergänzt SALES-01, SALES-04.
Status: belegt
---
### Kandidat SALES-06
Ebene: SyRS
Typ: funktional / Daten
Akteur: Vertrieb, Kunde
Vorbedingung: Ein Kundenauftrag (Order) wird gespeichert.
Fakt: `OrderSpecificLogic.PurchaseOrderNumberIsRequired()=true` (im Gegensatz zu Offer/SupplierOrder, wo `false`).
`ReceiptBL.CheckIfPurchaseOrderNumberIsNeeded()` erzeugt Fehler "Bitte tragen Sie eine Bestellnummer ein."
nur wenn zusätzlich `customer.PurchaseOrderNumberRequiered` gesetzt ist.
Aussage: Das System soll bei Aufträgen die Erfassung einer Kunden-Bestellnummer nur dann zwingend verlangen, wenn dies
für den jeweiligen Kunden stammdatenseitig konfiguriert ist.
Ergebnis: Kundenindividuelle Pflichtfeldsteuerung für die Bestellnummer statt globaler Regel.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:581 - PurchaseOrderNumberIsRequired() => true
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9258-9276 - CheckIfPurchaseOrderNumberIsNeeded(): Fehlermeldung "Bitte tragen Sie eine Bestellnummer ein." (SaveReceiptErrorMissingField.PurchaseOrderNumber)
Prüfidee: Kunde ohne PurchaseOrderNumberRequiered-Flag: Auftrag ohne Bestellnummer speicherbar; mit Flag: Fehler erzwungen.
Konsolidierungshinweis: Zusammen mit SALES-07 (Dubletten-Check) zu konsolidieren.
Status: belegt
---
### Kandidat SALES-07
Ebene: SyRS
Typ: Daten (Konsistenzregel)
Akteur: Vertrieb, System
Vorbedingung: Eine Kunden-Bestellnummer wird bei einem Auftrag neu vergeben oder geändert.
Fakt: `ReceiptBL.CheckForDuplicatePurchaseOrderNumber()` prüft kundenübergreifend (`f.CustomerI3D == customerReceipt.CustomerI3D`)
über alle Belegarten mit `PurchaseOrderNumberIsRequired()==true`, ob dieselbe Bestellnummer bereits verwendet wurde
(ausgenommen Belege, aus denen der aktuelle Beleg selbst weitergeleitet wurde). Bei Fund wird die Meldung
"Die Bestellnummer \"{Nummer}\" wurde bereits verwendet." gesetzt.
Aussage: Das System soll beim Speichern eines Auftrags prüfen, ob dieselbe Kunden-Bestellnummer bereits für einen
anderen Beleg desselben Kunden verwendet wurde, und den Nutzer bei Dubletten warnen.
Ergebnis: Verhinderung von versehentlichen Doppelbestellungen/-erfassungen unter derselben Kundenreferenznummer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10802-10844 - CheckForDuplicatePurchaseOrderNumber(), inkl. Ausschluss der eigenen Weiterleitungs-Herkunftskette via GetForwardedFromHierarchy()
Prüfidee: Zwei Aufträge desselben Kunden mit identischer Bestellnummer anlegen → Warnmeldung erwartet; Weiterleitung Angebot→Auftrag mit gleicher Nummer darf nicht warnen.
Konsolidierungshinweis: Ergänzt SALES-06.
Status: belegt
---
### Kandidat SALES-08
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Vertrieb, Finanzen (Kreditkontrolle)
Vorbedingung: Ein Kundenbeleg (Auftrag/Lieferschein etc.) mit Positionen wird gespeichert und der Kunde hat ein Kreditlimit
(`CreditLimit`) hinterlegt.
Fakt: `ReceiptBL.CheckIfCustomerLimitIsReached()` summiert die (Netto- oder Brutto-) offenen Beträge aus allen
limitrelevanten Belegarten (`TakesPlaceInLimitCalculation()`) abzüglich bereits fakturierter Ursprungsbeträge.
Überschreitet der neue Betrag das verfügbare Limit, wird `ShowCustomerLimitExceededDialog` gesetzt mit Text
"Das Limit von {CreditLimit} {Währung} wurde um {Differenz} {Währung} überschritten. ... Möchten Sie den
Speichervorgang fortsetzen?" – überstimmbar über `data.SaveAlthoughCustomerLimitExceeded`.
Aussage: Das System soll beim Speichern limitrelevanter Kundenbelege das verfügbare Kreditlimit des Kunden prüfen und
bei Überschreitung eine explizite Bestätigung durch den Sachbearbeiter verlangen, bevor gespeichert wird.
Ergebnis: Kreditrisikokontrolle mit Übersteuerungsmöglichkeit (kein hartes Verbot, sondern Bestätigungsdialog).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:8636-8690 - CheckIfCustomerLimitIsReached(), Textbaustein und Bedingung data.SaveAlthoughCustomerLimitExceeded==false
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:356-370 - TakesPlaceInLimitCalculation(): Order zählt nur, wenn Setting OrderAndDeliveryListTakePlaceInCustomerLimitCalculation aktiv UND Beleg im Status Active ist.
Prüfidee: Kunde mit Limit 1000, Auftrag über 1500 anlegen → Dialog erscheint; nach Bestätigung speicherbar.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-09
Ebene: SyRS
Typ: Sicherheit / funktional (Vier-Augen-Prinzip)
Akteur: Vertrieb, Vorgesetzter/berechtigter Zweitnutzer
Vorbedingung: Eine Artikelposition in einem Kundenbeleg wird zu einem Nettopreis unterhalb des hinterlegten Artikel-Mindestpreises
(`Article.MinPrice`) gespeichert, und der aktuell angemeldete Nutzer besitzt nicht das Recht
`ALLOW_IGNORE_MINIMUM_PRICE`.
Fakt: `ReceiptBL.CheckArticleMinPrices()` sammelt alle Positionen unterhalb des Mindestpreises. Optional kann der
Speichervorgang mit `UsernameForArticleMinPrices`/`PasswordForArticleMinPrices` eine erneute Authentifizierung
eines zweiten Benutzers auslösen (`_authenticatorFactory`); nur wenn dieser zweite Benutzer das Recht
`ALLOW_IGNORE_MINIMUM_PRICE` besitzt, wird der Unterschreitungsbetrag akzeptiert, ansonsten bleibt die Position
in der Fehlerliste und der Speichervorgang schlägt fehl bzw. der Preis wird automatisch auf den Mindestpreis angehoben.
Aussage: Das System soll das Unterschreiten des Artikel-Mindestpreises verhindern, es sei denn der speichernde oder ein
per Zweitauthentifizierung autorisierter Benutzer besitzt das Recht, den Mindestpreis zu ignorieren.
Ergebnis: Vier-Augen-Kontrolle bei Preisnachlässen unterhalb der Mindestpreisgrenze, mit Recht-basierter Freigabe.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9036-9124 - CheckArticleMinPrices(), inkl. Re-Authentifizierung über zweiten Benutzer und Rechteprüfung UserRightsConst...Offer.ALLOW_IGNORE_MINIMUM_PRICE
Prüfidee: Position mit Preis < MinPrice ohne Recht speichern → Blockade/Dialog; mit zweitem autorisierten Login → Speichern erlaubt.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-10
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb, Behörden (Elektrogesetz/WEEE)
Vorbedingung: Ein Auftrag enthält eine Artikelposition, deren Artikelstamm `WEEENeeded=true` markiert ist.
Fakt: `ReceiptBL.CheckIfWeeeIsNeeded()` blockiert das Speichern mit "Der Beleg kann nicht gespeichert werden, da
einige Positionen keine WEEE Nummer haben.", sofern `IReceiptSpecificLogic.IsWeeeRequired()` für die Belegart
true liefert. `OrderSpecificLogic.IsWeeeRequired()=true`, `OfferSpecificLogic.IsWeeeRequired()=false`.
Aussage: Das System soll bei Aufträgen (nicht bei Angeboten) erzwingen, dass für WEEE-pflichtige Artikel eine
WEEE-Registrierungsnummer je Position erfasst wird, bevor der Beleg gespeichert werden kann.
Ergebnis: Gesetzeskonformität (Elektrogesetz) wird technisch am Auftrag, nicht am unverbindlichen Angebot erzwungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9393-9413 - CheckIfWeeeIsNeeded()
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:270 - IsWeeeRequired() => true
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:324 - IsWeeeRequired() => false
Prüfidee: WEEE-pflichtigen Artikel in Angebot ohne WEEE-Nummer speichern (ok) vs. in Auftrag weiterleiten ohne Nummer (Fehler).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-11
Ebene: SyRS
Typ: funktional (Web-Portal-Workflow)
Akteur: Kunde (Web-Account: Ersteller/"Creator"), Kunde (Web-Account: Prüfer/"Checker"), Kunde (Web-Account: Besteller/"Orderer")
Vorbedingung: Ein Kunde hat über das Web-Portal einen Warenkorb (technisch: ein Angebot mit `CartState`) erstellt.
Fakt: `ReceiptCartReleaseSystemBL` implementiert einen mehrstufigen Freigabeworkflow mit dem Enum `ReceiptCartState`
(Created → ReadyForCheck → Checked/DeclinedByChecker → Ordered/DeclinedByOrderer), rollenbasiert über
Web-Rechte `WEBRIGHT_WEBCART2_CHECK_CART` und `WEBRIGHT_WEBCART2_ORDER_CART`. Jeder Übergang erzeugt einen
Log-Eintrag und löst E-Mail-Benachrichtigungen an die jeweils betroffenen Rollen (Creator, Checker, Orderer,
interner Empfänger) aus. `ThrowIfReceiptCartStateIsNot()` verhindert Übergänge aus falschem Ausgangszustand
mit Meldung "Der Warenkorb befindet sich bereits an einem anderen Schritt des Freigabewesens.".
Aussage: Das System soll für Web-Bestellungen einen mehrstufigen Freigabeprozess (Erstellung → Prüfung → Bestellfreigabe)
mit rollenbasierten Rechten, Zustandsvalidierung und automatischer E-Mail-Benachrichtigung anbieten.
Ergebnis: Compliance-fähiger, nachvollziehbarer Bestell-Freigabeprozess für B2B-Web-Bestellungen (Vier-/Sechs-Augen-Prinzip
kundenseitig).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptCartReleaseSystemBL.cs:65-298 - Methoden ReadyCartForCheck/CheckerApproveCart/CheckerDeclineCart/OrdererApproveCart/OrdererDeclineCart + UpdateReceiptCartState() mit Zustands- und Rechteprüfung
- [SEKUNDÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptCartState.cs:24-39 - enum ReceiptCartState mit Kommentaren "In Prüfung"/"In Bestellung"
Prüfidee: Kompletten Workflow von Ersteller über Prüfer bis Besteller durchspielen inkl. Ablehnungs-/Nachbesserungspfad.
Konsolidierungshinweis: Hängt mit SALES-12 zusammen (fachliche Pflichtfelder vor Bestellauslösung).
Status: belegt
---
### Kandidat SALES-12
Ebene: SwRS
Typ: funktional (Validierung)
Akteur: Kunde (Web-Account: Besteller)
Vorbedingung: Ein geprüfter Warenkorb (`ReceiptCartState.Checked`) soll final bestellt werden.
Fakt: `ReceiptCartReleaseSystemBL.OrdererApproveCart()` wirft `ResultException` mit
"Bitte tragen Sie eine Bestellnummer ein!" wenn `customer.PurchaseOrderNumberRequiered` und keine
Bestellnummer im Warenkorb hinterlegt ist, sowie "Bitte tragen Sie eine Lieferadresse ein!" wenn
`offer.DeliveryAddress` leer ist – jeweils vor der eigentlichen Statusänderung und Weiterleitung in den Auftrag.
Aussage: Das System soll vor der finalen Bestellauslösung eines Web-Warenkorbs zwingend eine Lieferadresse verlangen und
– falls kundenseitig konfiguriert – eine Bestellnummer, bevor der Warenkorb in einen Auftrag umgewandelt wird.
Ergebnis: Verhinderung unvollständiger Web-Bestellungen (fehlende Lieferadresse/Bestellnummer).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptCartReleaseSystemBL.cs:177-198 - OrdererApproveCart(): Pflichtfeldprüfungen vor ForwardCartToOrder()
Prüfidee: Warenkorb ohne Lieferadresse final bestellen → Exception; mit Adresse → Auftrag mit IsDirectDeliveryPossible=true wird erzeugt.
Konsolidierungshinweis: Ergänzt SALES-11.
Status: belegt
---
### Kandidat SALES-13
Ebene: SyRS
Typ: funktional
Akteur: System, Vertrieb
Vorbedingung: Ein Web-Warenkorb wird final bestellt (`OrdererApproveCart`).
Fakt: Der erzeugte Auftrag erhält `order.IsDirectDeliveryPossible = true` und `order.Produced = offer.CartAssembleArticles`;
nach dem Speichern des Auftrags wird über `EnsureCartIsClosed()` sichergestellt, dass der Ursprungswarenkorb
(Angebot) im Status `ReceiptState.Completed` ist (falls er nicht bereits automatisch geschlossen wurde).
Aussage: Das System soll beim Abschluss eines Web-Warenkorb-Bestellvorgangs automatisch sicherstellen, dass sowohl der
resultierende Auftrag mit den korrekten Direktlieferungs-/Montage-Flags angelegt als auch der ursprüngliche
Warenkorb-Beleg als abgeschlossen markiert wird.
Ergebnis: Konsistenter Abschluss des Web-Bestellprozesses ohne verwaiste offene Warenkorb-Angebote.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptCartReleaseSystemBL.cs:193-198,356-381 - OrdererApproveCart()/EnsureCartIsClosed()
Prüfidee: Nach Bestellauslösung prüfen, dass Warenkorb-Angebot im Status "abgeschlossen" ist.
Konsolidierungshinweis: Ergänzt SALES-11, SALES-12.
Status: belegt
---
### Kandidat SALES-14
Ebene: StRS
Typ: funktional (Geschäftsziel CRM/Vertriebssteuerung)
Akteur: Vertrieb, Vertriebsleitung
Vorbedingung: Ein Beleg implementiert `IReceiptWithClassifications` (u.a. Angebote).
Fakt: `ReceiptBL.CheckIfClassificationIsNeeded()` verlangt drei Felder als Pflichtfelder für die
CRM-Klassifizierung: `ProjectEnd` (Projektende), `ProductGroupClassificationI3D` (Produktgruppe),
`ProbabilityClassificationI3D` (Abschlusswahrscheinlichkeit), sofern `data.IgnoreCallbacks==false`.
Ergänzend liefert `OfferSpecificLogic.ShouldBeSetCrmProjectByThreshold()=true`.
Aussage: Das System soll bei Angeboten eine CRM-Klassifizierung (Produktgruppe, Abschlusswahrscheinlichkeit, geplantes
Projektende) als verpflichtende Angaben zur Vertriebssteuerung/Forecasting erzwingen.
Ergebnis: Strukturierte Vertriebs-Pipeline-Daten (Sales-Funnel) als Basis für Umsatzprognosen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:9415-9440 (SetMessage-Aufrufe im weiteren Verlauf) - CheckIfClassificationIsNeeded()
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:631 - ShouldBeSetCrmProjectByThreshold() => true
Prüfidee: Angebot ohne Klassifizierung speichern → Fehler zu fehlenden Feldern ProjectEnd/ProductGroupClassification/ProbabilityClassification.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-15
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb, Kunde
Vorbedingung: Ein Auftrag wird angelegt/gespeichert, für den eine Anzahlung erforderlich ist.
Fakt: `DownPaymentBL.CreateDownPaymentInvoice()` erzeugt eine neue `ReceiptInvoice`, setzt
`invoice.DownPaymentForOrderI3D = parentReceiptOrder.I3D` und übernimmt Währung, Zahlungskondition,
Bestellnummer, Kostenstelle/-träger, Projektnummer und Filiale 1:1 vom Ursprungsauftrag; der Rechnungstitel wird
über `CreateInvoiceTitle("Anzahlung", parentReceiptOrder)` erzeugt.
Aussage: Das System soll aus einem Auftrag eine Anzahlungsrechnung erzeugen können, die referenziell mit dem
Ursprungsauftrag verknüpft bleibt und dessen Rahmenbedingungen (Zahlungskondition, Kostenstelle, Projekt) übernimmt.
Ergebnis: Nachvollziehbare Anzahlungsverwaltung mit Rückverfolgbarkeit zum Auftrag; Basis für spätere Verrechnung in
`ReceiptProgressionBL` (Down-Payment-SQL, `RechKopf.DownPaymentForOrderI3D`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/DownPayment/DownPaymentBL.cs:82-120 - CreateDownPaymentInvoice()
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptProgressionBL.cs:140-166 - CreateDownPaymentSql(): SQL-Verknüpfung RechKopf.DownPaymentForOrderI3D
Prüfidee: Anzahlungsrechnung aus Auftrag erzeugen, prüfen ob Verknüpfung in Belegverfolgung ("Progression") sichtbar ist.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-16
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb, Disposition
Vorbedingung: Ein Auftrag wird gespeichert.
Fakt: `OrderSpecificLogic.CreatesToDosWithTypes()` erzeugt automatisch bis zu vier Aufgaben-Typen:
`DeliveryDateOver` (Lieferdatum überschritten), `Commission` (Kommissionierung nötig, wenn Artikel
`Picking`-Flag hat und `QuantityPicked==0` und `order.Produced==false`), `Mounted` (Montage nötig, wenn
Artikel `Mounted`-Flag hat), `ReminderOrder` (Wiedervorlage). Angebote erzeugen nur `ReminderOffer`.
Aussage: Das System soll aus Auftragsdaten automatisch Aufgaben (To-Dos) für Liefertermin-Überwachung, Kommissionierung
und Montage ableiten, abhängig von artikelspezifischen Merkmalen (Picking, Mounted) und dem Produktionsstatus
des Auftrags.
Ergebnis: Automatisierte Prozesssteuerung (Aufgaben) ohne manuelles Anlegen von Wiedervorlagen durch den Innendienst.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:262-322 - CreatesToDosWithTypes(), CreatesCommisionToDoFor(), CreatesMountedToDoFor()
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:319-322 - CreatesToDosWithTypes() nur ReminderOffer
Prüfidee: Auftrag mit Picking-Artikel und QuantityPicked=0 anlegen → Kommissionierungs-To-Do muss entstehen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-17
Ebene: SwRS
Typ: funktional (Provisionsberechnung)
Akteur: Vertrieb, Vertriebsleitung
Vorbedingung: Ein Auftrag wird neu angelegt und `AppSettingsConst.OrderAutoProvisionIsActive` ist aktiv.
Fakt: `OrderSpecificLogic.GetEmployeeForAutoProvision()` wählt anhand der Einstellung `OrderAutoProvisionEmployee`
(Wertebereich 0-5) einen von sechs möglichen Kundenbetreuern (Adviser1I3D…Adviser6I3D) als Provisionsempfänger;
`GetAutoProvisionShare()` liefert den Provisionsanteil aus `OrderAutoProvisionPercent`.
Aussage: Das System soll bei aktivierter automatischer Provisionierung anhand konfigurierbarer Kundenbetreuer-Zuordnung
(bis zu 6 Betreuerrollen je Kunde) und eines Prozentsatzes automatisch einen Provisionsempfänger und -anteil
für neue Aufträge bestimmen.
Ergebnis: Automatisierte, konfigurierbare Provisionsverteilung ohne manuelle Zuordnung je Auftrag.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:513-548 - IsProvisionRequired(), AutoProvisionForNewReceipts(), GetEmployeeForAutoProvision(), GetAutoProvisionShare()
Prüfidee: Setting OrderAutoProvisionEmployee=2 (Adviser3) und Prozentsatz 10 setzen, neuen Auftrag anlegen, Provisionsempfänger/-anteil prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-18
Ebene: SyRS
Typ: Schnittstelle (EDI)
Akteur: Einkauf, Lieferant (EDI-System)
Vorbedingung: Zu einer bestehenden Bestellung liegt eine per EDI empfangene Auftragsbestätigung (EDI-Order-Confirmation) vor.
Fakt: `SupplierOrderBL.UpdateSupplierOrderWithEdiValues()` erzeugt zunächst eine neue Version der Bestellung, setzt
`supplierOrder.IsOrderConfirmed=true`, hängt die `SupplierReceiptNumber` an `OrderConfirmationNumber` an
(mit Duplikatsprüfung per IndexOf), und übernimmt je nach übergebenen Update-Flags Preis (`BasePrice`,
umgerechnet mit `CurrencyFactor`), Liefertermin und offene Menge aus den EDI-Positionsdaten; nach dem Speichern
werden die verarbeiteten EDI-Rohdaten (`EDIDocuments`) aus dem System entfernt und ins Dokumentenverzeichnis
der Bestellung verschoben (`RemoveEdiData`).
Aussage: Das System soll eingehende EDI-Auftragsbestätigungen automatisiert einer bestehenden Bestellung zuordnen und
darüber Bestätigungsstatus, Preis, Liefertermin und Menge je Position aktualisieren können, wobei jede
EDI-Übernahme eine neue Belegversion erzeugt und protokolliert wird.
Ergebnis: Automatisierte Bestellabwicklung mit Lieferanten über EDI ohne manuelle Doppelerfassung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderBL.cs:35-140 - UpdateSupplierOrderWithEdiValues(), RemoveEdiData()
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderBL.cs:136 - Protokolleintrag via ReceiptLogBL.CreateUpdatedSupplierOrderWithEdiValuesEntry()
Prüfidee: EDI-Bestätigung mit abweichendem Preis/Termin einspielen, neue Bestellversion und Log-Eintrag prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-19
Ebene: SyRS
Typ: funktional
Akteur: Einkauf, Lager
Vorbedingung: Eine Bestellung mit Direktlieferungs-Positionen (`IsDirectDeliveryPossible`) wird gespeichert und war zuvor
aus einem Kundenauftrag übernommen (`ReceiptOrderItemI3D`).
Fakt: `SupplierOrderSpecificLogic.UpdateOrderOriginDeliveryDate()` schreibt den (neuen) Liefertermin der
Bestellposition zurück auf die Position im Ursprungsauftrag (`AufPos.Lieferdatum`); wenn alle Artikelpositionen
des Auftrags (ohne Stücklisten-Kopfpositionen, `Expanded==null`) denselben Liefertermin haben, wird zusätzlich
der Liefertermin im Auftragskopf (`AufKopf.Lieferdatum`) aktualisiert.
Aussage: Das System soll bei Direktlieferungen den in der Lieferantenbestellung erfassten oder bestätigten Liefertermin
automatisch in den zugehörigen Kundenauftrag zurückspiegeln, sowohl auf Positions- als auch – bei Einheitlichkeit
– auf Kopfebene.
Ergebnis: Aktuelle, konsistente Lieferterminanzeige im Kundenauftrag ohne manuelle Doppelpflege bei Streckengeschäft/Direktlieferung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:392-465 - UpdateOrderOriginDeliveryDate(), aufgerufen aus AfterReceiptIsSaved()
Prüfidee: Direktlieferungs-Bestellung mit neuem Liefertermin speichern, prüfen ob Ursprungsauftrag automatisch aktualisiert wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-20
Ebene: StRS/SyRS
Typ: funktional (Bedarfsermittlung/Dispo)
Akteur: Einkauf
Vorbedingung: Artikel mit Lagerabbuchung (`Abbuchung='J'`) oder Pflichtbuchung (`IsObligatoryBooking`) sind in offenen
Aufträgen/Beständen unterbestellt.
Fakt: `OrderSuggestionListBL` liefert mehrere Bestellvorschlagslisten (BVL): `GetOrderSuggestionArticle`
(artikelbasiert inkl. Sonderartikel/Spezialvereinbarungen), `GetOrderSuggestionOrder`
(auftragsbasiert, filterbar nach Direktlieferung `Direktlieferung=1` und Mietportal-Sonderfall `isMietPortal`),
`GetOrderSuggestionWH` (lagerbasiert). `StoreSuggestionInfo()`/`RemoveDirectDelivery()` erlauben manuelle
Bearbeitung einzelner Auftragspositionen (Infotext, Direktlieferungs-Flag) direkt aus der BVL heraus.
Aussage: Das System soll dem Einkauf eine mehrdimensionale Bestellvorschlagsliste (je Artikel, je Auftrag, je Lager)
bereitstellen, die offene Bedarfe inklusive Direktlieferungs- und Mietportal-Sonderfällen konsolidiert und
eine direkte Bearbeitung einzelner Auftragspositionen (Infotext, Direktlieferung entfernen) ermöglicht.
Ergebnis: Zentrales Werkzeug zur Bedarfsbündelung/Disposition vor der eigentlichen Bestellauslösung an Lieferanten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:589-733 - GetOrderSuggestionArticle(), GetArticlePerItems(), GetOrderSuggestionOrder()
- [PRIMÄR] src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs:1039-1067 - StoreSuggestionInfo(), RemoveDirectDelivery()
- [KONTEXT] git log: "2fbbe1561e Ticket 148592: Mindestbestellmenge in BVL", "4e8dca6f3e Ticket 147996: BVL mit Teil-Direktlieferung", "f54e265bff Ticket 155192: Neue Artikeleigenschaft 'Bei BVL berücksichtigen'", "78e1854f60 BVL: CRMProjekt für Aufträge" - belegen kontinuierliche fachliche Weiterentwicklung der Bestellvorschlagsliste (Mindestbestellmenge, Teil-Direktlieferung, Artikel-Ausschlussmerkmal).
Prüfidee: BVL für Artikel mit offenem Bedarf aus mehreren Aufträgen aufrufen, Direktlieferungs-Flag einer Position entfernen und Persistenz prüfen.
Konsolidierungshinweis: Ergänzt SALES-19 (Direktlieferung), ggf. mit LOGISTIK-Cluster (Lagerabgleich) abzugleichen.
Status: belegt
---
### Kandidat SALES-21
Ebene: SwRS
Typ: funktional
Akteur: Einkauf, Buchhaltung
Vorbedingung: Ein Wareneingang/Lieferantenrechnung wird abteilungs-/filialübergreifend verarbeitet (Filiale der Bestellung
≠ Filiale des Auftrags).
Fakt: `SupplierOrderPerBranchBL` liefert per Rohsql (`sSqlCalcSelect`/`sSqlCalcFrom`) Kalkulationszeilen, bei denen
`ISNULL(flA.I3D,0) != ISNULL(flB.I3D, 0)` (Bestell-Filiale ungleich Auftrags-Filiale) sowie eine analoge Abfrage
für filialübergreifende Helpdesk-Zeitbuchungen (`sSqlTicketOrder`). `WriteExportDate()` markiert einzelne
Positionen (KalkPos/LiGutPos/hlpdsk_timer) nach Verarbeitung mit einem Exportdatum, damit sie bei künftigen
Abfragen nicht erneut erscheinen (`ExportDate Is Null`-Filter in `GetBasisCalcList`).
Aussage: Das System soll filialübergreifende Beschaffungs- und Leistungsvorgänge (Bestellung einer Filiale für einen
Auftrag einer anderen Filiale, inkl. filialübergreifender Zeiterfassung) identifizieren und für die
innerbetriebliche Verrechnung exportierbar/markierbar machen, ohne bereits exportierte Datensätze erneut zu liefern.
Ergebnis: Grundlage für filialinterne Leistungsverrechnung (interne Kostenumlage) bei dezentraler Organisation.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Purchasing/SupplierOrderPerBranchBL.cs:24-116 - sSqlCalcSelect/sSqlCalcFrom mit Filialvergleich, GetBasisCalcList()
- [PRIMÄR] src/backend/Centron.BL/Purchasing/SupplierOrderPerBranchBL.cs:145-183 - WriteExportDate()
Prüfidee: Bestellung in Filiale A für Auftrag in Filiale B abwickeln, prüfen ob Datensatz in SupplierOrderPerBranch-Liste erscheint und nach Export nicht erneut.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-22
Ebene: SyRS
Typ: Schnittstelle / Daten
Akteur: Einkauf, externe Handelsplattform (Warenpool/TradePool)
Vorbedingung: Import-Dateien mit Handelsware-Artikeldaten (XML) liegen vor.
Fakt: `TradePoolBL.StartTradeImport()` iteriert über eine Liste von Importdateien und ruft je Datei
`TradePoolXmlLogic.Initialize()` + `ImportTradeArticles()` auf. Die Trefferliste (`GetTradeArticleList`)
unterstützt Filterung nach Herstellercode, Beschreibung sowie klassifikatorisch nach Class/Subclass1/Subclass2
(`TradeArticleFilterOptions`).
Aussage: Das System soll Handelsware-/Warenpool-Artikeldaten aus externen XML-Importdateien einlesen und in einer
klassifizierten (Class/Subclass1/Subclass2), nach Hersteller und Beschreibung durchsuchbaren Artikeldatenbank
bereitstellen.
Ergebnis: Zentraler externer Artikelpool (Handelsware) als Datenquelle für Einkauf/Vertrieb, unabhängig vom internen Artikelstamm.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TradePool/TradePoolBL.cs:28-101 - StartTradeImport(), GetTradeArticleList(), enum TradeArticleFilterOptions {Class, Subclass1, Subclass2}
Prüfidee: XML-Importdatei mit neuen Handelsware-Artikeln einspielen, Sichtbarkeit/Filterung in der Trefferliste prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-23
Ebene: SyRS
Typ: Sicherheit
Akteur: Handelspartner/-kunde (Trade-Portal)
Vorbedingung: Ein externer Handelskunde meldet sich am Warenpool-Portal an.
Fakt: `TradePoolBL.AuthenticateUser()` vergleicht den mit `CryptoUtils.CreatePasswordHash(password, user.Salt)`
berechneten Hash gegen den gespeicherten `user.Password`; `SaveUser()` erzeugt beim Anlegen einen zufälligen
Salt (`CryptoUtils.CreateSalt(32)`) und speichert nur den Hash, nie das Klartextpasswort.
Aussage: Das System soll die Anmeldung von Handelspartnern am Warenpool-Portal über gesalzene Passwort-Hashes (kein
Klartext-Passwort in der Datenbank) authentifizieren.
Ergebnis: Grundlegender Passwortschutz für das separate Handelsware-/Warenpool-Kundenkonto-System.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TradePool/TradePoolBL.cs:147-183 - SaveUser() (Salt+Hash), AuthenticateUser() (Hash-Vergleich)
Prüfidee: Anmeldung mit falschem Passwort muss fehlschlagen; Datenbank darf kein Klartextpasswort enthalten (Review).
Konsolidierungshinweis: Ggf. mit Sicherheits-Cluster abzugleichen (Hash-/Salt-Verfahren global einheitlich?).
Status: belegt; Workaround möglich (Legacy: eigenes, vom zentralen Login-System losgelöstes Auth-Verfahren erkennbar an eigener TradeCustomerLogin-Entität statt AppUser/WebAccount)
---
### Kandidat SALES-24
Ebene: SwRS
Typ: funktional / Daten
Akteur: Vertrieb, Produktmanagement
Vorbedingung: Für einen Kunden soll die Relevanz von Produktkategorien/-produkten (Produktmatrix) bewertet werden.
Fakt: `ProductMatrixBL.GetProductMatrixCustomerProductRating()` legt bei fehlendem Rating automatisch einen neuen
Datensatz mit Startwert `CustomerProductMatrixRatingValue.Nothing` an; Änderungen werden über
`CustomerProductMatrixRatingChangeLog` historisiert (`SaveOrUpdateCustomerProductRating`).
`AddNotExistingProductRatingToAllCustomersQuery` (Named Query) legt fehlende Ratings für alle Kunden nach.
Aussage: Das System soll für jede Kombination aus Kunde und Produktmatrix-Produkt eine Bewertung führen (mit
neutralem Startwert, falls keine existiert) und Änderungen an dieser Bewertung historisch nachvollziehbar
protokollieren.
Ergebnis: Strukturierte Cross-/Upselling-Steuerung (Produktmatrix) je Kunde mit Änderungshistorie.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ProductMatrix/ProductMatrixBL.cs:165-192 - GetProductMatrixCustomerProductRating(), SaveOrUpdateCustomerProductRating()
- [SEKUNDÄR] src/backend/Centron.BL/ProductMatrix/ProductMatrixBL.cs:195-200 - AddNotExistingProductRatingToAllCustomers() (Named Query AddNotExistingProductRatingToAllCustomersQuery)
Prüfidee: Neuen Kunden anlegen, prüfen ob nach Ausführung des Nachlege-Jobs für alle Matrix-Produkte ein Rating mit Wert "Nothing" existiert; Rating ändern und Change-Log prüfen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-25
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb, Kalkulation
Vorbedingung: Eine Pauschal-/Flatrate-Artikelposition (Stücklisten-Kopf, `Article.MaterialGroup.BlanketMaterialGroup`) ist in
einem Auftrag vorhanden.
Fakt: `OrderBalanceBL.AddHelpdeskTimerToOrderPosition()` verlangt zwingend eine Pauschalposition
(`IsOrderAssetItemABalanceItem`), lehnt Zeiten ab, die bereits einem Auftrag/Lieferschein/einer Rechnung
zugeordnet sind ("Die Zeit wurde bereits einer Auftragsposition hinzugefügt.", "Diese Zeit wurde bereits zu
einem Lieferschein weiterverarbeitet.", "Diese Zeit wurde bereits zu einer Rechnung weiterverarbeitet.") sowie
geplante Zeiten ("Geplante Zeiten können nicht zu einer Pauschale hinzugefügt werden."), und bucht den Wert der
Zeit als Abzug auf eine automatisch erzeugte/gesuchte Ausgleichsposition (`balanceItem.Price -= partListItem.TotalPrice`).
Aussage: Das System soll Helpdesk-Zeiterfassungen nur einmalig und nur an bereits abgerechnete/verplante Zeiten
ausschließende, gültige Pauschalpositionen eines Auftrags anhängen können, wobei der Wert der Zeit automatisch
vom Restguthaben der Pauschale abgezogen wird.
Ergebnis: Korrekte Verrechnung von Servicezeiten gegen Pauschalverträge/-positionen ohne Doppelverbrauch.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/Orders/OrderBalanceBL.cs:81-193 - AddHelpdeskTimerToOrderPosition(), DoValidateCurrentSelectionForAddingHelpdeskTimeToPosition() mit allen vier Fehlertexten
Prüfidee: Bereits verplante oder bereits weiterverarbeitete Helpdeskzeit an Pauschalposition anhängen → jeweilige Fehlermeldung erwartet.
Konsolidierungshinweis: Legacy-Pfad (CustomerAssets-Architektur) vs. neueres Receipt-Framework – zu klären, ob beide Pfade in Produktion aktiv sind (siehe Abdeckung).
Status: belegt
---
### Kandidat SALES-26
Ebene: SyRS
Typ: Sicherheit (Berechtigungen)
Akteur: Vertrieb (Sachbearbeiter, Filialleiter)
Vorbedingung: Ein Benutzer versucht, Angebote/Aufträge anzulegen, zu bearbeiten oder einzusehen.
Fakt: Jede `*SpecificLogic`-Klasse prüft für die jeweilige Belegart individuelle Benutzerrechte:
`CREATE_NEW_OFFER`/`CREATE_NEW_OFFER_ONLY_OWN_BRANCH`, `EDIT_OFFER`/`EDIT_OFFER_ONLY_OWN_BRANCH`,
`SHOW_OFFERS`/`SHOW_OFFERS_ONLY_OWN_BRANCH`/`SHOW_OFFERS_ONLY_OWN` (analog für Order/SupplierOrder:
`RIGHT_BESTELLUNGANLEGEN`, `Purchase.Supplier.Order.SHOW_ORDER`), zusätzlich getrennte Rechte für
Preisänderung (`CHANGE_PURCHASE_PRICE`, `CHANGE_PRICE`) und Mindestpreis-Ignorierung.
Aussage: Das System soll je Belegart (Angebot, Auftrag, Bestellung) granular getrennte Rechte für Anlegen, Bearbeiten,
Einsehen (jeweils optional auf eigene Filiale/eigene Belege eingeschränkt) sowie für das Ändern von Einkaufs-
bzw. Verkaufspreisen vorsehen.
Ergebnis: Feingranulares, belegart- und filialbezogenes Rechtesystem im Vertriebs-/Einkaufsbereich.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:480-501 - HasRightToCreateANewReceipt(Offer.CREATE_NEW_OFFER), HasRightToEditReceipt(Offer.EDIT_OFFER), HasRightToViewReceipt(Offer.SHOW_OFFERS)
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:552-573 - analoge Rechte für Order.*
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:673-696 - RIGHT_BESTELLUNGANLEGEN, Purchase.Supplier.Order.SHOW_ORDER
Prüfidee: Benutzer mit "nur eigene Filiale"-Recht darf keine Angebote anderer Filialen sehen/bearbeiten.
Konsolidierungshinweis: Gehört ggf. zum übergreifenden Security-Cluster, hier fachlich (Vertrieb/Einkauf) verankert.
Status: belegt
---
### Kandidat SALES-27
Ebene: SyRS
Typ: funktional (Bonitätssteuerung)
Akteur: Vertrieb, Finanzbuchhaltung
Vorbedingung: Für einen Kunden ist eine Mahnstufe (`dunningLevel`) > 0 erfasst.
Fakt: `ReceiptBL` (CanUserCreateNewReceiptsAtCustomerOrSupplier, um Zeile 10201-10216) blockiert das Anlegen neuer
Belege einer Art, sobald die aktuelle Mahnstufe des Kunden die belegartspezifische Schwelle
`BlockNewReceiptsDunningLevel()` erreicht/überschreitet, mit Fehlermeldung "Aufgrund der Mahnstufe darf kein
neuer Beleg vom Typ \"{Belegname}\" angelegt werden.". `OrderSpecificLogic.BlockNewReceiptsDunningLevel()`
liest den kundenindividuellen Schwellwert `customerDetail.OrderLockAfterDunning`.
Aussage: Das System soll das Anlegen neuer Aufträge (und anderer konfigurierter Belegarten) automatisch sperren, wenn
die Mahnstufe eines Kunden einen je Kunde konfigurierbaren Schwellwert erreicht.
Ergebnis: Automatisierte Bonitäts-/Mahnsperre verhindert Folgegeschäfte mit säumigen Kunden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10205-10216 - Mahnstufen-Blockade mit Fehlertext
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:687-693 - BlockNewReceiptsDunningLevel() liest customerDetail.OrderLockAfterDunning
Prüfidee: Kunde mit Mahnstufe über Schwellwert setzen, neuen Auftrag anlegen → Fehlermeldung erwartet.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-28
Ebene: SwRS
Typ: Daten (Referentielle Integrität)
Akteur: Vertrieb (Stammdatenpflege)
Vorbedingung: Ein Abschlussgrund (`ReceiptCompleteReason`) für Angebote soll gelöscht werden.
Fakt: `ReceiptCompleteReasonBL.DeleteReceiptCompleteReason()` prüft vorab, ob noch Angebote existieren, die
`CloseReasonI3D == reason.I3D` referenzieren; ist das der Fall, wird die Löschung mit
"Couldn´t be deleted, because the reason is used by an offer" verweigert.
Aussage: Das System soll das Löschen eines Angebots-Abschlussgrundes verhindern, solange dieser noch von mindestens
einem Angebot referenziert wird.
Ergebnis: Schutz der referentiellen Integrität zwischen Stammdaten (Abschlussgründe) und historischen Angebotsdaten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptCompleteReasonBL.cs:63-76 - DeleteReceiptCompleteReason()
Prüfidee: Abschlussgrund löschen, der einem geschlossenen Angebot zugeordnet ist → Fehlermeldung erwartet.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-29
Ebene: SyRS
Typ: funktional (Steuerbehandlung)
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Ein Angebot/Auftrag wird in einen Folgebeleg weitergeleitet (Forwarding).
Fakt: `OfferSpecificLogic.TakeoverVATWhenForwarding()` und `OrderSpecificLogic.TakeoverVATWhenForwarding()` liefern
beide `TakeoverVatMode.OnlyCustomVats` (nicht `Yes`, nicht `No`) – d.h. nur individuell/manuell gesetzte
Steuersätze werden beim Weiterleiten übernommen, Standard-Steuersätze werden im Zielbeleg neu ermittelt.
`GetDateTimeForVATCalculation()` verwendet dabei einheitlich `receipt.Date` (Belegdatum) als Stichtag.
Aussage: Das System soll beim Weiterleiten von Angeboten/Aufträgen in Folgebelege nur explizit individuell vom Nutzer
gesetzte (abweichende) Steuersätze übernehmen, während Standard-Steuersätze anhand des Belegdatums des
Zielbelegs neu bestimmt werden.
Ergebnis: Korrekte, tagesaktuelle Steuersatzermittlung auch bei länger zurückliegenden Angeboten, ohne individuelle
Sondervereinbarungen zu verlieren.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:549-551 - TakeoverVATWhenForwarding()=OnlyCustomVats, GetDateTimeForVATCalculation()=receipt.Date
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:639-641 - identische Logik für Order
Prüfidee: Angebot mit Standard-MwSt. nach Steuersatzänderung in Auftrag weiterleiten → neuer Satz greift; Angebot mit individuell überschriebenem Steuersatz → Satz bleibt erhalten.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-30
Ebene: SwRS
Typ: funktional / nicht-funktional (aktuelle Einschränkung)
Akteur: Vertrieb
Vorbedingung: Ein Beleg wird als Bar-Beleg (`IsCashAsset`) markiert und gespeichert.
Fakt: `ReceiptBL.SaveReceipt()` bricht mit der festen Meldung "Aktuell werden leider noch keine Bar-Belege
unterstützt." ab, sobald `receipt is IReceiptWithIsCash` und `IsCashAsset==true`.
Aussage: Das System soll das Speichern von als Bar-Beleg gekennzeichneten Belegen bis auf Weiteres vollständig verhindern.
Ergebnis: Bekannte funktionale Lücke/Produktentscheidung: Barverkauf ist im aktuellen Stand nicht abbildbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:3763-3765 - harte Blockade mit Klartext-Fehlermeldung
Prüfidee: Beleg mit IsCashAsset=true speichern → Speichervorgang muss mit exakt dieser Meldung abgebrochen werden.
Konsolidierungshinweis: Für eine Web/SaaS-Neuimplementierung zu klären, ob Barverkauf als Funktionsumfang gefordert ist (aktuell technisch ausgeschlossen).
Status: belegt; Workaround: keiner vorhanden (harter Blocker im Code, keine Umgehung über Settings ersichtlich)
---
### Kandidat SALES-31
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Angebotspositionen sollen im Layout hervorgehoben (alternativ, optional, informativ, nach Aufwand, ohne
Leistung) dargestellt werden.
Fakt: `OfferSpecificLogic` erlaubt alle sieben Positionsarten (`SupportsArticlePositionKindAlternative/Optional/
Informative/OnDemand/OnEffort/NoService/NoServiceOptional` = jeweils `true`), während
`SupplierOrderSpecificLogic` sämtliche dieser Positionsarten ablehnt (`false`), und `OrderSpecificLogic` die
Positionsarten Alternative/Optional/Informative über Settings (`InOrderForArticlePositionKindAlternativeUse`
etc.) auf `OnEffort`, `OnDemand` oder `Default` umschalten kann, sie selbst aber nicht direkt unterstützt
(`SupportsArticlePositionKind...=false` bei gleichzeitiger Verfügbarkeit von OnDemand/OnEffort/NoService=true).
Aussage: Das System soll unterschiedliche Positionsarten (Alternativposition, optionale Position, Informationsposition,
Positionen nach Aufwand/auf Abruf, ohne Leistung) belegartabhängig unterschiedlich zulassen bzw. beim
Weiterleiten in eine andere, konfigurierbare Positionsart überführen.
Ergebnis: Differenzierte Angebotsgestaltung (z. B. Alternativpositionen) mit kontrollierter Übernahmeregel in Folgebelege.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs:421-461 - alle SupportsArticlePositionKind*() => true
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:440-484 - GetArticlePositionKindForAlternative/Optional/Informative() mit Settings-gesteuertem Mapping auf OnEffort/OnDemand/Default
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs:563-631 - alle SupportsArticlePositionKind*() => false
Prüfidee: Angebot mit Alternativposition in Auftrag weiterleiten, Einstellung InOrderForArticlePositionKindAlternativeUse auf verschiedene Werte testen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SALES-32
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Ein aktives Angebot wird als "Kein Angebot mehr gewünscht"/abgeschlossen markiert (manueller Abschluss).
Fakt: `OfferBL.CloseOfferByHand()` setzt den (Legacy-)Status nur auf `2` (=abgeschlossen), wenn zuvor bereits ein
`CloseReasonI3D > 0` (Abschlussgrund) am Angebot gesetzt wurde; ohne Abschlussgrund liefert die Methode `false`
und der Status bleibt unverändert.
Aussage: Das System soll den manuellen Abschluss eines Angebots nur zulassen, wenn zuvor ein Abschlussgrund erfasst wurde.
Ergebnis: Erzwungene Dokumentation des Grundes für Nichtzustandekommen/Abschluss eines Angebots (Auswertbarkeit Verlustgründe).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/Offers/OfferBL.cs:66-81 - CloseOfferByHand()
Prüfidee: Angebot ohne Abschlussgrund manuell schließen → Methode liefert false, Status bleibt "offen".
Konsolidierungshinweis: Legacy-Pfad (CustomerAssets), ggf. Ablösung durch Receipt-Framework/ReceiptCompleteReason (SALES-28) prüfen.
Status: belegt; Workaround: Prüfen, ob dieser Legacy-Pfad im aktuellen UI überhaupt noch erreichbar ist [HYPOTHESE: veraltete Codepfad, evtl. nicht mehr im Einsatz, da ReceiptOfferBL/OfferSpecificLogic der aktivere Pfad zu sein scheint]
---
## Abdeckung
**Gelesen (vollständig oder in relevanten Ausschnitten):**
- `src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs` (11.441 Zeilen; gezielt gelesen: SaveReceipt-Pipeline Z.3517-3760,
CanForwardReceiptsInto/ForwardReceipt Z.1350-1550, CheckIfCustomerLimitIsReached Z.8636-8730,
CheckArticleMinPrices Z.9036-9125, CheckIfPurchaseOrderNumberIsNeeded Z.9258-9296, CheckIfWeeeIsNeeded/
CheckIfClassificationIsNeeded Z.9370-9440, CheckForDuplicatePurchaseOrderNumber Z.10802-10844,
Mahnstufen-Blockade Z.10201-10217, Bar-Beleg-Blockade Z.3763-3765) – **nicht vollständig gelesen**, da Datei zu groß
(>11.000 Zeilen); weitere Validierungen (CheckIfMandatIsNeeded, CheckIfCostCenterIsNeeded, CheckServicePeriods,
CheckIfLeasingAndServiceAreCorrect u.v.a.) wurden nur über Methodennamen identifiziert, nicht im Detail gelesen.
- `src/backend/Centron.BL/Sales/Receipts/ReceiptProgressionBL.cs` (vollständig, 907 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/IReceiptSpecificLogic.cs` (vollständig, 605 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/Offers/OfferSpecificLogic.cs` (vollständig, 664 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs` (vollständig, 750 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderSpecificLogic.cs` (vollständig, 857 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/SupplierOrders/SupplierOrderBL.cs` (vollständig, 151 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/Offers/ReceiptOfferBL.cs` (vollständig, 220 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/ReceiptCompleteReasonBL.cs` (vollständig, 77 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/ReceiptCartReleaseSystemBL.cs` (vollständig, 567 Zeilen)
- `src/backend/Centron.BL/Sales/Receipts/DownPayment/DownPaymentBL.cs` (Ausschnitt Z.1-120 von insgesamt größerer Datei)
- `src/backend/Centron.BL/Sales/CustomerAssets/Offers/OfferBL.cs` (vollständig, 223 Zeilen)
- `src/backend/Centron.BL/Sales/CustomerAssets/Orders/OrderBalanceBL.cs` (vollständig, 330 Zeilen)
- `src/backend/Centron.BL/Sales/CustomerAssets/Orders/OrderReplacementBL.cs` (vollständig, 70 Zeilen)
- `src/backend/Centron.BL/Sales/CustomerAssets/Orders/OrderBL.cs` (nur Methodenliste/Signaturen, nicht Methodenkörper, außer Erwähntes)
- `src/backend/Centron.BL/ProductMatrix/ProductMatrixBL.cs` (vollständig, 224 Zeilen)
- `src/backend/Centron.BL/TradePool/TradePoolBL.cs` (vollständig, 231 Zeilen)
- `src/backend/Centron.BL/Purchasing/SupplierOrderPerBranchBL.cs` (vollständig, 187 Zeilen)
- `src/backend/Centron.BL/Purchasing/OrderSuggestionList/OrderSuggestionListBL.cs` (1144 Zeilen; Ausschnitte Z.589-733 und
Z.1039-1144 gelesen, restliche ca. 700 Zeilen nur über Methodenliste erfasst, u.a. GetPriceMatrixFromDB, GetDistributorToArticle)
**Ausgelassen / nur oberflächlich gesichtet (bekannte Lücken):**
- `src/backend/Centron.BL/Sales/Receipts/Orders/ReceiptOrderBL.cs` (1320 Zeilen) – nicht gelesen, nur über Namensraum identifiziert.
- `src/backend/Centron.BL/Sales/Receipts/ReceiptCartBL.cs` (1078 Zeilen) und weitere Receipt-Internals
(`ReceiptItemBL`, `ReceiptPriceHelperBL`, `ReceiptArticleBookingBL`, `ReceiptItemPriceBL`, `AutomaticallyCloseReceiptHelperBL`
u.v.a. unter `Sales/Receipts/Internal`) – nicht gelesen.
- `src/backend/Centron.BL/Sales/Receipts/Offers/OfferImportSettingsBL.cs`, `ClassificationProbabilityBL.cs`,
`ProductGroupBL.cs` – nicht gelesen (thematisch zu SALES-14 gehörig, ggf. weitere Details dort).
- `src/backend/Centron.BL/Purchasing/Suppliers/*`, `src/backend/Centron.BL/Purchasing/PurchaseSettings/*` – nicht gelesen
(Lieferantenstammdaten/Einkaufskonditionen); `Purchasing/Suppliers/SupplierBL.cs` nur als Dateiname erfasst.
Weitere Details zu Konditionsverwaltung/Preislisten Lieferant fehlen daher (mögliche Lücke für eigene SwRS-Kandidaten).
- `src/backend/Centron.BL/Buying/External/*` – nicht gelesen (nur Verzeichnisname bekannt); unklar, ob und wie sich dies
fachlich vom Purchasing-Bereich unterscheidet [HYPOTHESE: evtl. externe Einkaufsintegration, nicht verifiziert].
- `src/backend/Centron.BL/TradePool/Core/TradePoolXmlLogic.cs` – nicht gelesen (Detail-Importlogik XML→Artikeldaten).
- `src/backend/Centron.Data.Entities` (Entities/DB-Mapping) und `src/backend/Centron.DAO` – nicht durchsucht; DB-Constraints
(Check-Constraints, Fremdschlüssel) wurden nicht direkt in SQL-Skripten verifiziert, sondern nur indirekt über BL-Code
erschlossen. ReceiptState/ReceiptCartState-Werte sind aus C#-Enums belegt, nicht aus DB-Schema.
- WPF/XAML-UI-Schicht (`src/frontend` o.ä.) wurde nicht gesichtet; UI-Texte/Feldbeschriftungen wurden ausschließlich aus
Fehlermeldungs-Strings im BL-Code abgeleitet, nicht aus tatsächlichen XAML-Labels.
- `git log` wurde nur für den Unterordner Sales/Receipts/Offers, Orders, SupplierOrders, Purchasing, ProductMatrix, TradePool
geprüft (15 letzte Commits); keine vollständige Historienanalyse, keine Ticket-/Anforderungsdokumente außerhalb des Codes eingesehen.
**Generelle Einschränkung:** Die Business-Logik ist stark settings-getrieben (`AppSettingsBL`/`AppSettingsConst`); die exakten
Standardwerte und Wertebereiche vieler referenzierter Einstellungen (z. B. `CloseOfferAutomatically`,
`OrderAutoProvisionEmployee`) wurden nur so weit dokumentiert, wie sie im gelesenen Code direkt sichtbar waren – die
Einstellungs-UI/Struktur selbst (`Administration/Settings`) wurde nicht untersucht.
@@ -0,0 +1,557 @@
# Rohbefunde Cluster: Sicherheit & Berechtigungen (SEC)
Quelle: CentronERP-Codebasis (C#/WPF/MSSQL). Recherche-Agent für Reverse Requirements Engineering (RRE), Zwischenformat vor ID-Konsolidierung.
---
### Kandidat SEC-01
Ebene: StRS
Typ: Stakeholder-Ziel
Akteur: c-entron Mitarbeiter (interner Benutzer, "AppUser"), Kunde (Web-Account)
Vorbedingung: -
Fakt: Das System unterscheidet technisch zwei vollständig getrennte Benutzerarten mit eigenen Tabellen/Entities und eigenen Authentifizierungspfaden: interne Mitarbeiter (`AppUser`/Tabelle `Sichbenu`) und Kunden-Zugänge (`WebAccount`). Beide durchlaufen unterschiedliche Authenticator-Klassen (`BasicAuthenticator`/`ActiveDirectoryAuthenticator` vs. `WebAccountAuthenticator`).
Aussage: Das System soll interne Mitarbeiterkonten und externe Kundenzugänge als getrennte Identitätsklassen mit eigenen Rechte- und Authentifizierungsregeln führen.
Ergebnis: Zwei unabhängige Benutzer-/Rechtemodelle (App-Rechte über `Sichrech`/`Sichtrus`/`Sichmemb` für Mitarbeiter, `WebRights`/`WebAccountsRights` für Kunden).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs (AuthenticatorFactory.GetMainAuthenticator, Zeilen 88-95) - Begründung: Routing anhand des konkreten `AuthObject`-Typs (BasicAuthObject/WebAccountAuthObject/OpenIdConnectAuthObject) belegt getrennte Codepfade.
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/WebAccountAuthenticator.cs (Zeile 20-83) - Begründung: Eigene Authentifizierungsklasse nur für Kundenzugänge.
Prüfidee: Prüfen, ob im Zielsystem beide Identitätsklassen (Mitarbeiter, Kunde) weiterhin getrennt modelliert werden müssen oder ob ein einheitliches Identity-Modell mit Rollenattribut ausreicht.
Konsolidierungshinweis: Grundlage für SEC-08 bis SEC-11 (Login-Validierung) und SEC-20/21 (Passwortregeln je Kontotyp).
Status: belegt
---
### Kandidat SEC-02
Ebene: StRS
Typ: Stakeholder-Ziel
Akteur: Administrator (Rechteverwaltung)
Vorbedingung: -
Fakt: Rechte werden nicht direkt an Benutzer, sondern an Gruppen (`AppGroup`) vergeben; Benutzer werden Gruppen zugeordnet (`AppUserMember`), Gruppen erhalten Rechte (`AppGroupRightAssignment`). Das Modul "Rechteverwaltung" (`Rechteverwaltung`) verwaltet dies laut Doku.
Aussage: Das System soll Zugriffsrechte gruppenbasiert (rollenbasiert) statt benutzerindividuell vergeben, um Verwaltungsaufwand und Fehlerquote bei der Rechtevergabe zu reduzieren.
Ergebnis: Ein Benutzer erhält die Vereinigungsmenge aller Rechte seiner zugeordneten Gruppen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (GetRightsFromCurrentUser, Zeilen 63-87; CheckRightsFromUser, Zeilen 95-111) - Begründung: SQL-Join über `Sichtrus`/`Sichmemb` aggregiert Rechte ausschließlich über Gruppenmitgliedschaft.
- [KONTEXT] docs/guides/development/check-userrights.md (Zeile 3) - Begründung: "Rights and groups can be managed in the Rechteverwaltung module."
Prüfidee: Klären, ob im SaaS-Zielsystem weiterhin Gruppen als einzige Rechteträger dienen sollen oder zusätzlich direkte Nutzer-Overrides (Allow/Deny) benötigt werden.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-03
Ebene: StRS
Typ: Stakeholder-Ziel
Akteur: Administrator, Mitarbeiter (eingeschränkter Sichtbereich)
Vorbedingung: -
Fakt: Neben "Vollrechten" existiert die dokumentierte Kategorie "einschränkendes Recht" (restricting right), z. B. `SHOW_HELPDESK_ONLY_OWN`, `SHOW_HELPDESK_ONLY_OWN_BRANCH`, `MANAGE_RIGHTS_ONLY_OWN_BRANCH`. Diese Rechte schränken eine bereits gewährte Sichtbarkeit weiter ein (z. B. nur eigene Filiale).
Aussage: Das System soll eine Datensparsamkeit nach Bedarfsprinzip ("need-to-know") über kombinierbare einschränkende Rechte (nur eigene Datensätze / nur eigene Filiale) umsetzen können.
Ergebnis: Ein Benutzer mit Grundrecht + einschränkendem Recht sieht nur eine Teilmenge der Datensätze, die er ohne das einschränkende Recht sehen würde.
Belege:
- [PRIMÄR] CentronRights.md (Abschnitte 1.1, 1.2, 2.1, Zeilen 9-26) - Begründung: Explizite Dokumentation als "restricting right" mit fachlicher Wirkung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (SaveRightGroup, Zeilen 391-393; DeleteRightGroup, Zeilen 355-357) - Begründung: `MANAGE_RIGHTS_ONLY_OWN_BRANCH` wird serverseitig ausgewertet und verweigert filialübergreifende Aktionen.
Prüfidee: Ermitteln, wie viele "nur eigene"/"nur eigene Filiale"-Rechte insgesamt existieren (Sichrech-Auswertung) und ob dieses Muster generisch (z. B. Row-Level-Security/Policy Engine) statt Recht-für-Recht abgebildet werden kann.
Konsolidierungshinweis: Ergänzt SEC-02.
Status: belegt
---
### Kandidat SEC-04
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator
Vorbedingung: -
Fakt: Die Gruppe mit `I3D == 6` bzw. Name "Administratoren" ist im Code hart gegen Löschung geschützt (`DeleteRightGroup`) und nur eine explizite Whitelist von ca. 30 Rechten darf dieser Gruppe hinzugefügt/entzogen werden (`GetAssignableAdminRightI3Ds`).
Aussage: Das System soll die Administratorengruppe strukturell vor versehentlicher Löschung und vor Entzug sicherheitskritischer Rechte schützen.
Ergebnis: Löschversuch der Administratorengruppe liefert Fehlermeldung "Die Adminstratoren Gruppe darf nicht gelöscht werden"; Rechteänderungen an dieser Gruppe außerhalb der Whitelist werden abgelehnt (Rückgabe `false`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (DeleteRightGroup, Zeilen 348-374; SaveAndAssignGroupToRight/RemoveAssignGroupToRight, Zeilen 261-299; GetAssignableAdminRightI3Ds, Zeilen 714-759) - Begründung: Serverseitige Schutzlogik unabhängig vom UI, harte Prüfung `group.I3D == 6`.
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppUserGroupBL.cs (IsAdministratorGroup/IsAdministratorGroupI3D, Zeilen 78-89) - Begründung: Zentrale Definition "Administratorengruppe = I3D 6 ODER Name = 'Administratoren'".
Prüfidee: Verifizieren, ob Namensvergleich ("Administratoren") als Sicherheitskriterium zuverlässig ist (Umbenennungsrisiko) oder nur der I3D-Vergleich sicherheitsrelevant sein sollte.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-05
Ebene: StRS
Typ: Sicherheit
Akteur: Mitarbeiter, Kunde (Web-Account)
Vorbedingung: -
Fakt: Zusätzlich zu Benutzername/Passwort existiert eine konfigurierbare Zwei-Faktor-Authentifizierung mit zwei austauschbaren Verfahren: RADIUS-Server (`RadiusTwoFactorValidator`) und E-Mail-Link (`EmailTwoFactorValidator`), gesteuert über `WebServiceConfigHelper.Current.TwoFactorAuthType`.
Aussage: Das System soll eine zusätzliche Authentifizierungsstufe (2FA) als organisatorisch konfigurierbare Sicherheitsmaßnahme anbieten.
Ergebnis: Login schlägt fehl, wenn 2FA aktiviert, aber nicht erfolgreich validiert wurde ("Die Zwei-Faktor-Authentifizierung ist fehlgeschlagen.").
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorAuthBL.cs (GetTwoFactorValidator, Zeilen 181-194; ValidateTwoFactor, Zeilen 33-80) - Begründung: Zentrale Weiche für 2FA-Verfahren, in allen drei Authenticator-Klassen (Basic/AD/WebAccount) eingebunden.
Prüfidee: Klären, ob im Zielsystem TOTP/App-basierte 2FA (wie in TwoFactorAuthenticationBL für den Passwort-Manager, siehe SEC-28) als drittes gleichwertiges Verfahren für den Login ergänzt werden soll.
Konsolidierungshinweis: Bündelt SEC-14, SEC-15, SEC-16.
Status: belegt
---
### Kandidat SEC-06
Ebene: StRS
Typ: Schnittstelle
Akteur: Mitarbeiter (Unternehmens-Konto)
Vorbedingung: Azure AD App Registration vorhanden, Lizenz `OpenIDConnectAuthentication`
Fakt: Die Funktion "Anmelden mit Microsoft" ist als vollständiger OpenID-Connect-Flow über MSAL dokumentiert und implementiert (`/config/jwt`, `/jwt/login`, `/jwt/connect_accounts`).
Aussage: Das System soll Single-Sign-On über Microsoft Entra ID als alternativen, konfigurierbaren Anmeldeweg unterstützen.
Ergebnis: Erfolgreiche Anmeldung liefert ein c-entron-Ticket (Session) ohne c-entron-eigenes Passwort.
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md (gesamt, insb. Zeilen 126-146, 386-403) - Begründung: Vollständige technische Dokumentation inkl. Dateipfaden.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs (GetFromOpenIdConnectAuth, Zeilen 129-145) - Begründung: Lizenzprüfung `LicenseGuids.OpenIDConnectAuthentication` und Aktivierungs-Flag `JwtEnabled` als Vorbedingung bestätigt.
Prüfidee: Prüfen, ob Redirect-/Consent-Flow und Token-Validierung 1:1 in eine Web-/SaaS-Neuimplementierung (z. B. mit Standard-OIDC-Middleware) übernommen werden können.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-07
Ebene: StRS
Typ: Sicherheit
Akteur: Administrator, Vertriebsmitarbeiter mit Zugriff auf Kundenzugangsdaten
Vorbedingung: Lizenz "Passwort-Manager" vorhanden
Fakt: Der Zugriff auf das gesamte Passwort-Manager-Modul (Kundenzugänge/Passwörter) ist zusätzlich zur Rechteprüfung an eine kommerzielle Lizenz gekoppelt (`LicenseManager.Instance.HasLicense(LicenseGuids.PasswordManager)`), die in praktisch jeder öffentlichen Methode von `PasswordManagerBL` geprüft wird.
Aussage: Das System soll den Zugriff auf sicherheitskritische Zusatzmodule (z. B. Passwort-Manager) sowohl über Lizenz als auch über Benutzerrechte absichern (zweistufige Zugriffskontrolle).
Ergebnis: Ohne Lizenz: Fehlermeldung "Sie besitzen keine Lizenz für den Passwort-Manager." (`DefaultMessageCodes.LicenseNotFound`), unabhängig von vorhandenen Rechten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/PasswordManager/PasswordManagerBL.cs (z. B. Zeilen 94-95, 243-244, 263-264, 331-332, 349-350, 896-897, 932-933) - Begründung: Wiederkehrendes Muster in mind. 8 Methoden.
- [KONTEXT] docs/reference/security/licensing-system.md (Zeilen 50-63) - Begründung: Allgemeines Lizenzkonzept (`LicenseManager.Instance.HasLicense`) bestätigt als Standardmuster.
Prüfidee: Klären, ob Lizenzprüfung im SaaS-Modell durch Tenant-/Subscription-Feature-Flags ersetzt wird und ob die doppelte Prüfung (Lizenz UND Recht) beibehalten werden soll.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-08
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter (Benutzername/Passwort-Login)
Vorbedingung: SystemAuthenticationMethod = Basic (oder None ohne aktives AD)
Fakt: `BasicAuthenticator.AuthenticateInternal` verlangt nicht-leeren Benutzernamen und nicht-leeres Passwort, dekodiert das übertragene Passwort (`SHA1Decoder.GetDecodedSHA1String`) und sucht exakt einen `AppUser` mit passendem `Name` und `Password`-Hash.
Aussage: Das System soll eine Anmeldung nur zulassen, wenn Benutzername und Passwort-Hash exakt mit einem gespeicherten aktiven Konto übereinstimmen.
Ergebnis: Bei fehlendem Benutzernamen/Passwort: Fehler "…kein Benutzername oder Passwort übergeben" (`DefaultMessageCodes.NoUsernameOrPassword`); bei falscher Kombination: generische Meldung "Anmeldung fehlgeschlagen, bitte prüfen Sie Ihren Benutzernamen/Passwort" (`DefaultMessageCodes.LoginFailed`) - kein Hinweis, ob Benutzername oder Passwort falsch war.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs (Zeilen 35-58) - Begründung: Direkte, durchgesetzte Kernlogik der Passwortprüfung.
Prüfidee: Manuellen Login-Test mit falschem Passwort/falschem Benutzernamen durchführen und Antwortzeiten/Fehlermeldungen vergleichen (User-Enumeration-Schutz prüfen).
Konsolidierungshinweis: Siehe SEC-26 (Hashing-Schwäche).
Status: belegt
---
### Kandidat SEC-09
Ebene: SyRS
Typ: funktional; nicht-funktional (Robustheit)
Akteur: Mitarbeiter (Active-Directory-Login)
Vorbedingung: Active Directory aktiviert
Fakt: `ActiveDirectoryAuthenticator` probiert mehrere URL/Port-, TLS- und Auth-Type-Kombinationen (Negotiate/Kerberos/Basic) gegen den LDAP-Server durch, bis eine erfolgreich ist oder ein bekannter Fehlercode (`IncorrectCredentials = 49`) auftritt; bei `IncorrectCredentials` wird sofort abgebrochen, um wiederholte Fehlversuche gegen den LDAP-Server (und damit ein mögliches AD-Lockout) zu vermeiden.
Aussage: Das System soll bei Active-Directory-Anmeldungen mehrere Verbindungsvarianten automatisch durchprobieren, jedoch bei einer eindeutig falschen Anmeldung sofort abbrechen, um eine Kontosperrung durch wiederholte Fehlversuche am LDAP-Server nicht zu verschlimmern.
Ergebnis: Bei falschem Passwort: Meldung "Die Anmeldung am Active Directory ist fehlgeschlagen. Bitte überprüfen Sie Ihre Anmeldedaten." nach genau einem Versuch, nicht nach allen Kombinationen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/ActiveDirectoryAuthenticator.cs (ValidateInternal, Zeilen 146-206; Konstanten Zeilen 143-144) - Begründung: Explizite Fehlercode-Unterscheidung und Kommentar zur Lockout-Vermeidung (Zeilen 181-187).
Prüfidee: Mit Test-AD verifizieren, dass bei falschem Passwort tatsächlich nur ein LDAP-Bind-Versuch stattfindet.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-10
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter, Administrator
Vorbedingung: -
Fakt: `Authenticator.ValidateAppUser` prüft nach erfolgreicher Kennwort-/AD-Prüfung zusätzlich: (a) Checkbox-Deaktivierung (`user.IsAccountDisabled`), (b) Datumsfenster `AccountDisabledFromDate`/`AccountDisabledToDate` (auch nur-von oder nur-bis gesetzt), (c) Mitarbeiterstatus über `EmployeeBL.IsActiveEmployeeCompact` (Einstellungs-/Austrittstermin).
Aussage: Das System soll ein erfolgreich authentifiziertes Konto zusätzlich anhand von Aktivierungsstatus und Zeitfenstern sperren können, unabhängig vom Passwort.
Ergebnis: Fehlermeldung "Mitarbeiterkonto wurde deaktiviert" (`DefaultMessageCodes.EmployeeAccountDeactivated`) trotz korrektem Passwort.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs (ValidateAppUser, Zeilen 157-218) - Begründung: Durchgesetzte Logik, unabhängig vom gewählten Authenticator (Basic/AD/WebAccount nutzen dieselbe Basisklasse).
- [SEKUNDÄR] src/webservice/Centron.WebServices.Core/Entities/Administration/AppUserDTO.cs (Zeilen 16-26) - Begründung: Bestätigt Felder `AccountDisabledFromDate/ToDate/IsAccountDisabled` als DTO-Vertrag.
Prüfidee: Testfälle: nur "von"-Datum in Zukunft/Vergangenheit, nur "bis"-Datum, beide Daten, um Randfallverhalten zu bestätigen.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-11
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter, Kunde
Vorbedingung: -
Fakt: Nach Authentifizierung prüft `ValidateRights` in `Authenticator` je Zielanwendung (`ApplicationKind`) ein optionales `RequiredRight` (muss vorhanden sein) und ein optionales `DisallowingRight` (darf nicht vorhanden sein), bevor ein Ticket ausgestellt wird. Für Web-Accounts ist diese Prüfung deaktiviert (`WebAccountAuthenticator.ValidateRights` gibt immer Erfolg zurück).
Aussage: Das System soll den Zugang zu einzelnen Anwendungen/Clients zusätzlich zur allgemeinen Anmeldung anwendungsspezifisch über Rechte freischalten oder sperren können.
Ergebnis: Fehlermeldung `TicketBL_GetTicket_RightsMissing` bzw. `TicketBL_GetTicket_LoginDisallowed` mit Anwendungsname.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs (ValidateRights, Zeilen 68-86) - Begründung: Kernlogik.
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/WebAccountAuthenticator.cs (Zeilen 37-40) - Begründung: Bewusste Ausnahme für Kundenzugänge dokumentiert abweichendes Verhalten.
Prüfidee: Liste aller `ApplicationKind`-Einträge mit gesetztem `RequiredRight`/`DisallowingRight` erheben.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-12
Ebene: SyRS
Typ: nicht-funktional (Sitzungsverwaltung)
Akteur: Alle authentifizierten Benutzer
Vorbedingung: -
Fakt: `TicketBL` vergibt nach Login ein Sitzungs-Ticket mit Ablaufzeit; Standard 30 Minuten (`TicketExpireInMinutes`), Sonderfall Monitoring-Connector 5 Minuten, Sonderfall "OneDay" 1440 Minuten, sowie ein konfigurierbarer Wert aus den Einstellungen (`AppSettingsConst.TicketReleaseTime`), mindestens jedoch 30 Minuten (`Math.Max`).
Aussage: Das System soll Sitzungen nach einer definierten, je nach Anwendungstyp unterschiedlichen Inaktivitätsdauer automatisch ablaufen lassen.
Ergebnis: Nach Ablauf ist das Ticket ungültig, Folgeaufrufe scheitern mit "Could not get the ticket." (`DefaultMessageCodes.CouldNotFindData`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TicketBL.cs (Konstanten Zeilen 26-28, GetExpireDate Zeilen 136-164) - Begründung: Vollständige, durchgesetzte Ablaufzeit-Logik inkl. Konfigurationspfad.
Prüfidee: Prüfen, ob 30 Minuten als Session-Timeout für die SaaS-Neuimplementierung übernommen werden soll oder ein Standard-Refresh-Token-Modell sinnvoller ist.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-13
Ebene: SyRS
Typ: nicht-funktional (Performance/Effizienz)
Akteur: System (intern)
Vorbedingung: -
Fakt: `RefreshTicketExpireDate` aktualisiert das Ablaufdatum eines Tickets nur, wenn die neue Ablaufzeit mindestens 5 Minuten später liegt als die bisherige - eine bewusste Optimierung, um DB-Schreibzugriffe zu reduzieren, mit dokumentiertem Kompromiss (Ticket kann in seltenen Randfällen früher ablaufen als früher).
Aussage: Das System soll die Aktualisierung von Sitzungs-Ablaufzeiten auf ein performance-optimiertes Mindestintervall begrenzen.
Ergebnis: Nicht jeder API-Aufruf löst ein DB-Update aus; in seltenen Fällen läuft ein Ticket früher ab als bei einer exakten Verlängerung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TicketBL.cs (RefreshTicketExpireDate, Zeilen 113-134, inkl. Entwicklerkommentar) - Begründung: Explizit dokumentierter Trade-off im Code.
Prüfidee: Klären, ob dieses Optimierungsverhalten im Zielsystem funktional relevant ist oder rein technische Implementierungsdetail bleibt.
Konsolidierungshinweis: Ergänzt SEC-12.
Status: belegt
---
### Kandidat SEC-14
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter, Kunde (bei aktivierter 2FA)
Vorbedingung: `TwoFactorAuthEnabled` global aktiviert; `UseTwoFactorAuthentication` beim Benutzer/Web-Account aktiviert
Fakt: `HasToValidateTwoFactor` erzwingt 2FA immer neu, wenn: (a) global deaktiviert → nie, (b) `requireTwoFactorAuth` explizit angefordert, (c) konfigurierte Gültigkeitsdauer (`TwoFactorValidDurationInDays`, pro Benutzer oder global) ≤ 0, oder (d) die letzte 2FA-Validierung für Anwendung+Gerät+IP länger als die Gültigkeitsdauer zurückliegt (datumsbasiert, ohne Uhrzeitanteil).
Aussage: Das System soll die Häufigkeit erneuter Zwei-Faktor-Abfragen über eine je Benutzer konfigurierbare Gültigkeitsdauer steuern, gebunden an Anwendung, Gerätename und IP-Adresse.
Ergebnis: Wiederholter Login von selbem Gerät/IP innerhalb der Gültigkeitsdauer benötigt keine erneute 2FA-Bestätigung; Tabelle `TwoFactorAuthLastLogin` speichert je Kombination den letzten Zeitpunkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorAuthBL.cs (HasToValidateTwoFactor, Zeilen 82-135; GetLastLogin/RememberLogin, Zeilen 137-179) - Begründung: Vollständige, durchgesetzte Regel inkl. Grenzfall-Kommentierung.
Prüfidee: Testen: Login von neuem Gerät vs. bekanntem Gerät, Wechsel der IP-Adresse, Grenzfall "Gültigkeitsdauer = 0".
Konsolidierungshinweis: Detailliert SEC-05.
Status: belegt
---
### Kandidat SEC-15
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter/Kunde (2FA per E-Mail-Link)
Vorbedingung: 2FA-Typ = EmailLink
Fakt: `EmailTwoFactorValidator` erzeugt einen einmaligen GUID-Code, sendet einen Link `{...}/2fa/validate?code=...` per E-Mail und wartet asynchron (mit Timeout `MailTwoFactorAuthTimeoutInSeconds`) auf den Klick des Nutzers; danach wird der Code aus dem Speicher entfernt (`_codes.TryRemove`).
Aussage: Das System soll bei E-Mail-basierter 2FA einen zeitlich begrenzten, einmal verwendbaren Bestätigungslink verwenden.
Ergebnis: Bei Timeout: Fehlermeldung "Sie haben nicht innerhalb des Timeouts auf den Link... geklickt." (`DefaultMessageCodes.Canceled`); der Code ist nach Verwendung oder Timeout ungültig.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/EmailTwoFactorValidator.cs (ValidateCredentials Zeilen 38-83, TrySetCodeAsValidated Zeilen 85-98) - Begründung: Durchgesetzte Logik inkl. Entfernen des Codes nach Nutzung.
Prüfidee: Prüfen, ob der Code serverseitig persistent (DB) oder nur In-Memory (`ConcurrentDictionary`) gehalten wird - Auswirkung auf Skalierbarkeit/Mehrinstanzbetrieb im SaaS-Zielsystem.
Konsolidierungshinweis: Detailliert SEC-05.
Status: belegt; Workaround (In-Memory-Code-Speicher ist nicht mandantenfähig/skalierbar - relevant für SaaS-Architektur)
---
### Kandidat SEC-16
Ebene: SyRS
Typ: Schnittstelle
Akteur: Mitarbeiter (2FA per RADIUS)
Vorbedingung: 2FA-Typ = RadiusServer; nur für `AppUser`-Logins (`SupportsRadiusServer`), nicht für Web-Accounts
Fakt: `RadiusTwoFactorValidator` kommuniziert über UDP mit einem konfigurierten RADIUS-Server; bei Timeout wird der RADIUS-Fehler in eine abbrechbare `ResultException` mit `DefaultMessageCodes.Canceled` übersetzt.
Aussage: Das System soll RADIUS-basierte Zwei-Faktor-Authentifizierung ausschließlich für interne Mitarbeiterkonten anbieten, nicht für Kundenzugänge.
Ergebnis: Web-Account-Login mit RADIUS-2FA übergeht die Prüfung stillschweigend (`if (user.SupportsRadiusServer is false) return;`).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/RadiusTwoFactorValidator.cs (ValidateCredentials, Zeilen 39-63) - Begründung: Explizite Bedingung und Fehlerbehandlung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorUser.cs (SupportsRadiusServer, Zeile 124, mit Kommentar Zeilen 119-123) - Begründung: Begründet fachlich, warum nur AppUser RADIUS nutzen kann (Kopplung an AD-Domänenkonto).
Prüfidee: Klären, ob dieses Verhalten (stiller Bypass bei Web-Account+RADIUS) beabsichtigt ist oder eine Lücke darstellt, falls ein Admin RADIUS für Kunden aktiviert.
Konsolidierungshinweis: Detailliert SEC-05.
Status: belegt
---
### Kandidat SEC-17
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter (Microsoft-Login)
Vorbedingung: JWT/OIDC aktiviert, Lizenz vorhanden
Fakt: Serverseitig validiert die ASP.NET-Core-JWT-Middleware Signatur, Issuer, Audience und Lifetime des Microsoft-ID-Tokens gegen das OpenID-Connect-Discovery-Dokument, bevor der `oid`-Claim zum Auffinden des Benutzers über `OpenIdConnectSubjectIdentifier` (Spalte in `Sichbenu`) verwendet wird.
Aussage: Das System soll bei Anmeldung über Microsoft Entra ID das erhaltene Token vollständig kryptographisch validieren, bevor eine lokale Identität zugeordnet wird.
Ergebnis: Ungültige/abgelaufene/falsch signierte Tokens werden von der Middleware abgewiesen, bevor eigene Business-Logik erreicht wird.
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md (Abschnitt "Was auf dem Server passiert", Zeilen 126-146) - Begründung: Dokumentierter Standardablauf inkl. Codeausschnitt für User-Lookup.
- [KONTEXT] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md (Tabelle Zeilen 388-403) - Begründung: Verweist auf konkrete Implementierungsdateien (`OpenIdConnectAuthenticator.cs`, `CentronHost.cs`) für vertiefende Prüfung.
Prüfidee: `OpenIdConnectAuthenticator.cs` und `CentronHost.cs` direkt einsehen, um die Middleware-Konfiguration (Clock-Skew, erlaubte Algorithmen) zu verifizieren (in dieser Recherche nicht mehr geöffnet).
Konsolidierungshinweis: Ergänzt SEC-06.
Status: belegt; HYPOTHESE für Detail "erlaubte Signaturalgorithmen/Clock-Skew-Toleranz" (Quelldatei `CentronHost.cs` nicht gelesen, nur Doku ausgewertet)
---
### Kandidat SEC-18
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter mit Exportrecht
Vorbedingung: Lizenz Passwort-Manager vorhanden
Fakt: `GetAllCustomerAccountsWithAccessData` und `GetCustomerAccessDataForExport` prüfen zusätzlich zum Lizenzcheck explizit `UserRightsConst.PasswordManager.EXPORT_ACCESS_AND_PASSWORD_DATA` und werfen andernfalls eine `ResultException` mit `DefaultMessageCodes.RightCheckFailed`.
Aussage: Das System soll den Massenexport gespeicherter Kundenzugangsdaten/Passwörter an ein dediziertes, von der reinen Anzeige-Berechtigung getrenntes Exportrecht binden.
Ergebnis: Fehlermeldung "Sie besitzen nicht das Recht 'Passwort-Manager Export' um Zugänge und Passwörter zu exportieren".
Belege:
- [PRIMÄR] src/backend/Centron.BL/PasswordManager/PasswordManagerBL.cs (Zeilen 894-936) - Begründung: Durchgesetzte Prüfung vor jeglicher Datenaufbereitung, inkl. Entschlüsselung via `CentronConfigurationDbBL.GetHotlineMasterKey()` (Zeile 949-952).
Prüfidee: Prüfen, ob Export-Aktionen zusätzlich protokolliert werden (aktuell kein Log-Aufruf in diesen Methoden ersichtlich) - relevant für Audit-Anforderung im Zielsystem.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-19
Ebene: SyRS
Typ: Daten (Audit-Log)
Akteur: Mitarbeiter mit Zugriff auf Passwort-Manager-Einträge
Vorbedingung: -
Fakt: Jeder lesende Zugriff auf ein gespeichertes Kennwort im (Legacy-)Modul `PasswordManagementArea` erzeugt einen Eintrag in `PasswordManagementAccessLog` mit Aktionstyp, Zeitstempel und ausführendem Mitarbeiter (`PasswordManagementKeywordBL.GetDecryptedKeywordById` → `PasswordManagementAccessLogBL.SavePasswordManagementAccessLog`).
Aussage: Das System soll jeden Zugriff auf gespeicherte Kennwörter nachvollziehbar protokollieren (wer, wann, welche Aktion).
Ergebnis: Vollständige Zugriffshistorie je Kennwort-Datensatz abrufbar über `GetAllAccessLogsForKeyword`.
Belege:
- [PRIMÄR] src/backend/Centron.BL/PasswordManagementArea/PasswordManagementKeywordBL.cs (GetDecryptedKeywordById, Zeilen 21-36) - Begründung: Durchgesetzter Log-Aufruf bei jedem Lesezugriff.
- [SEKUNDÄR] src/backend/Centron.BL/PasswordManagementArea/PasswordManagementAccessLogBL.cs (Zeilen 17-43) - Begründung: Bestätigt Datenmodell des Logs.
Prüfidee: Abgleichen, ob das aktuell genutzte Passwort-Manager-Modul (`PasswordManagerBL`, Hotline-basiert) eine äquivalente Zugriffsprotokollierung besitzt oder nur das Legacy-Modul (siehe SEC-29).
Konsolidierungshinweis: Siehe SEC-29 zur Einordnung als mutmaßlich veraltetes Modul.
Status: belegt; HYPOTHESE ob dieses Protokoll im aktuell aktiven Passwort-Manager-Modul ein Äquivalent hat (in `PasswordManagerBL.cs` selbst wurde kein Zugriffs-Log für das Lesen einzelner Werte gefunden, nur `PasswordManagerLog` für andere Zwecke)
---
### Kandidat SEC-20
Ebene: SyRS
Typ: funktional; Sicherheit
Akteur: Kunde (Web-Account), Administrator (Anlage/Änderung)
Vorbedingung: -
Fakt: `WebAccountBL.UpdatePassword` und `SaveWebAccount`/`CreateWebAccountWithContacts` erzwingen serverseitig eine Mindestlänge von 8 Zeichen für Web-Account-Passwörter (`newPassword.Length < 8`).
Aussage: Das System soll für Kundenzugänge (Web-Accounts) eine Mindestpasswortlänge von 8 Zeichen erzwingen.
Ergebnis: Fehlermeldung "Das Password muss mindestens 8 Zeichen lang sein." bei Unterschreitung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/WebAccountBL.cs (UpdatePassword, Zeilen 183-188; SaveWebAccount, Zeilen 243-246) - Begründung: Zwei unabhängige, konsistente Durchsetzungsstellen.
Prüfidee: Prüfen, ob weitere Komplexitätsregeln (Groß-/Kleinschreibung, Sonderzeichen) an anderer Stelle (Client/UI) zusätzlich erzwungen werden - im gesichteten Code nicht gefunden.
Konsolidierungshinweis: Kontrastiert mit SEC-21 (AppUser-Passwortregel ist schwächer/konfigurierbar statt fix).
Status: belegt
---
### Kandidat SEC-21
Ebene: SyRS
Typ: funktional; Sicherheit
Akteur: Mitarbeiter (interner Login)
Vorbedingung: -
Fakt: Für interne `AppUser` wird die Mindestlänge über ein Feld `PasswordMinLength` je Benutzer konfiguriert (`AppUser.PasswordMinLength`, Spalte in `Sichbenu`); `UsersBL.IsValidAppUserPassword` prüft die Länge **nur**, wenn `PasswordMinLength > 0` - keine erzwungene Komplexität (Zeichenklassen), keine globale Mindestlänge als Fallback.
Aussage: Das System soll für interne Mitarbeiterkonten eine je Benutzer konfigurierbare Mindestpasswortlänge durchsetzen; ist keine Mindestlänge konfiguriert, gibt es aktuell keine serverseitige Längen- oder Komplexitätsprüfung.
Ergebnis: Bei `PasswordMinLength = 0` (Standardfall vieler Bestandskonten denkbar) akzeptiert das System beliebig kurze Passwörter für interne Benutzer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/UsersBL.cs (IsValidAppUserPassword, Zeilen 124-130; UpdatePassword, Zeilen 101-122) - Begründung: Durchgesetzte, aber schwache/optionale Regel; kein Komplexitäts-Check im gesamten `UsersBL`.
Prüfidee: Datenbankabfrage im Referenzsystem: Verteilung der Werte `Sichbenu.PasswordMinLength` (wie viele Konten haben 0/NULL?). Ergänzend prüfen, ob Passwort-Richtlinien (Sonderzeichen, Historie, Ablaufdatum) irgendwo anders im Code (z. B. Windows-Domänenrichtlinie bei AD-Login) durchgesetzt werden.
Konsolidierungshinweis: Kontrastiert SEC-20; wichtiger HYPOTHESE-Kandidat für Zielsystem-Härtung.
Status: belegt; Lücke: keine erzwungene Passwortkomplexität für interne Konten im untersuchten Code gefunden (nur Längenprüfung, optional)
---
### Kandidat SEC-22
Ebene: SyRS
Typ: funktional; Sicherheit
Akteur: Mitarbeiter, Kunde (Selbstständige Passwortänderung)
Vorbedingung: Konto nutzt keine externe Authentifizierung (AD/OIDC)
Fakt: `ChangeOwnPassword` verlangt das aktuelle Passwort, vergleicht dessen SHA1-Hash mit dem gespeicherten Wert, und verweigert die Änderung für Benutzer mit `AuthentificationKind.WindowsAuth`/`OpenIdConnectAuth` oder gesetztem `OpenIdConnectSubjectIdentifier` bzw. wenn die Systemauthentifizierung global auf AD/OIDC steht.
Aussage: Das System soll eine Selbstständige Passwortänderung nur nach Bestätigung des aktuellen Passworts zulassen und für extern authentifizierte Konten (AD/Microsoft) grundsätzlich verweigern.
Ergebnis: Fehlermeldungen: "Das aktuelle Passwort ist nicht korrekt." bzw. "Das c-entron Passwort kann für Benutzer mit externer Anmeldung (Active Directory / Microsoft Entra) nicht geändert werden."
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/UsersBL.cs (ChangeOwnPassword, Zeilen 56-99) - Begründung: Vollständige, durchgesetzte Fallunterscheidung inkl. Re-Authentifizierung.
Prüfidee: Prüfen, ob bei falscher Passworteingabe hier ebenfalls eine Rate-Limitierung/Lockout existiert (im gesichteten Code nicht gefunden, siehe SEC-23-Lücke).
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-23
Ebene: SyRS
Typ: nicht-funktional (Sicherheit) / HYPOTHESE
Akteur: Angreifer (Brute-Force), Mitarbeiter, Kunde
Vorbedingung: -
Fakt: Im gesamten durchsuchten Login-/Passwort-Code (`BasicAuthenticator`, `WebAccountAuthenticator`, `UsersBL`, `WebAccountBL`) wurde **keine** Logik für fehlgeschlagene Login-Zähler, Konto-Sperrung nach X Fehlversuchen oder Rate-Limiting gefunden (Suche nach `FailedLogin`, `LoginAttempt`, `Lockout`, `AccountLocked`, `BruteForce` lieferte keine Treffer in Login-Codepfaden).
Aussage: Das System soll wiederholte fehlgeschlagene Anmeldeversuche erkennen und nach einer definierten Schwelle temporär sperren bzw. verzögern (Brute-Force-Schutz), um Passwort-Rate-Angriffe zu verhindern.
Ergebnis: -
Belege:
- [KONTEXT] Negativrecherche via Grep über src/backend (Muster `FailedLogin|LoginAttempt|Lockout|AccountLocked|BruteForce`) - Begründung: Kein Treffer in den Authentifizierungs-BLs; einziger Treffer war unrelated (`AccountSearchBL.cs`, fachlich andere Bedeutung von "Account").
Prüfidee: Gezielt prüfen, ob Rate-Limiting auf Infrastrukturebene (Reverse Proxy/WAF/API-Gateway) statt im Anwendungscode umgesetzt ist, sowie ob Active-Directory-eigene Kontosperrrichtlinien dies für AD-Logins abdecken.
Konsolidierungshinweis: Kritischer Punkt für Sicherheitsanforderungen der Zielarchitektur.
Status: HYPOTHESE (fehlender Beleg für Brute-Force-Schutz auf Anwendungsebene; könnte auf Infrastruktur-/AD-Ebene liegen, was in diesem Code-Cluster nicht einsehbar ist)
---
### Kandidat SEC-24
Ebene: SwRS
Typ: Daten / Architektur
Akteur: System (intern)
Vorbedingung: -
Fakt: `AppRightsBL.CheckRightsFromUser`/`HasUserRight` ermitteln Rechte über Rohabfragen `SELECT st.Recht FROM dbo.Sichtrus st INNER JOIN dbo.Sichmemb sm ON sm.Gruppe = st.Gruppe WHERE sm.Benutzer = :UserI3D`; `HasUserRight` cached das Ergebnis pro Request über `Session.Advanced.Cache.GetOrAdd($"AllRightsFromAppUser{appUserI3D}", …)`. Rechteprüfungs-Muster (`HasUserRight(`, `CheckRightsFromUser`, `HasRights(`) kommen in mindestens 345 Fundstellen über 105 BL-Klassen und zusätzlich 160 Fundstellen über 79 WPF-ViewModel-Klassen vor.
Aussage: Das System soll Rechteprüfungen konsistent über eine gemeinsame Datenquelle (`Sichtrus`/`Sichmemb`) durchführen, auch wenn der Prüfaufruf selbst dezentral in jeder einzelnen Business-Logik-Klasse und jedem ViewModel erfolgt statt über einen zentralen Interceptor/Middleware-Mechanismus.
Ergebnis: Konsistente Rechtebasis, aber hohe Streuung der Aufrufstellen - Risiko vergessener Prüfungen bei neuen Funktionen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs (CheckRightsFromUser Zeilen 95-111, HasUserRight Zeilen 644-649) - Begründung: Zentrale Datenzugriffslogik.
- [KONTEXT] Grep-Auswertung `HasUserRight\(|CheckRightsFromUser|HasRights\(` über src/backend/Centron.BL (345 Treffer/105 Dateien) und src/centron/Centron.WPF.UI (160 Treffer/79 Dateien) - Begründung: Belegt Streuungsgrad quantitativ.
Prüfidee: Für die Neuimplementierung: Machbarkeit eines zentralen Policy-/Authorization-Middleware-Ansatzes (z. B. Attribut-/Decorator-basiert) statt manueller Einzelprüfungen bewerten.
Konsolidierungshinweis: Bündelt Erkenntnis aus SEC-02/SEC-03 auf technischer Ebene.
Status: belegt
---
### Kandidat SEC-25
Ebene: SwRS
Typ: Daten
Akteur: System (intern), Entwickler (Skript-Autor)
Vorbedingung: -
Fakt: Jedes Recht ist eine `int`-Konstante in `UserRightsConst.cs`, die exakt der Primärschlüssel-Spalte `I3D` der Tabelle `Sichrech` entspricht (Kommentar im Code: "NEW .NET MODULE RIGHTS START AT 20800000", "NEXT ID: 20800174"). Neue Rechte werden ausschließlich über DB-Skripte angelegt (`ScriptHelpers.AddRightIfNotExists(I3D, OwnerRecht, Text, Beschreibung)`), niemals direkt per SQL empfohlen.
Aussage: Das System soll Rechte-Identifikatoren als stabile, fortlaufend vergebene Ganzzahl-IDs verwalten, die per kontrolliertem Migrationsskript (nicht per Ad-hoc-SQL) angelegt werden.
Ergebnis: Rechte-IDs sind über Datenbankmigrationen (nicht Code-Deploy) verteilt und damit umgebungsübergreifend synchronisierungspflichtig.
Belege:
- [PRIMÄR] src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/Administration/Rights/UserRightsConst.cs (Zeilen 10-16) - Begründung: Kommentar zur ID-Vergabe-Konvention.
- [PRIMÄR] docs/guides/development/add-a-new-right.md (gesamt) - Begründung: Vorgeschriebener Prozess inkl. Codebeispiel `AddRightIfNotExists`.
Prüfidee: Für Zielsystem: Bewertung, ob GUID-basierte oder feature-flag-basierte Rechte-IDs (statt inkrementeller Integer aus Legacy-DB) sinnvoller sind.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat SEC-26
Ebene: SwRS
Typ: Sicherheit / HYPOTHESE (technische Schwäche)
Akteur: System (intern)
Vorbedingung: -
Fakt: Passwort-Hashing verwendet SHA1 (`CryptoUtils.CreatePasswordHash`, `SHA1Decoder.GetDecodedSHA1String`). Der Login-Vergleich in `BasicAuthenticator` erfolgt über `SHA1Decoder.GetDecodedSHA1String(Auth.Password)` gegen das gespeicherte `AppUser.Password`-Feld **ohne** erkennbares benutzerindividuelles Salt an dieser Stelle; der Code selbst enthält den Kommentar `// TODO the password should be salted!!!` direkt über der Vergleichsabfrage. `WebAccountBL` verwendet dasselbe `SHA1Decoder`-Verfahren ohne Salt für Kundenpasswörter.
Aussage: Das System soll Passwörter mit einem kryptographisch starken, gesalzenen Hash-Verfahren (z. B. bcrypt/Argon2/PBKDF2) speichern statt mit unsalzenem SHA1.
Ergebnis: Aktuell: SHA1-Hash ohne Salt, laut Entwicklerkommentar selbst als Mangel bekannt - erhöhtes Risiko bei Datenbank-Kompromittierung (Rainbow-Table-Angriffe).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs (Zeilen 46-50, insb. Kommentar Zeile 48) - Begründung: Im Code selbst als bekannter Mangel dokumentiert ("TODO").
- [PRIMÄR] src/backend/Centron.BL/Core/CryptoUtils.cs (Zeilen 15-34) - Begründung: `CreatePasswordHash` nutzt zwar einen `salt`-Parameter (SHA1(pwd+salt)), dieser wird jedoch beim eigentlichen Login-Vergleich in `BasicAuthenticator`/`WebAccountBL` nicht verwendet - dort kommt direkt `SHA1Decoder.GetDecodedSHA1String(password)` ohne Salt zum Einsatz.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Logins/WebAccountBL.cs (Zeilen 56, 192, 253, 415, 480) - Begründung: Gleiches unsalzenes SHA1-Muster für Kundenpasswörter, mehrfach repliziert.
Prüfidee: Mit Entwicklung/Produktverantwortlichen klären, ob eine Migration auf gesalzene, langsame Hash-Verfahren (bcrypt/Argon2id) für die Zielarchitektur zwingend vorausgesetzt wird (Sicherheitsanforderung, nicht nur funktional).
Konsolidierungshinweis: Zentraler Befund für die Sicherheitsspezifikation des Zielsystems; unabhängig von SEC-08/SEC-20/SEC-21 relevant.
Status: belegt; Workaround/bekannter Mangel (Code-Kommentar bestätigt die Schwäche als bekannt, aber nicht behoben)
---
### Kandidat SEC-27
Ebene: SwRS
Typ: Sicherheit
Akteur: Administrator (Kontoanlage/-änderung), Kunde (Empfänger)
Vorbedingung: Neuanlage oder Passwortänderung eines Web-Accounts durch einen Mitarbeiter
Fakt: `SendWebAccountPasswordMail` versendet das neue Klartext-Passwort direkt per E-Mail an den Kunden (`mailTemplate.Body.Replace("@@Passwort@@", newPassword)`), ohne Einmal-Link oder Aufforderung zur sofortigen Änderung im Code ersichtlich.
Aussage: Das System soll bei administrativer Neuvergabe eines Kundenpassworts keinen Klartext-Passwortversand per E-Mail vornehmen, sondern einen sicheren Reset-Mechanismus (Einmal-Link mit Ablaufzeit) verwenden.
Ergebnis: Das Passwort ist im E-Mail-Postfach des Kunden dauerhaft im Klartext einsehbar (E-Mail-Server-Logs, Postfach-Kompromittierung).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/WebAccountBL.cs (SendWebAccountPasswordMail, Zeilen 529-577, insb. Zeile 563) - Begründung: Durchgesetztes Verhalten, direkt im Mailversand-Code sichtbar.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Logins/WebAccountBL.cs (CreateWebAccountWithContacts Zeilen 449-454, UpdateWebAccount Zeilen 490-495) - Begründung: Zwei Aufrufstellen (Neuanlage, Änderung) bestätigen wiederkehrendes Muster.
Prüfidee: Klären, ob dies bewusste Produktentscheidung (Kundenservice-Anforderung) oder unbeabsichtigte Sicherheitslücke ist; Alternative (Reset-Link) für Zielsystem vorschlagen.
Konsolidierungshinweis: Ergänzt SEC-26 als weiterer Klartext-Passwort-Befund.
Status: belegt
---
### Kandidat SEC-28
Ebene: SwRS
Typ: Architektur / HYPOTHESE (Redundanz)
Akteur: System (intern)
Vorbedingung: -
Fakt: Es existieren zwei voneinander unabhängige 2FA-Subsysteme im Code: (1) `TwoFactorAuthBL` mit `RadiusTwoFactorValidator`/`EmailTwoFactorValidator` für den allgemeinen Login (siehe SEC-05/14-16), und (2) `TwoFactorAuthenticationBL` (`Centron.BusinessLogic.TwoFactorAuthenticator`), das eine TOTP/Google-Authenticator-PIN gegen einen in der Personalverwaltung hinterlegten Schlüssel prüft (`ValidateAuthenticationPin` via `Centron.Core.GoogleAuthenticator.TwoFactorAuthenticator.ValidatePin`). Beide haben eigene Datenhaltung (`TwoFactorAuthLastLogin` vs. `NamedQueryEnums.PasswordManager.GetAppUserTwoFactorAuthKey`).
Aussage: Das System soll eine einheitliche Zwei-Faktor-Authentifizierungs-Infrastruktur nutzen, statt für unterschiedliche Anwendungsfälle (allgemeiner Login vs. Passwort-Manager-Bereich) getrennte, unabhängige 2FA-Mechanismen zu pflegen.
Ergebnis: -
Belege:
- [PRIMÄR] src/backend/Centron.BL/TwoFactorAuthenticator/TwoFactorAuthenticationBL.cs (ValidateAuthenticationPin, Zeilen 43-54) - Begründung: Eigenständige TOTP-Prüfung, referenziert weder `TwoFactorAuthBL` noch `TwoFactorUser`.
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorAuthBL.cs (gesamt) - Begründung: Vollständig getrenntes System für den Login-Flow.
Prüfidee: Klären, wo/wann `TwoFactorAuthenticationBL.ValidateAuthenticationPin` tatsächlich im Produktivbetrieb aufgerufen wird (z. B. beim Öffnen einzelner Passwort-Manager-Einträge) - in dieser Recherche wurde nur die Definition, nicht der Aufrufkontext geprüft.
Konsolidierungshinweis: Ergänzt SEC-05; ggf. im Zielsystem zu einem einzigen 2FA-Dienst konsolidieren.
Status: HYPOTHESE (Aufrufkontext/Nutzungshäufigkeit von TwoFactorAuthenticationBL im gesichteten Code nicht abschließend verifiziert, nur Definition gelesen)
---
### Kandidat SEC-29
Ebene: SwRS
Typ: Daten / Sicherheit (Altlast)
Akteur: System (intern)
Vorbedingung: -
Fakt: Im Legacy-Modul `PasswordManagementArea` legt `PasswordManagementKeywordBL.AddNewKeyword` einen neuen `PasswordManagementKeyword` mit `keyword.Salt = ""` und `keyword.Password = ""` an (keine tatsächliche Verschlüsselung/Speicherung des übergebenen Klartext-Parameters `password` erkennbar); `GetDecryptedKeywordById` gibt `keyword.Password` unverändert zurück, obwohl ein Kommentar `// decryption` eine Entschlüsselung suggeriert, die im Code nicht stattfindet.
Aussage: Das System soll keine Kennwortfelder mit leerem/fehlendem Verschlüsselungswert persistieren; auffällige Diskrepanz zwischen Kommentar ("decryption") und tatsächlicher Implementierung deutet auf unvollständigen oder toten Code hin.
Ergebnis: Im aktuellen Code werden Kennwörter über diesen Pfad faktisch nicht gespeichert (leerer String), was auf ein nicht mehr aktiv genutztes/abgelöstes Modul hindeutet (das produktiv genutzte Passwort-Manager-Modul ist vermutlich `PasswordManagerBL`/`HotlineCustomItemBL` mit `AESCryptoLogic`, siehe SEC-07).
Belege:
- [PRIMÄR] src/backend/Centron.BL/PasswordManagementArea/PasswordManagementKeywordBL.cs (AddNewKeyword Zeilen 38-58, GetDecryptedKeywordById Zeilen 21-36) - Begründung: Direkter Code-Befund, Diskrepanz zwischen Kommentar und Implementierung.
- [KONTEXT] src/backend/Centron.BL/PasswordManager/PasswordManagerBL.cs (Zeile 700: `new AESCryptoLogic().EncryptText(...)`) - Begründung: Zeigt, dass an anderer Stelle im System eine echte Verschlüsselung (AES) für Zugangsdaten existiert - Kontrast zum Legacy-Modul.
Prüfidee: Prüfen, ob `PasswordManagementArea`-Modul überhaupt noch von der WPF-UI referenziert wird oder bereits vollständig durch das Hotline-basierte Passwort-Manager-Modul (`PasswordManagerBL`) ersetzt wurde; ggf. als "nicht migrieren" einstufen.
Konsolidierungshinweis: Nicht mit SEC-07/SEC-18/SEC-19 (aktives Passwort-Manager-Modul) verwechseln - dies ist ein separates Altmodul.
Status: HYPOTHESE (Funktionsstatus "aktiv genutzt vs. totes Altmodul" nicht abschließend verifiziert; nur Code-Analyse ohne UI-Referenzprüfung durchgeführt)
---
### Kandidat SEC-30
Ebene: SwRS
Typ: Sicherheit
Akteur: System (intern)
Vorbedingung: -
Fakt: Sitzungs-Ticket-IDs werden aus dem Gerätenamen und einem zufälligen 32-Byte-Salt gebildet: `CryptoUtils.CreateSalt(32)` (kryptographisch sicherer `RandomNumberGenerator.GetBytes`) gefolgt von `CryptoUtils.CreatePasswordHash(deviceId, salt)` (SHA1(deviceId+salt)) - im Gegensatz zum Passwort-Hashing (SEC-26) wird hier tatsächlich ein Zufalls-Salt verwendet.
Aussage: Das System soll Sitzungs-Ticket-Identifikatoren nicht vorhersagbar/erratbar gestalten, indem ein kryptographisch sicherer Zufallswert einfließt.
Ergebnis: Ticket-IDs sind nicht direkt aus Gerätename allein ableitbar, da ein zufälliges Salt einfließt; SHA1 als Hash-Funktion ist für diesen Zweck (Kollisionsresistenz eines Bezeichners, nicht Passwortschutz) weniger kritisch als bei SEC-26.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/TicketBL.cs (GetTicketSalt, Zeilen 166-170) - Begründung: Durchgesetzte Logik.
- [SEKUNDÄR] src/backend/Centron.BL/Core/CryptoUtils.cs (CreateSalt, Zeilen 15-18) - Begründung: Bestätigt Verwendung von `RandomNumberGenerator` (kryptographisch sicherer Zufallsgenerator), im Gegensatz zu z. B. `System.Random`.
Prüfidee: Prüfen, ob Ticket-IDs zusätzlich an Transport-Sicherheit (TLS) gebunden sind, da sie als Bearer-ähnliches Sitzungsmerkmal fungieren.
Konsolidierungshinweis: Kontrastiert mit SEC-26 (dort fehlt Salt-Nutzung beim Passwort-Vergleich).
Status: belegt
---
## Abdeckung
**Vollständig gelesen (Datei-Inhalt geprüft):**
- CentronRights.md
- docs/guides/development/add-a-new-right.md
- docs/guides/development/check-userrights.md
- docs/reference/security/developer-security.md
- docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md
- docs/reference/security/licensing-system.md
- src/backend/Centron.BL/PasswordManager/PasswordManagerBL.cs
- src/backend/Centron.BL/PasswordManagementArea/PasswordManagementBL.cs
- src/backend/Centron.BL/PasswordManagementArea/PasswordManagementKeywordBL.cs
- src/backend/Centron.BL/PasswordManagementArea/PasswordManagementAccessLogBL.cs
- src/backend/Centron.BL/PasswordManagementArea/PasswordManagementLogBL.cs
- src/backend/Centron.BL/PasswordManagementArea/PasswordManagementUpdateBL.cs
- src/backend/Centron.BL/TwoFactorAuthenticator/TwoFactorAuthenticationBL.cs
- src/backend/Centron.BL/Administration/Rights/AppRightsBL.cs
- src/backend/Centron.BL/Administration/Rights/AppUserGroupBL.cs (Ausschnitt IsAdministratorGroup)
- src/backend/Centron.BL/Administration/Logins/Auth/Authenticator.cs
- src/backend/Centron.BL/Administration/Logins/Auth/BasicAuthenticator.cs
- src/backend/Centron.BL/Administration/Logins/Auth/ActiveDirectoryAuthenticator.cs
- src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs
- src/backend/Centron.BL/Administration/Logins/Auth/WebAccountAuthenticator.cs
- src/backend/Centron.BL/Administration/Logins/TicketBL.cs
- src/backend/Centron.BL/Administration/Logins/UsersBL.cs (Ausschnitt Login/Passwort)
- src/backend/Centron.BL/Administration/Logins/WebAccountBL.cs
- src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorAuthBL.cs
- src/backend/Centron.BL/Administration/Logins/TwoFactor/TwoFactorUser.cs
- src/backend/Centron.BL/Administration/Logins/TwoFactor/RadiusTwoFactorValidator.cs
- src/backend/Centron.BL/Administration/Logins/TwoFactor/EmailTwoFactorValidator.cs
- src/backend/Centron.BL/Core/CryptoUtils.cs
- src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/Administration/Rights/UserRightsConst.cs (erste ~100 Zeilen)
- src/backend/Centron.BL/WebServices/Administration/User/UserWebServiceBL.cs (Ausschnitt Passwort-Methoden)
**Nur überflogen / per Grep referenziert, nicht vollständig gelesen:**
- src/backend/Centron.BL/Security/PdfSigningBL.cs (nicht inhaltlich Passwort/Rechte-relevant für dieses Cluster, nur als Fundstelle für "CheckRight"-Muster registriert)
- src/backend/Centron.BL/Administration/Logins/Auth/OpenIdConnectAuthenticator.cs, OpenIdConnectAccountConnector.cs, FailingAuthenticator.cs, FallbackAuthenticator.cs (nur Dateiliste/Doku-Verweis, Inhalt nicht geöffnet)
- src/backend/Centron.BL/Administration/Logins/AuthenticationTicketBL.cs, EntraIDUsersBL.cs, WebRightsVisibility.cs (nicht geöffnet)
- src/backend/Centron.BL/Administration/Logins/TwoFactor/RadiusClient.cs, RadiusPaketParser.cs, ITwoFactorValidator.cs (nicht geöffnet, nur RadiusTwoFactorValidator als Aufrufer gelesen)
- src/backend/Centron.BL/PasswordManagementArea/PasswordManagementTypeBL.cs (nicht geöffnet)
- UserRightsConst.cs vollständig (nur die ersten 100 von vermutlich mehreren tausend Zeilen gelesen - Datei ist sehr umfangreich)
- src/webservice/Centron.Host/CentronHost.cs (JWT-Middleware-Konfiguration, laut Doku relevant, nicht geöffnet - Grund für HYPOTHESE-Status in SEC-17)
- src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs, RightsManagement-ViewModels (nur per Grep als Fundstellen identifiziert, nicht inhaltlich geprüft - Beleg für SEC-24 beruht auf Trefferzahl, nicht auf gelesenem Quelltext)
- src/backend/Centron.Entities/Entities/Administration/AppUser.cs (nur per Grep einzelne Property-Zeilen extrahiert, nicht als Ganzes gelesen)
**Bekannte Lücken:**
- Kein Zugriff auf `Centron.Core.GoogleAuthenticator.TwoFactorAuthenticator` (externe/interne Bibliothek) - PIN-Validierungsdetails (Zeitfenster, Algorithmus) nicht verifiziert.
- Aufrufkontext von `TwoFactorAuthenticationBL` (wo im Passwort-Manager-Flow tatsächlich verwendet) nicht ermittelt (SEC-28).
- Nutzungsstatus des Legacy-Moduls `PasswordManagementArea` (aktiv vs. tot) nicht anhand von UI-Referenzen verifiziert (SEC-29).
- Keine Analyse von Datenbank-Constraints (CHECK/UNIQUE) direkt in SQL-Skripten/Schema-Dateien durchgeführt - alle DB-Aussagen stammen aus C#-Code-Verhalten, nicht aus gelesenen DDL-Skripten.
- Web-Service-Controller-Ebene (z. B. `JwtAuthController.cs`, `CentronHost.cs`) wurde nur über die Doku, nicht im Code selbst geprüft.
- Rate-Limiting/Brute-Force-Schutz auf Infrastrukturebene (Reverse Proxy, WAF, Azure-Ebene) außerhalb des Codebasis-Scopes nicht einsehbar (SEC-23 bleibt daher HYPOTHESE statt gesicherter Negativbefund).
@@ -0,0 +1,647 @@
# RRE-Rohbefunde – Cluster ZEITERFASSUNG, PROJEKTE & TICKETS
Codebasis: CentronERP (C:\DEV\MasterArbeit\QuellCode\CentronERP). Alle Pfade relativ zum Repo-Root, sofern nicht absolut angegeben.
Diese Datei enthält Rohbefunde (keine finalen IDs) für die spätere Konsolidierung zu StRS/SyRS/SwRS gemäß ISO/IEC/IEEE 29148:2018.
---
### Kandidat TIME-01
Ebene: SwRS
Typ: Daten
Akteur: Mitarbeiter
Vorbedingung: Mitarbeiter erfasst eine Arbeitszeit auf einem Ticket (Helpdesk).
Fakt: `HelpdeskTimer` (Entity) besitzt u. a. `Start`, `Stop`, `Timer` (int, Sekunden), `LunchTime` (int?, Sekunden), `Calculable` (bool), `Article`, `HelpdeskTimerType`, `Contract`, `IsPlanned`, `IsSigned`, `OrderAssetItemI3D`/`DeliveryListAssetItemI3D`/`InvoiceAssetItemI3D` mit abgeleiteten Properties `IsAssignedToOrder/DeliveryList/Invoice` sowie `IsAssignedToAsset` (Kombination aller drei).
Aussage: Das System soll eine Ticketzeit mit Start-/Stopp-Zeitpunkt, Pausenzeit, Abrechenbarkeits-Flag, Artikel-, Vertrags- und Belegzuordnung als eigenständiges Datenobjekt führen.
Ergebnis: Datenmodell für Zeiterfassung auf Tickets bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Support/HelpdeskTimerArea/HelpdeskTimer.cs:11-62 - Begründung: vollständige Feldliste der Entity, inkl. abgeleiteter Zuordnungs-Properties.
Prüfidee: Neue Zeit anlegen und prüfen, dass alle Felder persistiert werden; IsAssignedToAsset bei Zuordnung zu Beleg true.
Konsolidierungshinweis: Basis-Datenmodell für TIME-02 bis TIME-22.
Status: belegt
---
### Kandidat TIME-02
Ebene: SwRS
Typ: funktional
Akteur: System
Vorbedingung: Eine Ticketzeit wird gespeichert.
Fakt: `HelpdeskTimerBL.SaveHelpdeskTimer` setzt beim Speichern automatisch `timer.Timer = (int)(timer.Stop.IgnoreMilliseconds() - timer.Start.IgnoreMilliseconds()).TotalSeconds`; `LunchTime` wird auf 0 defaultet falls null; `CreatedBy`/`CreatedDate`/`CreatedVersion`/`Employee` werden bei Bedarf aus dem aktuellen Benutzer gesetzt.
Aussage: Das System soll die Dauer einer Ticketzeit automatisch aus Start- und Stopp-Zeitpunkt berechnen und beim Fehlen den anlegenden Mitarbeiter sowie die erzeugende Softwareversion protokollieren.
Ergebnis: Automatische Serverseitige Berechnung/Default-Belegung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:353-407 (Methode `SaveHelpdeskTimer`, lokale Funktion `SetDefaultProperties`) - Begründung: unmittelbarer Code der Speicherlogik.
Prüfidee: Zeit mit Start=10:00, Stop=10:30 anlegen, prüfen dass Timer=1800 gespeichert wird.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-03
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter
Vorbedingung: Mitarbeiter möchte eine bestehende Ticketzeit bearbeiten.
Fakt: `HelpdeskTimerWebServiceBL.ThrowIfUserDoesntHaveRightToChangeHelpdeskTimers` prüft: Web-Account-Logins sind grundsätzlich ausgeschlossen; Neuanlage (`timerI3D <= 0`) ist immer erlaubt; Bearbeitung bestehender Zeiten erfordert das Recht `UserRightsConst.Sales.Customer.Helpdesk.EDIT_TIME`; besitzt der Nutzer zusätzlich nur `OWN_TIME_EDIT`, darf er nur Zeiten bearbeiten, deren `Employee` mit ihm identisch ist (Abgleich zusätzlich über verknüpften `EmployeeArticle.AppUser`, falls ein Artikel gesetzt ist).
Aussage: Das System soll die Bearbeitung fremder Ticketzeiten nur Mitarbeitern mit dem Recht "Zeiten bearbeiten" erlauben; Mitarbeiter mit dem eingeschränkten Recht "nur eigene Zeit bearbeiten" dürfen ausschließlich ihre eigenen Zeiten ändern.
Ergebnis: Rechtebasierte Bearbeitungssperre bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/Support/HelpdeskTimerWebServiceBL.cs:348-381 - Begründung: vollständige Rechtsprüfungslogik inkl. Fehlermeldungen.
Prüfidee: Mitarbeiter A (nur OWN_TIME_EDIT) versucht Zeit von Mitarbeiter B zu bearbeiten -> ResultException "Nutzer hat keine Rechte um Zeiten anderer Mitarbeiter zu bearbeiten".
Konsolidierungshinweis: Ergänzt TIME-05 (Löschrecht) und TIME-08 (Belegdatum-Recht) zum Gesamtrechtemodell der Zeiterfassung.
Status: belegt
---
### Kandidat TIME-04
Ebene: SwRS
Typ: Daten/Validierung
Akteur: System
Vorbedingung: Eine Ticketzeit soll gespeichert werden.
Fakt: `HelpdeskTimerWebServiceBL.ThrowIfInvalidHelpdeskTimer` verweigert das Speichern, wenn die Zeit bereits `IsAssignedToDeliveryList`, `IsAssignedToInvoice` oder `IsAssignedToOrder` ist (jeweils eigene Fehlermeldung); zusätzlich müssen `HelpdeskI3D != 0`, `Start.Year > 1980` und `Stop.Year > 1980` gelten.
Aussage: Das System soll eine Ticketzeit, die bereits einem Auftrag, Lieferschein oder einer Rechnung zugeordnet ist, gegen weitere Bearbeitung sperren.
Ergebnis: Schutz bereits abgerechneter Zeiten vor nachträglicher Änderung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/Support/HelpdeskTimerWebServiceBL.cs:327-346 - Begründung: explizite Guard-Kette mit fachlichen Fehlertexten.
Prüfidee: Zeit, die einer Rechnung zugeordnet ist, bearbeiten -> ArgumentException "...da sie einer Rechnung zugeordnet ist.".
Konsolidierungshinweis: Ergänzt TIME-06 (Löschsperre) - beide realisieren denselben fachlichen Schutz für Lesen vs. Löschen.
Status: belegt
---
### Kandidat TIME-05
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter
Vorbedingung: Mitarbeiter möchte eine Ticketzeit löschen.
Fakt: `HelpdeskTimerBL.DeleteHelpdeskTimer` prüft zunächst das Recht `UserRightsConst.Sales.Customer.Helpdesk.DELETE_HELPDESK_TIMER`; danach wird geprüft, ob `helpdeskTimer.IsAssignedToAsset` ist – falls ja, wird das Löschen mit "Die Helpdesk Zeit wurde einem Beleg zugewiesen. Löschen ist nicht möglich." verweigert. Beim erfolgreichen Löschen werden MyDay-Workitems entfernt (`MyDayBL.TryDeleteWorkItemsForHelpdeskTimer`), eine Historie geschrieben, externe Referenzen bereinigt und asynchron ein verknüpfter Kalendertermin gelöscht (`ScheduleBL.DeleteTimeSchedule`).
Aussage: Das System soll das Löschen einer Ticketzeit nur mit dem Recht "Zeiten löschen" erlauben und generell verweigern, sobald die Zeit einem Beleg (Auftrag/Lieferschein/Rechnung) zugeordnet ist.
Ergebnis: Lösch-Workflow mit Rechteprüfung, Belegsperre und Folgeaktionen (MyDay, Kalender, Historie) bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:554-602 - Begründung: vollständige Löschmethode inkl. Rechte- und Belegprüfung.
Prüfidee: Zeit ohne Belegzuordnung löschen -> erfolgreich, Historieneintrag und Kalendertermin-Löschung geschehen; Zeit mit Belegzuordnung löschen -> Fehler.
Konsolidierungshinweis: Verweist auf TIME-04 (analoge Sperre bei Bearbeitung) und TIME-18/21 (MyDay-/Kalender-Kopplung).
Status: belegt
---
### Kandidat TIME-06
Ebene: SwRS
Typ: Validierung
Akteur: Mitarbeiter
Vorbedingung: Mitarbeiter speichert eine bearbeitete Zeit in der Zeit-Abrechnungsansicht.
Fakt: `TimerBillingBL.SaveTimer` wirft eine `ResultException` mit Text "Die Zeit kann nicht gespeichert werden. Das Enddatum ist vor dem Startdatum (negative Dauer)." wenn `timer.Stop < timer.Start`.
Aussage: Das System soll das Speichern einer Ticketzeit verweigern, wenn deren Enddatum vor dem Startdatum liegt.
Ergebnis: Plausibilitätsprüfung Start/Stop bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/CustomerAssets/TimerBilling/TimerBillingBL.cs:482-483 - Begründung: direkte Validierung mit fachlicher Fehlermeldung.
Prüfidee: Zeit mit Stop < Start speichern -> Fehlermeldung, kein Speichern.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-07
Ebene: SyRS
Typ: Sicherheit
Akteur: Buchhaltung, Mitarbeiter
Vorbedingung: Ein Anwender öffnet die Einstellungen der Timer-Abrechnung (Belegdatum für Rechnung/Lieferschein).
Fakt: Commit baa9e7bd9b ("added rights check for editing invoice or delivery list date in the settings of timer billing") führt `BillingDateIsEnabled` ein: abhängig vom gewählten `ReceiptKind` wird `CentronCache.Instance.ReceiptSettings.CanChangeDateInInvoices` bzw. `CanChangeDateInDeliveryLists` ausgewertet; ist das Recht nicht vorhanden, wird das Datumsfeld deaktiviert und ein Info-Icon mit Tooltip "Sie besitzen nicht das Recht 'Datum der Rechnung/des Lieferscheins nach neuer Version / bei Neuanlage ändern'." angezeigt. Die zugrundeliegenden Rechte werden in `ReceiptWebServiceBL` aus `UserRightsConst.Sales.Customer.CustomerCommon.DeliveryList.CAN_CHANGE_DATE` bzw. `...Invoice.CAN_CHANGE_DATE` ermittelt.
Aussage: Das System soll die Möglichkeit, das Belegdatum eines aus Ticketzeiten erzeugten Rechnungs- oder Lieferschein-Belegs zu überschreiben, an das jeweilige belegspezifische Änderungsrecht koppeln und dem Anwender bei fehlendem Recht einen Hinweis anzeigen statt das Feld kommentarlos zu deaktivieren.
Ergebnis: Rechteabhängige Steuerung des Belegdatums in der Timer-Abrechnung bestätigt (jüngste fachliche Änderung im Cluster).
Belege:
- [PRIMÄR] Commit baa9e7bd9b - Begründung: expliziter Feature-Commit für dieses Verhalten, Betreff bestätigt fachlichen Zweck.
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingSettingsPageViewModel.cs:195-243,440-467,563-587 (Properties `BillingDateIsEnabled`/`ShowBillingDateNoteEnabledInfo`/`BillingDateNotEnabledInfo`, Methode `UpdateBillingDateIsEnabled`) - Begründung: konkrete Implementierung der Rechtekopplung inkl. UI-Text.
- [SEKUNDÄR] src/backend/Centron.BL/WebServices/Sales/Receipts/ReceiptWebServiceBL.cs:996-998 - Begründung: Ursprung der Rechte `CanChangeDateInInvoices`/`CanChangeDateInDeliveryLists`.
Prüfidee: Benutzer ohne CAN_CHANGE_DATE-Recht öffnet Timer-Abrechnungseinstellungen mit ReceiptKind=Invoice -> Datumsfeld deaktiviert, Info-Icon sichtbar.
Konsolidierungshinweis: Ergänzt TIME-03 (allgemeines Rechtemodell Zeiterfassung) um den Abrechnungskontext.
Status: belegt
---
### Kandidat TIME-08
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Ticketzeiten werden aus einem Ticket in einen Beleg (Rechnung/Lieferschein/Auftrag) übernommen; einzelne Zeiten sind als nicht abrechenbar (`Calculable == false`) markiert.
Fakt: `TimerBillingSettingsDTO.NonCalculableTimers` (Enum `NonCalculableTimersHandling`: `NoBilling`, `BillingWithPriceZero`) steuert `ReceiptItemTimerBL.InternalCreateTimerItem`: bei `NoBilling` werden nicht abrechenbare Zeiten komplett von der Belegposition ausgeschlossen (`return Result...AsSuccess(result)` ohne Position); bei `BillingWithPriceZero` wird die Position erzeugt, aber `item.BasePrice = 0` und ein eventueller Rabatt auf 0 gesetzt.
Aussage: Das System soll konfigurierbar steuern, ob als nicht abrechenbar markierte Ticketzeiten beim Erzeugen von Beleg-Positionen komplett übersprungen oder mit Preis 0 auf dem Beleg ausgewiesen werden.
Ergebnis: Zentrale Abrechnungsregel für nicht abrechenbare Zeit bestätigt (Timer→Rechnung-Risikobereich, PRIMÄR belegt).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:734-758,775-776,984-990 - Begründung: direkte Implementierung der Verzweigung anhand `NonCalculableTimersHandling`.
- [SEKUNDÄR] src/backend/Centron.Interfaces/Sales/Receipts/TimerBilling/NonCalculableTimersHandling.cs:3-8 - Begründung: Enum-Definition.
Prüfidee: Nicht abrechenbare Zeit mit Einstellung NoBilling abrechnen -> keine Position; mit BillingWithPriceZero -> Position mit Preis 0.
Konsolidierungshinweis: Kernbestandteil der Timer→Rechnung-Pipeline, siehe auch TIME-09, TIME-11, TIME-19.
Status: belegt
---
### Kandidat TIME-09
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Ticketzeiten mit unterschiedlichen Uhrzeiten/Wochentagen werden abgerechnet; ein Stundenzuschlagsschema ist hinterlegt (vertrags- oder global-basiert).
Fakt: `HelpdeskTimerBL.CalculateHourlySurchargeRateOverlaps` ermittelt pro Tag im Zeitraum der Ticketzeit die Überlappung mit den konfigurierten Zeitfenstern eines `HourlySurchargeRate`; je nach Wochentag (Montag–Sonntag) oder Feiertag wird ein individueller Prozentsatz (`RelevantPercentage`) angewandt. Die Rate wird zunächst über den Vertrag (`ReceiptContractHead`, via `GetReceiptHourlySurchargeRate`) ermittelt; existiert keine vertragsspezifische Rate, wird auf die globale Einstellung (`HourlySurchargeRatesBL.GetGlobalSettingsHourlySurchargeRate`) zurückgefallen.
Aussage: Das System soll bei der Abrechnung von Ticketzeiten automatisch tages- und wochentagsabhängige Stundenzuschläge berechnen, wobei ein vertragsspezifisches Zuschlagsschema Vorrang vor der globalen Einstellung hat.
Ergebnis: Zuschlagslogik als zentrale Abrechnungsregel bestätigt (Risikobereich, PRIMÄR belegt).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:173-341 - Begründung: vollständige Berechnungslogik inkl. Wochentags-Switch und Fallback-Reihenfolge.
Prüfidee: Ticketzeit an einem Sonntag mit vertragsspezifischer Rate abrechnen -> `SundayPercent` des Vertrags wird angewandt, nicht der globale Wert.
Konsolidierungshinweis: Ergänzt TIME-19 (Preis-/Rabattumrechnung bei Zuschlag).
Status: belegt
---
### Kandidat TIME-10
Ebene: SyRS
Typ: funktional
Akteur: Projektleiter, Buchhaltung
Vorbedingung: Alle abrechenbaren, noch offenen Ticketzeiten eines Tickets werden auf einen Beleg (Rechnung/Lieferschein) übernommen.
Fakt: `ReceiptItemTimerBL.CloseTickets` ermittelt für jeden nicht geschlossenen Ticket-Datensatz, ob noch berechenbare Zeiten ohne Zuordnung zu Rechnung/Lieferschein offen sind; ist das nicht der Fall, wird das Ticket als Kandidat zum automatischen Schließen markiert. Je nach `TicketCloseDialogOptions` (`Question`, `CloseAlways`, `AlwaysLeaveOpen`) wird entweder ein Bestätigungsdialog verlangt, automatisch geschlossen oder gar nichts unternommen.
Aussage: Das System soll nach vollständiger Abrechnung aller berechenbaren Ticketzeiten optional automatisch anbieten, das zugehörige Ticket zu schließen, gesteuert durch eine konfigurierbare Einstellung (Nachfragen/Immer schließen/Immer offen lassen).
Ergebnis: Automatisierter Ticket-Abschluss im Anschluss an die Abrechnung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:390-461 - Begründung: vollständige CloseTickets-Logik.
- [SEKUNDÄR] src/backend/Centron.Interfaces/Administration/Settings/SettingGroups/TicketCloseDialogOptions.cs:3-9 - Begründung: Enum-Definition der drei Optionen.
Prüfidee: Letzte offene berechenbare Zeit eines Tickets abrechnen, Einstellung=CloseAlways -> Ticket wird automatisch geschlossen.
Konsolidierungshinweis: Ergänzt TIME-26 (allgemeiner Ticket-Abschluss-Workflow HelpdeskCloseBL).
Status: belegt
---
### Kandidat TIME-11
Ebene: SwRS
Typ: funktional
Akteur: Mitarbeiter, Kunde
Vorbedingung: Ein Mitarbeiter lässt eine oder mehrere Ticketzeiten vor Ort vom Kunden unterschreiben.
Fakt: `HelpdeskTimerSignatureBL.AddSignature`/`SignMultipleTimers` speichert eine Signatur (`HelpdeskTimerSignatureCompact`) je Zeit; ist bereits eine Signatur vorhanden, wird der Aufruf ignoriert (`return null`); geplante Zeiten (`IsPlanned`) werden bei Sammelunterschrift übersprungen; jede Signatur wird protokolliert (`HelpdeskTimerLogBL.AddSignatureLog`). Das Entfernen einer Signatur (`RemoveSignatureFromTime`) erfordert das Recht `UserRightsConst.Sales.Customer.Helpdesk.DELETE_HELPDESK_SIGNATURE`.
Aussage: Das System soll die elektronische Unterschrift von Ticketzeiten unterstützen, dabei Mehrfachsignierung verhindern, geplante Zeiten von der Sammelunterschrift ausschließen und das Entfernen einer Signatur an ein eigenes Recht koppeln.
Ergebnis: Signaturworkflow inkl. Berechtigungsschutz bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerSignatureBL.cs:31-65,132-206 - Begründung: vollständige Signatur-Erzeugungs-, Sammel- und Löschlogik.
Prüfidee: Zeit ohne Recht DELETE_HELPDESK_SIGNATURE entfernen lassen -> Fehler "Sie besitzen nicht das Recht...".
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-12
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Eine bestehende Ticketzeit wird verändert.
Fakt: `HelpdeskTimerLogBL.AddLog` vergleicht alte und neue Werte (`Start`, `Stop`, `Timer`, `Calculable`, `ExternalNote`, `InternalNote`, `HelpdeskTimerType`, `LunchTime`, `IsPlanned`, `Article`, `Contract`, `DeviceI3D`, `ArticleWorkItem`) und erzeugt bei Abweichung einen `HelpdeskTimerLog`-Eintrag mit lesbarer Änderungsbeschreibung je Feld ("Feld: 'alt' => 'neu'"); bei Neuanlage wird "Zeit wurde angelegt" protokolliert. Der Log-Aufruf ist über try/catch von der eigentlichen Speicherung entkoppelt (Fehler im Log verhindern das Speichern der Zeit nicht).
Aussage: Das System soll jede Änderung an einer Ticketzeit feldweise mit Alt-/Neuwert nachvollziehbar protokollieren.
Ergebnis: Lückenloses Änderungsprotokoll als Audit-Anforderung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerLogBL.cs:23-237 - Begründung: vollständige Log-Erzeugungslogik mit Feldvergleich.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:379-386 - Begründung: Aufrufstelle, Fehler beim Logging werden bewusst verschluckt.
Prüfidee: Start einer Zeit ändern -> Log-Eintrag mit "Start: 'alt' => 'neu'".
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-13
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (KI-Dienst)
Vorbedingung: Eine Ticketzeit mit externem Notiztext wird gespeichert; die KI-Textbewertung ist lizenziert und aktiviert.
Fakt: `HelpdeskTimerBL.SaveHelpdeskTimer` prüft `CheckAiLicenseAndSettings` (Setting `AutomaticalAiTextRatingForHelpdeskTimers`) und stößt bei Erfüllung asynchron (Fire-and-forget) `GetAiTextRatingForTimerAsync` an, welche den `ExternalNote`-Text an einen KI-Dienst zur Bewertung übergibt und das Ergebnis als JSON in `HelpdeskTimer.AiTextRatingJson` nachträglich speichert (eigene DAOSession, unabhängig von der ursprünglichen Transaktion).
Aussage: Das System soll optional den Freitext einer Ticketzeit automatisiert durch einen KI-Dienst bewerten lassen, ohne den Speichervorgang der Zeit selbst zu verzögern.
Ergebnis: Asynchrone KI-Qualitätsbewertung von Zeitnotizen bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:421-466 - Begründung: vollständige Fire-and-forget-Logik inkl. Lizenzprüfung.
Prüfidee: Zeit mit Notiztext bei aktivierter Einstellung speichern -> AiTextRatingJson wird nachträglich befüllt.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-14
Ebene: SyRS
Typ: Schnittstelle
Akteur: Externes System (DocBee)
Vorbedingung: Ein externes mobiles Zeiterfassungssystem (DocBee) übermittelt eine Zeitbuchung.
Fakt: `DocBeeTicketTimerBL.SaveDocBeeTicketTimer` validiert Pflichtfelder: `ReferenceNumber`, `ExternalId`, `StartTime`/`EndTime` (beide != default, `EndTime > StartTime`), `EmployeeI3D > 0`; bei `DistanceInKm > 0` (Fahrtstrecke) ist zusätzlich ein existierender `ArticleI3D` Pflicht. Existiert bereits ein Ticket über `ObjectExternalReferences` zur `ReferenceNumber`, wird die Zeit dort angehängt, sonst wird automatisch ein neues Ticket für den referenzierten Kunden angelegt.
Aussage: Das System soll über eine Schnittstelle externe Zeitbuchungen (DocBee) mit definierten Pflichtfeldern entgegennehmen, bestehenden Tickets zuordnen oder bei Bedarf automatisch ein neues Ticket anlegen.
Ergebnis: Externe Zeiterfassungs-Schnittstelle mit Validierungsregeln bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/Connectors/DocBeeTicketTimerBL.cs:70-145 - Begründung: vollständige Validierungs- und Zuordnungslogik der Schnittstelle.
Prüfidee: DocBee-Zeitbuchung ohne ArticleI3D bei DistanceInKm>0 senden -> Fehler "ArticleI3D is required for travel entries.".
Konsolidierungshinweis: Ergänzt TIME-15 (Statusmapping derselben Schnittstelle).
Status: belegt
---
### Kandidat TIME-15
Ebene: SwRS
Typ: Schnittstelle
Akteur: Externes System (DocBee)
Vorbedingung: Eine DocBee-Zeitbuchung enthält ein Status-Feld.
Fakt: `DocBeeTicketTimerBL.MapStatusToBillingState` bildet den externen Status-String auf ein internes `StateEnum` ab: "Billable"→Billable, "Reserved"/leer→Reserved (Default), "DoNotInvoice"→DoNotInvoice, "Cancelled"→Cancelled. `Cancelled` bei einer bereits existierenden Zeit löst deren Löschung über `HelpdeskTimerBL.DeleteHelpdeskTimer` aus; `Billable` setzt `timer.Calculable = true`, alle anderen Werte `false`. Weicht die übermittelte "billable time" bzw. "actual time" von der berechneten Dauer ab, wird die Differenz als `LunchTime` (Pause) verbucht, da c-entron stets über `Timer` abrechnet.
Aussage: Das System soll den von DocBee übermittelten Abrechnungsstatus auf die interne Abrechenbarkeits- und Löschlogik der Ticketzeit abbilden, inklusive automatischer Stornierung bei Statuswechsel auf "Cancelled".
Ergebnis: Statusmapping und Storno-Verhalten der externen Schnittstelle bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/Connectors/DocBeeTicketTimerBL.cs:111-177,411-550 - Begründung: vollständige Mapping- und Storno-Logik inkl. Enum-Definition.
Prüfidee: DocBee sendet Status "Cancelled" für existierende ExternalId -> zugehörige HelpdeskTimer wird gelöscht (sofern nicht bereits abgerechnet).
Konsolidierungshinweis: Ergänzt TIME-14; nutzt dieselbe Löschsperre wie TIME-05 (Kommentar im Code verweist explizit darauf).
Status: belegt
---
### Kandidat TIME-16
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter
Vorbedingung: Ein Mitarbeiter bucht im Rahmen einer Ticketbearbeitung Material (Ersatzteile) auf das Ticket.
Fakt: `HelpdeskTimerArticleBookingBL.BookArticle` legt eine Beleg-Position mit `OriginKind = ReceiptItemOrigin.Helpdesk`, `OriginReceiptI3D = Helpdesk.I3D`, `OriginReceiptItemI3D = timer.I3D` in einem Lieferschein oder einer Rechnung an (nur diese zwei Belegarten unterstützt); existiert bereits ein offener, nicht abgeschlossener Beleg dieser Art für das Ticket, wird eine neue Version davon verwendet, sonst ein neuer Beleg angelegt mit Freitext "Die folgenden Positionen stammen aus dem Ticket {Nummer}.".
Aussage: Das System soll gebuchtes Material zu einer Ticketzeit als Position in einem Lieferschein oder einer Rechnung erfassen und dabei bevorzugt einen bereits offenen Beleg des Tickets weiterverwenden statt jedes Mal einen neuen zu erzeugen.
Ergebnis: Materialbuchung auf Ticketebene mit Belegwiederverwendung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerArticleBookingBL.cs:105-173,314-356 - Begründung: vollständige Buchungs- und Beleg-Wiederverwendungslogik.
Prüfidee: Zweites Material auf dasselbe Ticket buchen, während der erste Lieferschein noch offen ist -> neue Version desselben Lieferscheins statt neuer Beleg.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-17
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Eine mit "Mein Tag" (MyDay) verknüpfte Ticketzeit wird geändert oder gelöscht.
Fakt: `MyDayBL.TryUpdateWorkItemFromHelpdeskTimer` sucht alle `MyDayWorkItem`, deren `ConnectedHelpdeskTimer.I3D` der geänderten Zeit entspricht, und synchronisiert `StartTime`, `EndTime` und `BreakTime`; `TryDeleteWorkItemsForHelpdeskTimer` löscht diese Workitems beim Löschen der Zeit. Beide Methoden werden aus `HelpdeskTimerBL.SaveHelpdeskTimer` (bei Update, vor dem eigentlichen Speichern) bzw. `DeleteHelpdeskTimer` aufgerufen.
Aussage: Das System soll den Tagesplan-Eintrag (MyDay) eines Mitarbeiters automatisch mit Start-, End- und Pausenzeit synchronisieren, sobald die zugehörige Ticketzeit bearbeitet wird, und den Eintrag beim Löschen der Ticketzeit entfernen.
Ergebnis: Einseitige, automatische Synchronisation Ticketzeit → MyDay-Arbeitszeiteintrag bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MyDay/MyDayBL.cs:417-468 - Begründung: vollständige Synchronisations- und Lösch-Methoden.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs:371-374,587 - Begründung: Aufrufstellen aus der Zeiterfassung.
Prüfidee: Start einer Ticketzeit mit verknüpftem MyDay-Workitem ändern -> Workitem übernimmt neue Start-/Endzeit.
Konsolidierungshinweis: Ergänzt TIME-05 (Löschworkflow) und TIME-35 (MyDay allgemein).
Status: belegt
---
### Kandidat TIME-18
Ebene: StRS
Typ: Daten
Akteur: Buchhaltung
Vorbedingung: Die Abrechnung von Ticketzeiten zu Belegen soll konfiguriert werden.
Fakt: `TimerBillingSettingsDTO`/`HelpdeskSettings` bilden ein umfangreiches Regelwerk ab, u. a.: Gruppierung nach Zeittyp (`GroupTimersByType`) und gleichem Artikel (`GroupEqualArticles`), Rundung vor/nach Summierung (`RoundTimersBeforeGrouping`), Sortierung (`ChronologicalUp/Down/ByEmployee`), Einfügen von Ticket-Kurzbeschreibung/-Beschreibung, Sonderartikel am Ende oder direkt bei der Position, Übernahme der Ticketzeit als Leistungszeitraum (`UseTicketTimeAsServicePeriod`), Übertragung in Stücklisten (`TransferAllTimesToPartsList`/`TransferTimesWithSamePriceToPartsList`), Standard-Stücklistenkopf, Ersetzen von Stücklistenartikeln/-text, Sortierung der Stückliste nach Ticket.
Aussage: Das System soll der Buchhaltung ein umfangreiches, granular konfigurierbares Regelwerk zur Steuerung bereitstellen, wie Ticketzeiten zu Belegpositionen (inkl. Stücklisten) zusammengefasst, sortiert und dargestellt werden.
Ergebnis: Breites Konfigurationsmodell für die Timer-Abrechnung bestätigt.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Finances/TimerBilling/Pages/TimerBillingSettingsPageViewModel.cs:440-483 - Begründung: 1:1-Mapping der UI-Einstellungen auf die persistierten HelpdeskSettings-Felder.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:89-173,521-568 - Begründung: Verarbeitung dieser Einstellungen beim Erzeugen der Belegpositionen.
Prüfidee: Einstellung GroupTimersByType aktivieren -> Zeiten werden mit Titel-Trennzeile je Zeittyp gruppiert (Text aus AppSetting-Vorlage mit Platzhalter @@Typ@@).
Konsolidierungshinweis: Rahmen-Anforderung für TIME-08, TIME-09, TIME-19.
Status: belegt
---
### Kandidat TIME-19
Ebene: SwRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Eine Ticketzeit mit vollständig überlappendem Stundenzuschlag wird auf eine Belegposition übertragen, die bereits einen Rabatt trägt.
Fakt: `ReceiptItemTimerBL.InternalCreateTimerItem` berechnet den kombinierten Rabatt/Zuschlag: `combinedSurchargeRate = (1 + zuschlagsrate) * (1 - rabatt/100)`, daraus wird ein negativer "Rabatt" (= Aufschlag) `= (1 - combinedSurchargeRate) * 100` auf der Position gesetzt, sodass Zuschlag und bestehender Rabatt korrekt kombiniert werden (dokumentiertes Rechenbeispiel im Code: 25,00 € + 50 % Zuschlag − 21 % Rabatt = 29,625 €).
Aussage: Das System soll bei Ticketzeiten mit Stundenzuschlag den Zuschlag rechnerisch korrekt mit einem eventuell vorhandenen Rabatt auf der Belegposition kombinieren, statt beide unabhängig voneinander anzuwenden.
Ergebnis: Korrekte Kombination von Rabatt und Zeitzuschlag als Abrechnungsregel bestätigt (Risikobereich, PRIMÄR belegt).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs:953-982 - Begründung: vollständige Formel mit erläuterndem Rechenbeispiel im Quellcode.
Prüfidee: Zeit mit 50 % Zuschlag auf Position mit 21 % Rabatt abrechnen -> resultierender „Rabatt" auf der Position ist rechnerisch -18,5 %.
Konsolidierungshinweis: Ergänzt TIME-09 (Ermittlung des Zuschlagssatzes).
Status: belegt
---
### Kandidat TIME-20
Ebene: SyRS
Typ: Schnittstelle
Akteur: System
Vorbedingung: Eine Ticketzeit mit Terminbezug (geplant/gebucht) wird gespeichert oder gelöscht.
Fakt: `ScheduleBL.CreateOrUpdateTimeSchedule(HelpdeskTimer, AppUser)` wird nach jedem Speichern einer Zeit aufgerufen (aus `HelpdeskTimerBL.SaveHelpdeskTimer`); je nach Einstellung `OutlookAppointementHelpdeskTimeOvertake` (`None`/`Planned`/`All`) wird kein, nur bei geplanten (`IsPlanned`) oder immer ein Kalendertermin (`Schedule`, verknüpft über `ObjectType=HelpdeskTimerClass`) angelegt/aktualisiert und optional nach Exchange/Outlook synchronisiert. `ScheduleBL.DeleteTimeSchedule` setzt den zugehörigen Termin beim Löschen der Zeit auf `IsActive = false` (Soft-Delete).
Aussage: Das System soll Ticketzeiten optional automatisch als Kalendertermin abbilden und mit Outlook/Exchange synchronisieren, gesteuert durch eine globale Einstellung, sowie den Termin beim Löschen der Zeit deaktivieren statt physisch zu entfernen.
Ergebnis: Automatische Kalender-Synchronisation von Ticketzeiten bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Calendar/ScheduleBL.cs:2379-2508 - Begründung: vollständige Erzeug-/Update-/Soft-Delete-Logik inkl. Steuerung über Einstellung.
- [SEKUNDÄR] src/backend/Centron.BL/Calendar/CalendarBL.cs:52-89 - Begründung: Verwaltung der zugehörigen Synchronisationseinstellungen (`OutlookAppointementHelpdeskTimeOvertake` u. a.).
Prüfidee: Einstellung "Planned" wählen, ungeplante Zeit speichern -> kein Kalendertermin erzeugt; geplante Zeit speichern -> Termin wird erzeugt.
Konsolidierungshinweis: Ergänzt TIME-05 (Aufruf beim Löschen) und TIME-17 (analoge MyDay-Synchronisation).
Status: belegt
---
### Kandidat TIME-21
Ebene: SyRS
Typ: Sicherheit
Akteur: Mitarbeiter, Vorgesetzter
Vorbedingung: Ein Mitarbeiter ruft die Terminplanungsübersicht auf.
Fakt: `ScheduleBL.GetScheduleOverview` prüft zunächst `UserRightsConst.RIGHT_TERMINPLANUNG` (Grundzugriff); ohne `RIGHT_KALENDERANZEIGENALLE` darf nur der eigene Kalender (`filter.EmployeeI3D == eigene ID`) abgefragt werden, sonst Fehler "Sie haben nicht das Recht um fremde Kalender anzuschauen"; für den eigenen Kalender ist zusätzlich `RIGHT_KALENDERANZEIGENEIGENE` nötig, sonst "Sie haben nicht das Recht um Ihren Kalender zu sehen".
Aussage: Das System soll den Zugriff auf Kalenderdaten dreistufig absichern: Grundrecht Terminplanung, gesondertes Recht für fremde Kalender und gesondertes Recht für den eigenen Kalender.
Ergebnis: Mehrstufiges Berechtigungsmodell für Kalenderzugriff bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Calendar/ScheduleBL.cs:362-417 - Begründung: vollständige, dreistufige Rechteprüfung mit Fehlermeldungen.
Prüfidee: Mitarbeiter ohne RIGHT_KALENDERANZEIGENALLE fragt Kalender eines Kollegen ab -> Fehler "...fremde Kalender...".
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-22
Ebene: StRS
Typ: funktional
Akteur: Kunde, Mitarbeiter
Vorbedingung: Ein Mitarbeiter schickt einem Kunden Terminvorschläge zur Auswahl (z. B. für einen Service-Einsatz).
Fakt: `AppointmentRequestState` beschreibt einen linearen Workflow: `RequestOpen`(1) → `AppointmentProposalsSent`(2) → `AppointmentProposalAccepted`(3) ODER `AppointmentProposalsRejected`(4) → `Done`(5). `AppointmentRequestBL.HandleAppointmentRequestReply` verarbeitet die Kundenantwort über Microsoft Exchange (EWS): bei Ablehnung werden alle vorgeschlagenen Exchange-Termine gelöscht und `RequestState = AppointmentProposalsRejected` gesetzt; bei Annahme wird der akzeptierte Termin im Exchange-Kalender als "(Akzeptiert)" markiert, der Kunde als Pflichtteilnehmer ergänzt, die Kategorie von "Terminvereinbarung (offen)" auf "...(akzeptiert)" umgestellt und alle übrigen Vorschläge werden entfernt.
Aussage: Das System soll Terminanfragen an Kunden mit mehreren Terminvorschlägen unterstützen, deren Antwort (Annahme/Ablehnung) automatisiert im Exchange-Kalender nachvollziehen und den Anfragestatus entsprechend fortschreiben.
Ergebnis: Terminanfrage-Workflow mit Exchange-Integration bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/AppointmentRequests/AppointmentRequestBL.cs:29-114 - Begründung: vollständige Antwortverarbeitung inkl. Exchange-Aktionen.
- [SEKUNDÄR] src/backend/Centron.Interfaces/AppointmentRequests/AppointmentRequestState.cs:9-16 - Begründung: Statusdefinition.
Prüfidee: Kunde akzeptiert einen von drei Terminvorschlägen -> akzeptierter Termin bleibt mit Zusatz "(Akzeptiert)" bestehen, die anderen zwei werden entfernt, Status wechselt auf AppointmentProposalAccepted.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-23
Ebene: SwRS
Typ: Daten
Akteur: Projektleiter
Vorbedingung: Ein Ticketprojekt (TicketProject) wird angelegt oder gepflegt.
Fakt: `TicketProject` (Entity) besitzt `Status` (int, kein Enum im BL gefunden – "aktiv" ist hart als `Status == 1` codiert in `TicketProjectBL.CreateTicketProjectExpression`), `IsTemplate` (bool, trennt Vorlagen von echten Projekten), `PlannedStartDate`/`PlannedEndDate`, `ProgressInPercent`, `Number` (Belegnummer aus Nummernkreis `NumberGroupEnum.TicketProject`). `SaveOrUpdateTicketProject` erzwingt `ShortDescription` als Pflichtfeld und setzt bei fehlendem `PlannedStartDate` automatisch das aktuelle Datum.
Aussage: Das System soll Ticketprojekte mit Pflicht-Kurzbeschreibung, automatischer Nummernvergabe und einem Aktiv/Inaktiv-Status verwalten sowie Projektvorlagen von echten Projekten unterscheiden.
Ergebnis: Grunddatenmodell und Anlage-Validierung für Ticketprojekte bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/TicketProjects/TicketProject.cs:5-19 - Begründung: vollständige Feldliste.
- [PRIMÄR] src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:60-77,141-155 - Begründung: Anlage-/Validierungslogik und Statusfilterung.
Prüfidee: Ticketprojekt ohne ShortDescription speichern -> Guard-Fehler; Filter OnlyActive=true liefert nur Status==1.
Konsolidierungshinweis: Keine erkennbare Rechteprüfung beim Speichern (Beobachtung, siehe Abdeckung/Lücken).
Status: belegt
---
### Kandidat TIME-24
Ebene: SwRS
Typ: Daten
Akteur: Projektleiter, Mitarbeiter
Vorbedingung: Ein Ticketprojekt wird in Teilaufgaben untergliedert.
Fakt: `TicketProjectTask` besitzt `ParentTaskI3D` (Selbstreferenz für hierarchische Unteraufgaben), `EmployeeI3D` (zuständiger Mitarbeiter), `HelpdeskI3D` (optionale Verknüpfung zu einem konkreten Ticket), `PlannedDurationInMinutes`, `ProgressInPercent`, `IsTemplate`, `IsActive`. `TicketProjectBL.DeleteTicketProjectTask` löscht nicht physisch, sondern setzt `IsActive = false` (Soft-Delete). `GetAllSubTasks` traversiert rekursiv über `ParentTaskI3D`.
Aussage: Das System soll Projektaufgaben hierarchisch (Unteraufgaben) organisieren, optional mit einem konkreten Ticket verknüpfen und beim Löschen lediglich deaktivieren statt physisch zu entfernen.
Ergebnis: Hierarchische Aufgabenstruktur mit Soft-Delete und optionaler Ticketverknüpfung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:79-105,225-237 - Begründung: Soft-Delete-Implementierung und rekursive Unteraufgaben-Ermittlung.
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/TicketProjects/TicketProjectTask.cs - Begründung: Feldbestätigung (`ParentTaskI3D`, `HelpdeskI3D` u. a.), lt. Sub-Recherche.
Prüfidee: TicketProjectTask löschen -> Datensatz bleibt in der DB mit IsActive=false erhalten; GetTicketProjectTasks (IncludeInactive=false) liefert ihn nicht mehr.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-25
Ebene: SwRS
Typ: Daten
Akteur: Projektleiter
Vorbedingung: Zwischen Elementen eines Ticketprojekts (oder anderen Objekten) sollen zeitliche Abhängigkeiten definiert werden.
Fakt: `TicketProjectDependency` referenziert `PredecessorObjectKind`/`PredecessorObjectI3D` und `SuccessorObjectKind`/`SuccessorObjectI3D` (generisch über `CentronObjectKindNumeric`, nicht auf TicketProjectTask beschränkt) sowie einen `Type` vom Enum `TicketProjectDependencyType`: `FinishToStart`, `StartToStart`, `FinishToFinish`, `StartToFinish` – die vier klassischen Projektplan-/Gantt-Abhängigkeitstypen. `DeleteTicketProjectDependency` löscht physisch (kein Soft-Delete, im Gegensatz zu TicketProjectTask).
Aussage: Das System soll zwischen beliebigen Objekten (nicht nur Projektaufgaben) klassische Gantt-Abhängigkeiten (Ende-Anfang, Anfang-Anfang, Ende-Ende, Anfang-Ende) abbilden können.
Ergebnis: Generisches Abhängigkeitsmodell für die Projektplanung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:38-58 - Begründung: CRUD der Abhängigkeiten, physisches Löschen.
- [SEKUNDÄR] src/backend/Centron.Interfaces/ProjectTicket/TicketProjectDependencyType.cs (lt. Sub-Recherche) - Begründung: Enum-Definition der vier Abhängigkeitstypen.
Prüfidee: Abhängigkeit FinishToStart zwischen zwei TicketProjectTasks anlegen und wieder abfragen.
Konsolidierungshinweis: Zwei überlappende BL-Klassen (`TicketProjectBL` und separate `TicketProjectDependencyBL`) bieten ähnliche Abfragefunktion – Beobachtung für Konsolidierung/Bereinigung in der Neuimplementierung.
Status: belegt
---
### Kandidat TIME-26
Ebene: SyRS
Typ: Daten
Akteur: Mitarbeiter, Projektleiter
Vorbedingung: Der Bearbeitungsstatus eines Tickets (Helpdesk) soll ausgewertet werden (z. B. "ist offen/aktiv").
Fakt: Ticket-Zustände (`HelpdeskState`) sind keine feste Enumeration, sondern eine Stammdaten-Tabelle mit freien Einträgen (Felder u. a. `IsDeactivated`, `IsInternalCompanyBillingActive`, `ServiceBoardWebColor`, `ServiceBoardWebIcon`). Ob ein Ticket als "geschlossen" gilt, wird nicht über einen festen Wert geprüft, sondern über die konfigurierbare Einstellung `AppSettingsConst.HelpdeskClosedState`, die auf einen konkreten `HelpdeskState`-Datensatz verweist (`TicketListBL.CreateFilterExpression`: `f.HelpdeskStateI3D != closedI3D`). Ist die Einstellung nicht konfiguriert, wird der Aktiv-Filter gar nicht angewendet.
Aussage: Das System soll den "geschlossen"-Zustand eines Tickets nicht als festen Code, sondern als konfigurierbare Referenz auf einen frei definierbaren Ticketstatus behandeln.
Ergebnis: Konfigurierbares, stammdatenbasiertes Ticket-Statusmodell bestätigt (kein festes Enum "Offen/Geschlossen").
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskState.cs:6-15 - Begründung: Entity-Definition ohne Enum-Charakter.
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/TicketListBL.cs (lt. Sub-Recherche, Methode `CreateFilterExpression`) - Begründung: Implementierung der konfigurierbaren "geschlossen"-Prüfung.
Prüfidee: AppSetting HelpdeskClosedState auf einen bestimmten HelpdeskState-Datensatz setzen -> Tickets mit diesem Zustand werden aus "aktiv"-Filtern ausgeschlossen.
Konsolidierungshinweis: Wichtige Erkenntnis für SyRS: Statusmaschine ist datengetrieben, nicht code-fix – relevant für Web/SaaS-Neuimplementierung der Ticket-Zustandsverwaltung.
Status: belegt
---
### Kandidat TIME-27
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter
Vorbedingung: Ein Mitarbeiter schließt ein Ticket manuell oder das System schließt es automatisch nach vollständiger Abrechnung ab.
Fakt: `HelpdeskCloseBL.CloseHelpdesk`/`CloseHelpdeskForNotificationMethods` setzt beim Schließen `HelpdeskState = geschlossen`, `ClosedAt = DateTime.Now`, löscht offene ToDos des Tickets (`ToDoBL.DeleteHelpdeskToDos`), schreibt einen Statusänderungs-Historieneintrag (mit explizitem Workaround, da NHibernate durch Auto-Flush den alten Statuswert sonst nicht mehr für die Historie liefert), einen "Ticket abgeschlossen"-Historieneintrag, eine Account-Aktivität, und löst System- sowie optional externe/interne E-Mail-Benachrichtigungen aus (`CloseHelpdeskWithNotification`).
Aussage: Das System soll beim Abschließen eines Tickets automatisch offene Aufgaben entfernen, den Status- und Abschlussvorgang lückenlos in der Historie dokumentieren und interne wie externe Beteiligte per E-Mail informieren können.
Ergebnis: Vollständiger Ticket-Abschluss-Workflow bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs:120-157,200-362 - Begründung: vollständiger Abschluss-Workflow inkl. Historien- und Mail-Logik.
Prüfidee: Ticket mit offenen ToDos schließen -> ToDos werden gelöscht, Historieneintrag "Status wurde geändert" sowie "Ticket abgeschlossen" werden erzeugt.
Konsolidierungshinweis: Ergänzt TIME-10 (automatisches Schließen nach Timer-Abrechnung als Auslöser dieses Workflows).
Status: belegt
---
### Kandidat TIME-28
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Änderungen an einem Ticketprojekt oder dessen Aufgaben sollen nachvollziehbar sein.
Fakt: `TicketProjectLog` (Entity) besitzt `EventType` vom Enum `TicketProjectLogEventType`: `DateHasChanged`, `DescriptionHasChanged`, `MembersHaveChanged`, `TaskCreated`, `TaskMembersInformed`, `PlannedDurationHasChanged`, `ProgressHasChanged`, `OnlyStartDateHasChanged`, `OnlyEndDateHasChanged`, außerdem `LogLevel` (int, mehrstufig) und `MetaData`. Logeinträge können nach `MinLogLevel`, Zeitraum, `EventTypes`, `EmployeeI3Ds`, Projekt/Aufgabe gefiltert werden.
Aussage: Das System soll definierte, fachlich benannte Ereignistypen (Datums-, Beschreibungs-, Mitglieder-, Fortschrittsänderung u. a.) an Ticketprojekten und deren Aufgaben mit Log-Level protokollieren und filterbar bereitstellen.
Ergebnis: Strukturiertes, mehrstufiges Audit-Log für Ticketprojekte bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs:122-135,193-223 - Begründung: CRUD- und Filterlogik des Logs.
- [SEKUNDÄR] src/backend/Centron.Interfaces/ProjectTicket/TicketProjectLogEventType.cs (lt. Sub-Recherche) - Begründung: Enum-Definition der Ereignistypen.
Prüfidee: Fortschritt einer TicketProjectTask ändern -> Log-Eintrag mit EventType=ProgressHasChanged wird erwartet (Ereigniserzeugung selbst nicht in den gelesenen Dateien lokalisiert, nur Datenmodell/Filter – als Lücke vermerkt).
Konsolidierungshinweis: -
Status: belegt; Workaround (Ereigniserzeugung selbst außerhalb der gelesenen Dateien, nur Modell/Filter belegt)
---
### Kandidat TIME-29
Ebene: StRS
Typ: funktional
Akteur: Projektleiter, Vertrieb
Vorbedingung: Ein CRM-/Vertriebsprojekt (CrmProject, z. B. Kundenprojekt mit Umsatzprognose) wird angelegt oder ausgewertet.
Fakt: `CrmProject` verwaltet u. a. bis zu vier Berater- (`Adviser1-4I3D`) und Kontaktperson-Slots, `ProjectStateI3D`/`ProjectKindI3D`/`ProjectProbabilityI3D` (jeweils eigene Stammdaten-Entität statt Enum), Umsatz-/Margenwerte (auch monatlich), `DecisionDate`, `CloseProjectReason`. `CrmProjectBL.SaveCrmProject` erzwingt `Name` als Pflichtfeld, vergibt bei Neuanlage automatisch Nummer (`NumberGroupEnum.CRMProject`) und setzt `State = 1` (aktiv) fest. Das Recht `UserRightsConst.RIGHT_CRMPROJEKTONLYOWN` erzwingt bei fehlendem Vollzugriff eine Filterung auf Projekte, in denen der Mitarbeiter als Berater, Verantwortlicher oder Ersteller eingetragen ist.
Aussage: Das System soll Vertriebsprojekte mit mehreren Beratern/Kontaktpersonen, konfigurierbaren Status-/Art-/Wahrscheinlichkeits-Stammdaten sowie Umsatz-/Margenprognose verwalten und den Zugriff darauf optional auf eigene bzw. zugeordnete Projekte einschränken.
Ergebnis: Aktives Projektmanagement-Datenmodell (CrmProject, nicht das Legacy-„Project") mit Zugriffsbeschränkung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Customers/CrmProjects/CrmProject.cs (lt. Sub-Recherche) - Begründung: vollständige Feldliste.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CrmProjects/CrmProjectBL.cs:105-174,469-541 (lt. Sub-Recherche) - Begründung: Anlage-Validierung, automatische Nummernvergabe, Rechtefilterung `RIGHT_CRMPROJEKTONLYOWN`.
Prüfidee: Mitarbeiter ohne RIGHT_CRMPROJEKTONLYOWN-Ausnahme ruft Projektliste ab -> nur Projekte mit ihm als Berater/Verantwortlichem/Ersteller werden geliefert.
Konsolidierungshinweis: Abgrenzung zu TIME-30 (Legacy-„Project"-Entity, praktisch ungenutzt) wichtig für Scope der Neuimplementierung.
Status: belegt
---
### Kandidat TIME-30
Ebene: SwRS
Typ: Daten
Akteur: System
Vorbedingung: Das ältere, generische "Project"-Modul wird betrachtet.
Fakt: `ProjectBL` (`src/backend/Centron.BL/Projects/ProjectBL.cs`) besitzt nur zwei lesende Methoden (`GetProjectList()`, `GetProjectList(DateTime? filter)`), keinerlei Save/Delete/Statuswechsel-Logik; das zugehörige `Project`-Entity trägt deutschsprachige Feldnamen (`ProjektBeginn`, `ProjektGesperrtVon`, `AnsichtNurBeteiligte` u. a.) und wirkt im Vergleich zu `CrmProject`/`TicketProject` wie ein nicht mehr aktiv weiterentwickeltes Altsystem.
Aussage: Das System führt neben dem aktiven Ticketprojekt- und CRM-Projekt-Modul ein weiteres, funktional stark reduziertes Legacy-Projektmodul, dessen Migrationswürdigkeit für die Neuimplementierung gesondert zu prüfen ist.
Ergebnis: Architektonischer Befund: mind. drei parallele "Projekt"-Konzepte (Project, CrmProject, TicketProject) in der Codebasis.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Projects/ProjectBL.cs:1-36 - Begründung: vollständige, sehr kurze Klasse belegt den Legacy-Charakter direkt.
Prüfidee: Prüfen, ob `ProjectBL`/`Project`-Entity in der WPF-UI überhaupt noch referenziert wird (nicht Teil dieser Recherche).
Konsolidierungshinweis: Wichtig für StRS-Scope-Entscheidung: welches der drei Projektkonzepte wird in der Web/SaaS-Neuimplementierung fortgeführt.
Status: belegt; Workaround (Befund ist eine Beobachtung/Architekturhinweis, keine funktionale Anforderung im engeren Sinn)
---
### Kandidat TIME-31
Ebene: SyRS
Typ: funktional
Akteur: System
Vorbedingung: Eine wiederkehrende automatisierte Aufgabe (TaskManagementTask) erreicht ihren Ausführungszeitpunkt.
Fakt: `TaskManagementTask.Status` (Enum `ProjectStatus`: `Started=0`, `Paused=2`, `Finished=3`, Wert 1 ausgelassen) steuert `TaskManagementTaskBL.ExecuteTask`: bei `Finished` wird nichts getan; bei `Paused` ebenfalls nichts, wobei der Code-Pfad nach der Meldung ohne `return`-Anweisung weiterläuft (auffälliges Verhalten, siehe Prüfidee). Zwei Aktionstypen sind über Handler realisiert (`ITaskManagementActionHandler`): `TaskManagementHelpdeskActionHandler` (erzeugt automatisch ein Ticket) und `TaskManagementReportActionHandler` (versendet einen Report per E-Mail). Wiederholungen werden über vier Rhythmus-Typen (`TaskManagementDailyRecurrence`, `Weekly`, `Monthly`, `Yearly`) via `RecurrenceCalculator` berechnet; ein Task gilt als beendet, wenn `Recurrence.EndTime` überschritten oder `NumberOfRecurrence` erreicht ist.
Aussage: Das System soll wiederkehrende automatisierte Aktionen (automatische Ticketerstellung, automatischer Report-Versand) mit konfigurierbarem Wiederholungsrhythmus und einem dreistufigen Lebenszyklus (gestartet/pausiert/beendet) unterstützen.
Ergebnis: Automatisierte, wiederkehrende Aufgabenverwaltung mit zwei Aktionstypen bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TaskManager/TaskManagementTaskBL.cs:55-97,171-316,832-983 - Begründung: vollständige Speicher-, Ausführungs- und Wiederholungslogik.
- [SEKUNDÄR] src/backend/Centron.BL/TaskManager/ActionHandler/ITaskManagementActionHandler.cs:10-27 - Begründung: Handler-Vertrag für die zwei Aktionstypen.
Prüfidee: Task mit Status=Paused manuell ausführen lassen -> prüfen, ob trotz der Pause-Meldung tatsächlich (fälschlicherweise) weiterexekutiert wird, da im Code nach der Meldung kein `return` folgt (Verdacht auf funktionalen Fehler, für Neuimplementierung zu klären, nicht blind zu übernehmen).
Konsolidierungshinweis: Ergänzt TIME-32 (Rechte/Lizenz bei Ticketerstellung), TIME-33 (Nebenläufigkeitsschutz).
Status: belegt; Workaround (fehlendes `return` bei Paused-Fall ist ein im Code beobachtbarer, wahrscheinlicher Fehler – als Anforderung ist der SOLL-Zustand "pausierte Tasks werden nicht ausgeführt" zu spezifizieren, nicht das beobachtete Ist-Verhalten)
---
### Kandidat TIME-32
Ebene: SyRS
Typ: Sicherheit
Akteur: System, Mitarbeiter
Vorbedingung: Ein automatisierter Task vom Typ "Helpdesk-Aktion" wird ausgeführt (erzeugt ein neues Ticket).
Fakt: `TaskManagementHelpdeskActionHandler.Execute` prüft vor der Ticketerstellung die Lizenz `LicenseGuids.ServiceBoardWebDev` sowie das Recht `UserRightsConst.Sales.Customer.Helpdesk.ADD_NEW_HELPDESK` des ausführenden Benutzers – exakt dasselbe Recht, das auch bei manueller Ticketanlage erforderlich ist. Pflichtfelder der Aktion (`ValidateAction` in `TaskManagementTaskBL`) sind immer `Customer`, `State`, `ResponsiblePerson`; `Type`/`Priority`/`Category` sind zusätzlich pflicht, wenn die globalen Einstellungen `HelpdeskTypeFieldIsRequired`/`HelpdeskPriorityFieldIsRequired`/`HelpdeskMaincategoryFieldIsRequired` aktiv sind.
Aussage: Das System soll die automatische Ticketerstellung aus einer wiederkehrenden Aufgabe an dieselbe Lizenz- und Rechtebasis binden wie die manuelle Ticketanlage und dabei dieselben global konfigurierbaren Pflichtfeldregeln anwenden.
Ergebnis: Konsistente Rechte-/Pflichtfeldprüfung zwischen manueller und automatisierter Ticketerstellung bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TaskManager/ActionHandler/TaskManagementHelpdeskActionHandler.cs:50-58 - Begründung: direkte Lizenz- und Rechtsprüfung vor Ticketerstellung.
- [PRIMÄR] src/backend/Centron.BL/TaskManager/TaskManagementTaskBL.cs:603-657 - Begründung: vollständige `ValidateAction`-Methode mit bedingten Pflichtfeldern.
Prüfidee: Systembenutzer ohne ADD_NEW_HELPDESK-Recht als ausführender Kontext -> `ResultException` beim automatischen Ausführen des Tasks.
Konsolidierungshinweis: Ergänzt TIME-31.
Status: belegt
---
### Kandidat TIME-33
Ebene: SwRS
Typ: nicht-funktional
Akteur: System
Vorbedingung: Derselbe automatisierte Task könnte durch mehrere parallele Prozesse (z. B. mehrere Webservice-Instanzen) gleichzeitig ausgeführt werden.
Fakt: `TaskManagementTaskBL` sichert die Ausführung je Aktion und Tag über ein SQL-Server-Applikationslock (`sp_getapplock`, Resource `TMA_{ActionI3D}_{yyyyMMdd}`, `LockMode=Exclusive`, `LockOwner=Transaction`, `LockTimeout=0`); scheitert der Lock-Erwerb, wird eine Warnung "Task wird bereits von einer anderen Ausführung bearbeitet" zurückgegeben statt doppelt auszuführen. Zusätzlich verhindert eine Prüfung auf bereits existierenden `TaskManagementActionExecutedAt`-Eintrag für denselben Kalendertag eine wiederholte Ausführung (Idempotenz). Ein separater Reparaturmechanismus (`RepairMissingHelpdeskTickets`) erkennt und behebt Fälle, in denen ein Task als ausgeführt markiert wurde, das zugehörige Ticket aber durch einen Transaktions-Rollback verloren ging (Ticket 168438) – Reparatur nur für Tasks mit Status `Started`, um bereits pausierte/beendete Tasks nicht wiederzubeleben.
Aussage: Das System soll die parallele oder doppelte Ausführung derselben wiederkehrenden Aufgabe am selben Tag durch ein verteiltes Sperrverfahren und einen Idempotenz-Check verhindern und über einen Reparaturmechanismus sicherstellen, dass bei Ausführungsfehlern keine dauerhaft inkonsistenten Zustände (ausgeführt markiert, aber Ergebnis fehlt) bestehen bleiben.
Ergebnis: Nebenläufigkeitsschutz und Selbstheilungsmechanismus für automatisierte Aufgaben bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TaskManager/TaskManagementTaskBL.cs:673-715 - Begründung: Lock- und Idempotenzlogik.
- [PRIMÄR] src/backend/Centron.BL/TaskManager/TaskManagementTaskBL.cs:453-600 - Begründung: vollständiger Reparaturmechanismus inkl. Statusprüfung.
Prüfidee: Zwei parallele Ausführungsanfragen für denselben Task am selben Tag simulieren -> zweiter Aufruf erhält Warnung statt Doppelanlage eines Tickets.
Konsolidierungshinweis: -
Status: belegt
---
### Kandidat TIME-34
Ebene: SyRS
Typ: funktional
Akteur: Mitarbeiter, Teamleiter
Vorbedingung: Ein Arbeitstag eines Mitarbeiters (MyDay) ist am Folgetag noch nicht als abgeschlossen markiert.
Fakt: `MyDayNotificationsBL.GetDayNotFinalizedNotifications`/`GenerateDayNotFinalizedNotifications` ermittelt für Abteilungen mit aktivem MyDay alle Mitarbeiter ohne `MyDayFinalizedDay`-Eintrag für den letzten Arbeitstag (Wochenende wird übersprungen). Bestehen für einen Mitarbeiter ausschließlich Einträge vom Typ `Vacation`/`Sickness`, wird der Tag automatisch (ohne Benachrichtigung) als abgeschlossen markiert ("Automatisch abgeschlossen."); andernfalls wird eine E-Mail-Benachrichtigung an den Mitarbeiter sowie eine zusammenfassende Benachrichtigung an den Team-Leiter der Abteilung erzeugt. Ein Verhindern von Doppelversand erfolgt über `MyDayNotificationLog` (pro Typ/Datum/Mitarbeiter nur einmal).
Aussage: Das System soll Mitarbeiter automatisch erinnern, wenn ihr Arbeitstag nicht als abgeschlossen markiert wurde, dabei Urlaubs-/Krankheitstage automatisch als erledigt behandeln, den zuständigen Teamleiter zusätzlich informieren und Mehrfachbenachrichtigungen verhindern.
Ergebnis: Automatisierte Erinnerungs- und Eskalationslogik für unvollständige Tagesabschlüsse bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MyDay/MyDayNotificationsBL.cs:39-280 (lt. Sub-Recherche, insb. Z.119-233 `GenerateDayNotFinalizedNotifications`, Z.235-280 `GenerateTeamLeaderNotifications`) - Begründung: vollständige Erkennungs-, Auto-Abschluss- und Benachrichtigungslogik.
Prüfidee: Mitarbeiter ohne finalisierten Vortag und ausschließlich Urlaubseinträgen -> Tag wird automatisch abgeschlossen, keine Mail versendet; Mitarbeiter mit gemischten/keinen Einträgen -> Mail an Mitarbeiter und Teamleiter.
Konsolidierungshinweis: Ergänzt TIME-17 (MyDay-Grunddaten aus Ticketzeiten).
Status: belegt
---
### Kandidat TIME-35
Ebene: SwRS
Typ: Daten
Akteur: Mitarbeiter
Vorbedingung: Ein WorkItem (Tageseintrag) in "Mein Tag" wird automatisch aus mehreren Quellen vorgeschlagen.
Fakt: `MyDayBL.GetNewWorkItems` sammelt Vorschläge aus Outlook-Terminen, Telefonanrufen, Helpdesk-Zeiterfassungen sowie – fehlertolerant per try/catch (Fehler werden gesammelt statt den Aufruf abzubrechen) – aus externen Fernwartungs-Diensten (TeamViewer-REST-API, Supremo-REST-API) und Passwort-Manager-RDP-Sitzungen. Bereits vom Mitarbeiter verworfene automatische Vorschläge werden über `MyDayDismissedItem` (Schlüssel `UniqueId`) dauerhaft ausgeblendet. `SaveOrUpdateWorkItem` verhindert Duplikate anhand einer `UniqueId`, die bei generierten Einträgen aus Typ und Objekt-I3D abgeleitet wird.
Aussage: Das System soll Tageseinträge automatisch aus mehreren internen und externen Quellen (Kalender, Telefonie, Ticketzeiten, Fernwartungs-Tools) vorschlagen, dabei einmal verworfene Vorschläge dauerhaft nicht erneut anzeigen und Duplikate anhand einer eindeutigen Kennung vermeiden.
Ergebnis: Multi-Quellen-Vorschlagsmechanismus mit Duplikat- und Dismiss-Schutz für MyDay bestätigt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MyDay/MyDayBL.cs:132-164,285-309,474-563 (lt. Sub-Recherche) - Begründung: Speicher-, Dismiss- und Multi-Quellen-Sammellogik.
Prüfidee: Vom Mitarbeiter verworfenen TeamViewer-Vorschlag erneut abrufen (gleicher Zeitraum) -> Vorschlag erscheint nicht erneut.
Konsolidierungshinweis: Ergänzt TIME-17, TIME-34.
Status: belegt
---
## Abdeckung
**Direkt und vollständig gelesen (Methodenkörper, eigene Recherche):**
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerBL.cs
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerSettingsBL.cs
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerSignatureBL.cs
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerLogBL.cs
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerArticleBookingBL.cs
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerTypeBL.cs (teilweise)
- src/backend/Centron.BL/Sales/Support/HelpdeskCloseBL.cs
- src/backend/Centron.BL/Sales/Support/TicketProjectSettingsBL.cs
- src/backend/Centron.BL/Sales/CustomerAssets/TimerBilling/TimerBillingBL.cs
- src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs (erste ~1110 von 2112 Zeilen; Rest nicht gelesen, siehe Lücken)
- src/backend/Centron.BL/DataExchange/Connectors/DocBeeTicketTimerBL.cs (erste 150 Zeilen von ~552; MapStatusToBillingState/Enum über gezielten Grep vollständig erfasst)
- src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs (vollständig)
- src/backend/Centron.BL/TaskManager/TaskManagementTaskBL.cs (vollständig)
- src/backend/Centron.BL/TaskManager/ActionHandler/ITaskManagementActionHandler.cs (vollständig)
- src/backend/Centron.BL/TaskManager/ActionHandler/TaskManagementHelpdeskActionHandler.cs (vollständig)
- src/backend/Centron.BL/Time/TimingSettingsBL.cs (vollständig, generisch, kaum fachliche Substanz)
- src/backend/Centron.BL/Projects/ProjectBL.cs (vollständig)
- src/backend/Centron.BL/AppointmentRequests/AppointmentRequestBL.cs (vollständig)
- src/backend/Centron.BL/Calendar/CalendarBL.cs (vollständig)
- src/backend/Centron.BL/MyDay/MyDayBL.cs (Ausschnitt: TryUpdateWorkItemFromHelpdeskTimer/TryDeleteWorkItemsForHelpdeskTimer, Z.417-468)
- src/backend/Centron.Entities/Entities/Sales/Support/HelpdeskTimerArea/HelpdeskTimer.cs
- src/backend/Centron.Entities/Entities/CustomerArea/Support/HelpdeskState.cs
- src/backend/Centron.Entities/Entities/TicketProjects/TicketProject.cs
- Commit baa9e7bd9b (vollständiger Diff)
- Diverse Enum-Dateien via Grep verifiziert: TicketCloseDialogOptions, TimerSorting, NonCalculableTimersHandling, AppointmentRequestState.
**Über zwei parallel arbeitende Recherche-Subagenten abgedeckt (Methodenkörper gelesen, hier als SEKUNDÄR/PRIMÄR mit Verweis "lt. Sub-Recherche" übernommen, da nicht durch den Hauptagenten selbst mit Zeilennummer verifiziert):**
- src/backend/Centron.BL/TicketProjects/TicketProjectBL.cs (Cross-Check, deckungsgleich mit eigener Lektüre)
- src/backend/Centron.BL/Sales/Support/TicketProcess/TicketProcessBL.cs
- src/backend/Centron.BL/Sales/Support/TicketProjectDependencyBL.cs
- src/backend/Centron.BL/Sales/Support/TicketListBL.cs
- src/backend/Centron.BL/Administration/Logins/TicketBL.cs (bestätigt: kein Support-Ticket-Bezug, sondern Auth-Session-Tickets – daher nicht als TIME-Kandidat verwendet)
- src/backend/Centron.BL/TaskManager/ActionHandler/TaskManagementReportActionHandler.cs
- src/backend/Centron.BL/Projects/ProjectBL.cs (Cross-Check)
- src/backend/Centron.BL/Sales/Customers/CrmProjects/CrmProjectBL.cs
- src/backend/Centron.BL/MyDay/MyDayBL.cs (vollständig, 1592 Zeilen)
- src/backend/Centron.BL/MyDay/MyDayNotificationsBL.cs
- src/backend/Centron.BL/MyDay/MyDayWebServiceBL.cs (grob)
- src/backend/Centron.BL/Calendar/CalendarBL.cs (Cross-Check)
- src/backend/Centron.BL/AppointmentRequests/AppointmentRequestBL.cs (Cross-Check)
- src/backend/Centron.BL/Sales/Calendar/ScheduleBL.cs (Kalender-/Termin-Kernlogik, Kopplung an Helpdesk-Timer)
- Zugehörige Entities/Enums: CrmProject, TicketProjectTask, TicketProjectLog, TicketProjectLogEventType, TicketProjectDependency, TicketProjectDependencyType, MyDayWorkItem, MyDayWorkItemType, MyDayDismissedItem, MyDayFinalizedDay, MyDayNotificationType, ProjectStatus, TaskManagementActionType, Project-Entity.
**Bewusst nicht/nur oberflächlich untersucht (Lücken):**
- src/backend/Centron.BL/Sales/Receipts/Internal/ReceiptItemTimerBL.cs, Zeilen ab ~1111 (Rest der 2112 Zeilen, u. a. `CreateSpecialArticleItems`-Fortsetzung, `GetHelpdeskTimersText`, `GetSpecialArticlesText`) – Kernlogik der Positionsgruppierung wurde erfasst, Text-/Formatierungsdetails am Ende der Datei nicht.
- src/backend/Centron.BL/DataExchange/Connectors/DocBeeTicketTimerBL.cs, mittlerer Teil (ca. Zeilen 150-410) – Ticketerstellung/-suche im Detail nicht Zeile für Zeile gelesen, nur Validierungsanfang und Statusmapping/Timer-Aufbau am Ende.
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerTypeBL.cs – nur die ersten 40 Zeilen (reine CRUD-Wrapper, geringe fachliche Tiefe vermutet).
- src/backend/Centron.BL/Sales/Support/HelpdeskTimerAddressSpecialArticlesBL.cs, HelpdeskTimerBookedArticlesFilter.cs – nicht gelesen (Sonderartikel-Detaillogik, thematisch mit TIME-16 verwandt, aber nicht Kern der Zeiterfassung).
- src/backend/Centron.BL/Sales/Support/HelpdeskSettingsBL.cs, HelpdeskSearchBL.cs, HelpdeskOverviewFilterBL.cs, HelpdeskConnectionNumberBL.cs – nur punktuell per Grep referenziert (`GetClosedHelpdeskState`), nicht vollständig gelesen; vollständige Helpdesk-Statusmaschine (Ticket selbst, außerhalb der Zeiterfassung) ist daher nur in Teilen belegt.
- src/backend/Centron.BL/Sales/Support/TicketProcess/TicketProcessBL.cs, TicketProjectDependencyBL.cs, TicketListBL.cs – nur über Sub-Agent erfasst, nicht durch den Hauptagenten selbst mit Zeilenverifikation gegengelesen (Risiko geringfügiger Zeilenabweichungen bei künftiger Verifikation).
- src/backend/Centron.BL/MyDay/MyDayNotificationsWebServiceBL.cs, ReportConnections.cs, ReportRecord.cs, Supremo.cs – nicht gelesen (Webservice-Wrapper bzw. externe Report-Strukturen, geringe erwartete fachliche Tiefe für dieses Cluster).
- Centron.DAO-Mappings (NHibernate-XML/Fluent-Mappings) wurden nicht systematisch nach DB-Constraints (NOT NULL, Unique, Fremdschlüssel-Kaskaden) durchsucht – Datenbank-seitige Integritätsregeln (jenseits der BL-Guards) sind daher nicht separat belegt und könnten zusätzliche SwRS-Kandidaten liefern.
- WPF-UI-Schicht wurde nur für TimerBillingSettingsPageView(Model) (Kontext des Ausgangscommits) angesehen; weitere UI-Validierungen/Strings in anderen Zeiterfassungs-/Ticket-/Projekt-Dialogen wurden nicht systematisch gesichtet.
- Keine Recherche zu mobilen Apps/ServiceBoardWeb-Frontend-Code (nur Backend-BL und ein WPF-Dialog betrachtet).
**Bekannte Auffälligkeiten/Bugs (nicht als Anforderung, sondern als Hinweis für Konsolidierung markiert):**
- `TaskManagementTaskBL.ExecuteTask`: Pfad `ProjectStatus.Paused` ruft `Result.AsSuccess()` auf, ohne den Rückgabewert per `return` zu verwenden – der Code läuft danach möglicherweise weiter in die Ausführungslogik hinein (siehe TIME-31, Prüfidee).
- `TicketProjectSettingsBL.CreateProjectSettingsExpression`: Filtert sowohl `TicketProjectI3Ds` als auch `EmployeeI3Ds` über `f.I3D` statt über die vermutlich korrekten Felder `f.TicketProjectI3D`/`f.EmployeeI3D` (lt. Sub-Recherche, nicht durch Hauptagenten selbst verifiziert).
- `AppointmentRequestBL.HandleAppointmentRequestReply`: `SaveOrUpdateAppointmentRequest` wird im Annahme-Zweig zweimal aufgerufen, das erste Ergebnis wird verworfen (Code-Duplikat, funktional unschädlich da idempotent).
@@ -0,0 +1,14 @@
- **Mandant**: Eine in sich abgeschlossene Unternehmens-/Firmeneinheit innerhalb von CentronERP mit eigenen Stammdaten (u. a. Logos, Bankverbindungen); genau ein Mandant ist als Standard-Mandant markiert.
- **ApplicationSettings vs. Stammdat**: Zwei parallel existierende Datenbank-Ablagen für Systemeinstellungen - `Stammdat` ist die historische, nicht mehr für Neuanlagen vorgesehene Tabelle (Zugriff über `AppSettingsConst`), `ApplicationSettings` die aktuelle Tabelle (Zugriff über `ApplicationSettingID`).
- **Group Setting Class**: Eine serverseitige Business-Logic-Klasse, die mehrere fachlich zusammengehörige Einstellungen lädt, typisiert kapselt (DTO) und über eine dedizierte API bereitstellt, statt dem Client direkten Tabellenzugriff zu erlauben.
- **MailTemplateReference / Mailvorlagen-Identitätsschema**: Eindeutige Kennzeichnung einer Mailvorlage über die Kombination der Felder ObjectKind (Objektart), ObjectI3D (Bezug zu einer konkreten Datenbankzeile), SubObjectKind (Unterscheidung ohne Objektbezug) und TemplatePrio (Priorität).
- **Hotline-Masterkey**: Ein zentral hinterlegtes, separat verwaltetes kryptografisches Geheimnis, mit dem weitere sensible Zugangsdaten (z. B. MailScanner-Postfachpasswörter, OAuth-Client-Secrets) zusätzlich AES-verschlüsselt werden; ohne hinterlegten Masterkey ist Ver-/Entschlüsselung nicht möglich.
- **MailScanner / Virtual Mail Assistant (VMA)**: Komponente zum automatisierten Abholen und Verarbeiten eingehender E-Mails aus konfigurierten Postfächern (Profile mit Zugangsdaten, Workflow-Zuordnung); Zugriff auf die Profile ist über das Recht ACCESS_VMA_MODULE geschützt.
- **ESR/QR-Referenz**: Schweizer Zahlungsreferenzverfahren (Einzahlungsschein mit Referenznummer bzw. dessen Nachfolger QR-Rechnung), für das je Mandant eines von bis zu vier hinterlegten Bankkonten als aktives Referenzkonto gewählt werden kann.
- **RTF (Rich Text Format)**: Internes Speicherformat für formatierten Text in Mailvorlagen und Signaturen; Klartext wird bei Bedarf automatisch anhand globaler Schrifteinstellungen in RTF konvertiert.
- **CentronWebserviceMailType**: Zentrale Einstellung, die festlegt, welches E-Mail-Transportprotokoll (SMTP, Microsoft Exchange/EWS oder Microsoft Graph) für den serverseitigen Mailversand verwendet wird.
- **Domain-Blacklist**: Liste gesperrter Empfänger-Domains bzw. Domain-Muster, gegen die jede Ziel-E-Mail-Adresse vor dem Versand geprüft wird, um Mailversand an unerwünschte Domains zu verhindern.
- **LogKind**: Statuswert einer Systembenachrichtigung (Successful, PartlyError, Error), der u. a. für Filterung und automatisierte Fehleranalyse verwendet wird.
- **Modulkategorie**: Feste, lokalisierte Gruppierungsebene für Anwendungsmodule (z. B. "Vertrieb", "Abrechnung", "Administration"), der jedes Modul zur strukturierten Anzeige (u. a. im Favoritenmenü) zugeordnet ist.
- **NotificationUser**: Ein frei definierbarer Benachrichtigungsempfänger (nicht zwingend ein Systembenutzer) mit Name/Telefon/E-Mail, der beliebigen Geschäftsobjekten zugeordnet werden kann.
@@ -0,0 +1,7 @@
- **StRS-ADM-04** (Kontextabhängige E-Mail-Signaturen): Offen, ob die Signaturquelle "Outlook" (lokales Windows-Client-Profil/Registry) in einer Web-/SaaS-Architektur ohne lokalen Windows-Client überhaupt sinnvoll fortgeführt werden kann oder durch rein zentrale (Centron-)Signaturverwaltung ersetzt werden muss - im Code keine Migrationsentscheidung dokumentiert.
- **SwRS-ADM-17** (Domain-Blacklist für Mailversand): Offen, welche fachliche Absicht hinter der Zeichen-für-Zeichen-Regex-Konstruktion für Nicht-"@"-Einträge steht (Sub-Domain-Wildcard vs. Teilstringsperre) - im Code nicht kommentiert, Klärung mit Fachbereich empfohlen.
- **SwRS-ADM-18** (Objektspezifische Mail-Tracking-Schlüsselwörter): Offen, wie die konfigurierten Tracking-Keywords beim Mailempfang tatsächlich ausgewertet werden (Verknüpfungslogik zu MailScanner/Zuordnung eingehender Antworten wurde in diesem Rechercheumfang nicht gelesen).
- **SwRS-ADM-19** (Rechteprüfung beim Zugriff auf MailScanner-Profile): Offen, ob `SaveProfile`, `DeleteProfile` und `SaveTasks` an anderer Stelle (z. B. WebService-/API-Schicht) ebenfalls rechtegeprüft werden - im gelesenen BL-Code selbst nicht erkennbar, nicht abschließend verifiziert.
- **SyRS-ADM-06** (Externe Lizenzserver-Anbindung): Offen, ob/wie das aktuelle On-Premise-Lizenzmodell (Hardware-ID- und Einzeldatenbank-Bindung über externen c-entron-Office-Lizenzserver) auf eine Multi-Tenant-SaaS-Architektur übertragen werden soll - im Code keine Aussage zu einer geplanten SaaS-Lizenzierung.
@@ -0,0 +1,95 @@
ID: StRS-ADM-01
Titel: Zentrale, clientunabhängige Konfigurationsverwaltung
Ebene: StRS
Typ: nicht-funktional (Architekturprinzip)
Akteur: Systemadministrator, IT-Verantwortlicher
Vorbedingung: Client-Anwendung möchte Einstellungen lesen/schreiben.
Fakt: Laut Entwicklerdokumentation greift der Client "nie direkt" auf die Settings-Tabellen zu; stattdessen existieren pro fachlichem Bereich "Group Setting Classes", die Settings laden, typisiert kapseln und über dedizierte REST-API-Methoden (POST) bereitstellen (Beispiel `ReceiptWebServiceBL.GetReceiptInvoiceSettings`/`SaveReceiptInvoiceSettings`).
Aussage: Das System soll Systemkonfiguration ausschließlich über eine serverseitige Business-Logic-Schicht mit klar definierten, fachlich gruppierten DTOs bereitstellen und den direkten Tabellenzugriff durch Clients unterbinden.
Ergebnis: Zentrale, versionierbare Konfigurationsschnittstelle als Grundlage für eine künftige Web-/SaaS-API.
Belege:
- [SEKUNDÄR] docs/guides/development/settings-management.md:63-114 - Begründung: Beschreibt explizit "The client never accesses settings tables directly" sowie Group-Setting-Class-Pattern mit Beispielcode.
- [KONTEXT] src/backend/Centron.BL/Administration/Settings/AppSettingsGroupBL.cs:1864-1887 - Begründung: Konkretes Beispiel eines Group-Setting-Zugriffs (CentronNotifications).
Prüfidee: Architekturreview: Prüfen, ob WPF-Client tatsächlich nur über WebService-DTOs auf Settings zugreift (keine direkten SQL/DAO-Aufrufe aus UI-Schicht).
Tracelinks: SyRS-ADM-01; SwRS-ADM-01, SwRS-ADM-02, SwRS-ADM-03, SwRS-ADM-04
Konsolidierung: nein
Status: belegt
---
ID: StRS-ADM-02
Titel: Personalisierte Modulfavoriten je Mitarbeiter
Ebene: StRS
Typ: funktional
Akteur: Sachbearbeiter/Endbenutzer
Vorbedingung: Benutzer ist angemeldet und möchte häufig genutzte Module schnell erreichen.
Fakt: Benutzer können Module individuell als Favoriten markieren (`ModuleFavorite` verknüpft `Employee` und `Module`); die Anzeige erfolgt gruppiert nach Modulkategorie (`GetModuleFavoritesGroupedByCategory`). Beim Speichern der Favoriten wird bei technischem Fehler die Meldung "Die Favoriten konnten nicht gespeichert werden." zurückgegeben, beim Umschalten eines einzelnen Favoriten "Der Favorite konnte nicht geändert werden.".
Aussage: Das System soll es jedem Benutzer ermöglichen, Module individuell als Favoriten zu markieren und diese nach Kategorie gruppiert anzuzeigen; Fehler beim Speichern sollen dem Benutzer mit einer verständlichen Meldung angezeigt werden.
Ergebnis: Personalisierte, schnellere Navigation im Modulmenü je Mitarbeiter.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleBL.cs:44-81 (GetModuleFavorites, SaveModuleFavorites, UpdateModuleFavorite) - Begründung: Zeigt Favoriten-Datenmodell (pro Employee) und Fehlermeldungstexte.
- [SEKUNDÄR] src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:88-113 (GetModuleFavoritesGroupedByCategory) - Begründung: Zeigt Gruppierungslogik nach Kategorie für die Anzeige.
Prüfidee: UI-/API-Test: Favorit setzen, Session neu laden, prüfen ob Favorit weiterhin gruppiert nach Kategorie erscheint; Fehlerfall (DB nicht erreichbar) prüfen auf Fehlermeldungstext.
Tracelinks: SwRS-ADM-05, SwRS-ADM-06 (Modul-/Kategoriesynchronisation als technische Grundlage); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: StRS-ADM-03
Titel: Konfigurierbares E-Mail-Transportprotokoll
Ebene: StRS
Typ: Schnittstelle
Akteur: IT-Verantwortlicher
Vorbedingung: Das System soll E-Mails im Namen des Unternehmens versenden/empfangen.
Fakt: Der zu verwendende Mail-Client wird zentral über die Einstellung `CentronWebserviceMailType` gesteuert und kann zwischen SMTP (Default), Microsoft Exchange (EWS) und Microsoft Graph umgeschaltet werden (`CentronMailFactory.GetMail`). Zusätzlich existiert ein globaler Testmail-Modus (`TestMails.IsEnabled`), der bei aktiven Subscribern jede reale Mail-Versendung durch einen In-Memory-Mock ersetzt.
Aussage: Das System soll die Wahl des E-Mail-Transportprotokolls (SMTP/Exchange/Microsoft Graph) als zentrale, administrierbare Einstellung anbieten und einen von der Konfiguration unabhängigen Test-/Simulationsmodus für den Mailversand unterstützen.
Ergebnis: Flexible Integration in unterschiedliche Kunden-Mailinfrastrukturen; sichere Testbarkeit ohne reale Mailversendung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/CentronMailFactory.cs:26-53 (GetMail) - Begründung: Zeigt Protokollauswahl per Setting und TestMail-Vorrang.
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 - Begründung: Zeigt Subscriber-Pattern für Testmail-Abfang.
Prüfidee: Konfigurationstest: CentronWebserviceMailType nacheinander auf 0/Exchange/Graph setzen und prüfen, dass jeweils die korrekte Implementierungsklasse instanziiert wird.
Tracelinks: SyRS-ADM-03; SwRS-ADM-09, SwRS-ADM-10, SwRS-ADM-11, SwRS-ADM-12, SwRS-ADM-17, SwRS-ADM-18
Konsolidierung: nein
Status: belegt
---
ID: StRS-ADM-04
Titel: Kontextabhängige E-Mail-Signaturen
Ebene: StRS
Typ: funktional
Akteur: Systemadministrator/Sachbearbeiter
Vorbedingung: Ausgehende Mails (allgemein, Helpdesk intern, Helpdesk extern) sollen eine Signatur erhalten.
Fakt: `MailSignatureBL` unterscheidet drei unabhängig konfigurierbare Signaturkontexte (Standard `MailSignatureKind`, `HelpdeskInternalMailSignatureKind`, `HelpdeskExternalMailSignatureKind`) und je Kontext eine Signaturquelle (`MailSignatureKind`-Enum: None/Outlook/Centron). Bei Quelle "Outlook" wird die Signatur aus lokalen Outlook-RTF-Dateien plus Windows-Registry-Konfiguration (`HKCU\...\Outlook\Profiles\...`) gelesen; bei Quelle "Centron" aus einer in der Datenbank hinterlegten Signatur (`AppSettingData`, Encoding 1252).
Aussage: Das System soll pro Mail-Kontext (Standard, Helpdesk intern, Helpdesk extern) eine unabhängig konfigurierbare Signaturquelle unterstützen, wahlweise aus lokalem Outlook-Profil oder zentral in der Datenbank gepflegter Signatur.
Ergebnis: Fachlich getrennte, kontextabhängige Signaturgestaltung; Outlook-Quelle ist jedoch an lokale Windows-Umgebung/Registry gebunden (Client-seitige Abhängigkeit).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSignatureBL.cs:111-182 (GetHelpdeskExternalSignature, GetHelpdeskInternalSignature, GetDefaultSignature, GetSignature) - Begründung: Drei parallele, strukturell identische Methoden für die drei Kontexte.
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSignatureBL.cs:41-96 (GetDefaultOutlookSignature) - Begründung: Zeigt Registry-/Dateisystem-Abhängigkeit der Outlook-Signaturquelle inkl. `OperatingSystem.IsWindows()`-Prüfung mit Fehler "Outlook default signature can only be loaded on windows".
Prüfidee: Für Web-/SaaS-Migration klären: Outlook-Signaturquelle ist im Web-/SaaS-Kontext (kein lokales Windows-Client-Profil) nicht sinnvoll übertragbar - Anforderung an Nachfolgesystem prüfen (nur noch zentrale Signaturverwaltung?).
Tracelinks: StRS-ADM-03 (gemeinsamer Kommunikations-/Mail-Kontext); SyRS/SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; HYPOTHESE bzgl. Weiterverwendung der Outlook-Quelle im Web/SaaS-Kontext (technische Prämisse "lokaler Windows-Client mit Outlook" entfällt vermutlich in einer SaaS-Architektur - im Code nicht explizit als Migrationsentscheidung dokumentiert)
---
ID: StRS-ADM-05
Titel: Mandantenstammdaten mit Logos und Bankverbindungen
Ebene: StRS
Typ: Daten
Akteur: Systemadministrator
Vorbedingung: Unternehmensstammdaten (Mandant) sollen gepflegt und für Belegdruck/Kommunikation verwendet werden.
Fakt: `MandatorBL` erwartet genau einen als Standard markierten Mandanten (`Default == 1`, `GetDefaultMandator`/`GetDefaultMandatorExtended`); ein Mandant kann bis zu acht unterschiedliche Logo-/Bildvarianten hinterlegen (`PictureOne` … `PictureEight`, Zugriff über `GetMandatorLogoByIndex` mit Index 1-8, sonst Fehler "image index was out of range (index can be between 1 and 8)"). Für ESR/QR-Zahlungsreferenzen kann eines von vier hinterlegten Bankkonten je Mandant als aktiv markiert werden (`UseBankForEsr` 1-4, `GetEsrBankIndex`/`GetIBANFromEsrIndex`).
Aussage: Das System soll pro Mandant genau einen als Standard gekennzeichneten Datensatz mit bis zu acht wählbaren Firmenlogos sowie bis zu vier hinterlegten Bankverbindungen verwalten, von denen eine für ESR/QR-Referenzen aktiv gewählt werden kann.
Ergebnis: Mandantenfähige Stammdatenverwaltung als Grundlage für Corporate-Design (Logo) und Zahlungsverkehr je Mandant.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:19-27 (GetDefaultMandator, GetDefaultMandatorExtended) - Begründung: Zeigt Default-Flag-Semantik.
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:90-125 (GetMandatorLogoByIndex) - Begründung: Zeigt Acht-Bilder-Struktur inkl. Fehlermeldung bei ungültigem Index.
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/MandatorBL.cs:54-88 (GetEsrBankIndex, GetIBANFromEsrIndex) - Begründung: Zeigt Vier-Konten-Struktur mit wählbarem Referenzkonto.
Prüfidee: Datenmodelltest: Mehrere Mandanten mit Default=1 in Testdaten anlegen und prüfen, welches Verhalten GetDefaultMandator zeigt (GetEntity liefert vermutlich undefiniertes Verhalten bei Mehrfachtreffern - Eindeutigkeit als Datenintegritätsregel prüfen/erzwingen).
Tracelinks: SyRS/SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,349 @@
ID: SwRS-ADM-01
Titel: Zwei-Tabellen-Architektur für Systemeinstellungen
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator
Vorbedingung: Ein Setting soll gelesen oder geschrieben werden.
Fakt: Das System verwaltet Anwendungseinstellungen in zwei getrennten Tabellen/Enum-Familien: der Legacy-Tabelle `Stammdat` (Zugriff über `AppSettingsConst`) und der aktuellen Tabelle `ApplicationSettings` (Zugriff über `ApplicationSettingID`). `AppSettingsBL.GetSettings`/`GetSettingsForUpdate` akzeptieren ausschließlich Werte dieser beiden Enum-Typen und werfen sonst eine Exception ("Invalid settings type").
Aussage: Das System soll Konfigurationswerte konsistent über genau zwei unterscheidbare Einstellungs-Namensräume (Legacy und aktuell) referenzieren und beim Zugriff typsicher zwischen beiden unterscheiden.
Ergebnis: Zugriff auf eine unbekannte/fremde Einstellungs-ID führt zu einer Exception statt eines stillen Fehlers.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:47-65 (GetSettings) - Begründung: Zeigt Typprüfung und Exception "Invalid settings type".
- [SEKUNDÄR] docs/guides/development/settings-management.md:7-31 - Begründung: Beschreibt explizit die Dual-Table-Architektur und dass neue Einstellungen nur in ApplicationSettings angelegt werden sollen.
Prüfidee: Unit-Test: GetSettings mit gemischter Liste aus AppSettingsConst und ApplicationSettingID prüfen; GetSettings mit anderem Objekttyp muss Exception werfen.
Tracelinks: StRS-ADM-01; SyRS-ADM-01
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-02
Titel: Fortlaufende ID-Vergabe für neue Systemeinstellungen
Ebene: SwRS
Typ: funktional
Akteur: Entwickler/Systemadministrator (Customizing)
Vorbedingung: Eine neue Systemeinstellung soll eingeführt werden.
Fakt: Neue Einstellungen erhalten eine fortlaufende numerische ID aus einem im Quellcode gepflegten Kommentar ("Next Centron Settings ID"), aktuell Wert 10471 in `ApplicationSettingID.cs` Zeile 14. IDs ab 50000 ("Riverbird") sind für ein anderes Produkt reserviert und werden von c-entron.NET nicht verwendet.
Aussage: Das System soll für jede Systemeinstellung eine eindeutige, fortlaufend vergebene numerische Kennung besitzen, die produktübergreifende ID-Bereiche (c-entron vs. Riverbird) getrennt hält.
Ergebnis: Eindeutige Zuordnung Setting-ID zu Bedeutung; Namensraum-Trennung zwischen Produktlinien.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs:14 - Begründung: Aktueller Zähler "Next Centron Settings ID : 10471".
- [SEKUNDÄR] docs/guides/development/settings-management.md:33-47 - Begründung: Beschreibt Ablaufprozess für ID-Vergabe und Riverbird-Reservierung.
Prüfidee: Prüfen ob je vergebener ID genau eine Beschreibung in ApplicationSettingDefinitions existiert (Konsistenzcheck als Build-Test denkbar).
Tracelinks: StRS-ADM-01; SyRS-ADM-01
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-03
Titel: Automatische Anlage fehlender Einstellungsdatensätze
Ebene: SwRS
Typ: funktional
Akteur: System (technisch)
Vorbedingung: Eine ApplicationSetting-ID wird erstmals angefragt, aber es existiert noch kein Datensatz.
Fakt: `AppSettingsBL.LoadNewSettingsOptimized` legt für angefragte `ApplicationSettingID`-Werte, die weder im Session-Cache noch in der DB vorhanden sind, automatisch einen neuen `ApplicationSetting`-Datensatz mit leerer Beschreibung aus `ApplicationSettingDefinitions.Instance.GetApplicationSettingDescription(...)` an und speichert ihn in der Session.
Aussage: Das System soll beim ersten Zugriff auf eine noch nicht existierende Einstellung automatisch einen Standard-Datensatz mit Beschreibungstext anlegen, ohne dass ein expliziter Administrations-Schritt nötig ist.
Ergebnis: Keine Null-Referenzfehler bei neu eingeführten Settings; Selbstheilung des Datenbestands.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:106-152 (LoadNewSettingsOptimized, GetDefaultEmptyInstance) - Begründung: Zeigt Anlage-auf-Anfrage-Logik inkl. Session-Cache-Optimierung.
Prüfidee: Test: GetSettings mit einer neuen, noch nie gespeicherten ApplicationSettingID aufrufen und prüfen, dass ein Datensatz mit Default-Werten entsteht.
Tracelinks: StRS-ADM-01; SyRS-ADM-01
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-04
Titel: Typisierte Einstellungs-Getter mit Default-Fallback
Ebene: SwRS
Typ: funktional
Akteur: Entwickler (API-Konsument)
Vorbedingung: Ein Setting-Wert soll gelesen werden, evtl. ohne dass ein Datensatz existiert.
Fakt: `SettingsCollection` bietet typisierte Getter (`GetBool`, `GetString`, `GetInt`, `GetLargeString`, `GetDecimal`, `GetDouble`, `GetDateTime`, `GetEnum<T>`) mit optionalem Default-Wert; bei Enum-Werten wird geprüft, ob der gespeicherte Int-Wert überhaupt im Enum definiert ist (`Enum.IsDefined`), sonst wird der übergebene Default zurückgegeben statt eines ungültigen Enum-Werts.
Aussage: Das System soll beim Lesen von Einstellungen stets einen typsicheren Wert mit definiertem Fallback liefern und ungültige/undefinierte Enum-Rohwerte automatisch auf den Standardwert abbilden.
Ergebnis: Robuste Konfigurationsauswertung auch bei inkonsistenten/veralteten Datenbankwerten (z. B. nach Enum-Änderungen).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/SettingsCollection.cs:106-123 (GetEnum<T>, GetEnumOrDefault) - Begründung: Zeigt Validierung per Enum.IsDefined mit Fallback auf Default.
Prüfidee: Test: In DB einen Enum-Setting-Wert außerhalb des gültigen Bereichs speichern (z.B. -1) und prüfen, dass GetEnum<T> den übergebenen Default zurückgibt statt zu werfen.
Tracelinks: StRS-ADM-01; SyRS-ADM-01
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-05
Titel: Automatischer Abgleich interner Module mit der Datenbank
Ebene: SwRS
Typ: funktional
Akteur: System (Startup/Migration)
Vorbedingung: Anwendung startet oder Modulliste wird synchronisiert.
Fakt: `ModuleBL.DoCreateMissingInternalModulesInDB` gleicht eine im Code definierte Liste von `ModuleClass` (ModuleGuid, ModuleName, Category) gegen als „intern" markierte `Module`-Datensätze in der DB ab (Vergleich der GUID case-insensitive) und legt für jedes im Code aber nicht in der DB vorhandene Modul automatisch einen neuen `Module`-Datensatz mit zugehöriger Kategorie an.
Aussage: Das System soll interne Anwendungsmodule anhand einer im Code gepflegten Modulliste automatisch mit der Datenbank synchronisieren, sodass neue Module ohne manuellen Administrationsschritt sichtbar werden.
Ergebnis: Modulverwaltung bleibt auch nach Software-Updates konsistent ohne manuelle DB-Pflege.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleBL.cs:22-42 (DoCreateMissingInternalModulesInDB) - Begründung: Zeigt GUID-basierten Abgleich und automatisches Anlegen fehlender Module.
Prüfidee: Test: Neues ModuleClass-Objekt mit unbekannter GUID übergeben, prüfen dass genau ein neuer Module-Datensatz inkl. Kategorie entsteht.
Tracelinks: StRS-ADM-02; SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-06
Titel: Feste Modulkategorien mit lokalisiertem Anzeigetext
Ebene: SwRS
Typ: funktional
Akteur: System (Startup/Migration)
Vorbedingung: Interne Modulkategorien müssen in der DB existieren.
Fakt: `ModuleCategoryBL.CreateInternalCategories` definiert eine feste Liste interner `CentronModuleCategory`-Werte (u. a. Purchasing, Sales, Billing, Administration, BaseData, DataExchange, Controlling, Logistic, MyCentron, PasswordManager, NexowareConnect) und legt fehlende Kategorien mit deutschem Anzeigetext an (z. B. "Einkauf", "Vertrieb", "Abrechnung"). `DoGetDisplayTextForCategory` wirft eine `ArgumentOutOfRangeException`, falls für eine Kategorie kein Anzeigetext hinterlegt ist.
Aussage: Das System soll eine feste Menge interner Modulkategorien mit lokalisiertem Anzeigetext verwalten und beim Fehlen eines Anzeigetexts einen harten Fehler erzeugen statt eine leere/inkonsistente Kategorie anzulegen.
Ergebnis: Konsistente, vollständig übersetzte Kategorie-Struktur; Entwicklerfehler (vergessene Übersetzung) werden früh sichtbar.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:26-83 (CreateInternalCategories, DoGetDisplayTextForCategory) - Begründung: Enthält vollständige Kategorienliste, deutsche Anzeigetexte und Exception bei fehlender Zuordnung.
Prüfidee: Testfall: Neue CentronModuleCategory ohne case in DoGetDisplayTextForCategory hinzufügen, prüfen dass ArgumentOutOfRangeException geworfen wird ("Unknown category: ...").
Tracelinks: StRS-ADM-02; SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-07
Titel: Filterkriterien für Systembenachrichtigungen
Ebene: SwRS
Typ: funktional
Akteur: Systemadministrator
Vorbedingung: Systembenachrichtigungen sollen gefiltert/durchsucht werden (z. B. Fehleranalyse).
Fakt: `CentronNotificationsBL.CreateFilterExpression` erlaubt Filterung nach: nur Fehler (`LogKind.Error`/`LogKind.PartlyError`), Datum-von/-bis, konkretem `LogKind`, `ObjectKind`, `ShortSign` (Kurzzeichen) und `ObjectI3D`. `LogKind` kennt die Werte Successful, PartlyError, Error.
Aussage: Das System soll Systembenachrichtigungen nach Status (erfolgreich/teilweise fehlerhaft/fehlerhaft), Zeitraum, Objektbezug und Bearbeiterkürzel filterbar machen.
Ergebnis: Gezielte Fehleranalyse und Auditing für Administratoren möglich.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs:79-121 (CreateFilterExpression) - Begründung: Vollständige Filterkriterien.
- [PRIMÄR] src/webservice/Centron.WebServices.Core/Entities/Notifications/LogKind.cs:1-9 - Begründung: Enum-Definition der drei Status.
Prüfidee: API-Test: Filter mit OnlyErrors=true setzen, prüfen dass nur Error/PartlyError-Einträge zurückkommen.
Tracelinks: SyRS-ADM-02; StRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-08
Titel: Objektbezogene Benachrichtigungsempfänger mit Deduplizierung
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator/Fachbereich
Vorbedingung: Ein Geschäftsobjekt (z. B. Workflow/Prozess) soll bei Ereignissen bestimmte Empfänger benachrichtigen.
Fakt: `NotificationUser` (Titel, Vor-/Nachname, Telefon, E-Mail) wird über eine m:n-Bindungstabelle `NotificationUsersToObject` (ObjectKind + ObjectI3D) einem beliebigen Geschäftsobjekt zugeordnet. Beim Speichern (`UpdateUsersFromObject`) wird ein Benutzer anhand der Kombination aus Vorname/Nachname/Titel/Telefon/E-Mail dedupliziert wiederverwendet; nicht mehr referenzierte Bindungen werden entfernt.
Aussage: Das System soll es erlauben, beliebige Kontaktpersonen (nicht zwingend Systembenutzer) objektbezogen als Benachrichtigungsempfänger zu hinterlegen, wobei identische Kontakte dedupliziert wiederverwendet werden.
Ergebnis: Wiederverwendbare Kontaktverwaltung für Benachrichtigungsempfänger je Objektinstanz.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Notifications/UserNotificationBL.cs:41-117 (UpdateUsersFromObject) - Begründung: Zeigt Bindungslogik, Deduplizierung und Bereinigung nicht mehr benötigter Bindungen.
Prüfidee: Test: Zwei Objekte mit identischem NotificationUser (gleiche Felder) verknüpfen, prüfen dass nur ein NotificationUser-Datensatz in der DB existiert.
Tracelinks: SyRS-ADM-02; StRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-09
Titel: Erzwungene SSL-Verschlüsselung für Office365-SMTP
Ebene: SwRS
Typ: funktional; Workaround
Akteur: System (technisch)
Vorbedingung: SMTP-Client wird für den Versand aufgebaut.
Fakt: `SMTPMail.CreateSmtpClient` aktiviert SSL zwingend (`client.EnableSsl = true`), wenn der konfigurierte Host exakt `"smtp.office365.com"` ist – unabhängig vom konfigurierten Wert der Einstellung `SmtpSslActive`. Für alle anderen Hosts gilt ausschließlich der konfigurierte Wert.
Aussage: Das System soll für den Sonderfall Office365-SMTP verschlüsselte Übertragung erzwingen, auch wenn die SSL-Einstellung deaktiviert konfiguriert wurde.
Ergebnis: Verhindert versehentlich unverschlüsselten Versand über Office365, führt aber zu inkonsistentem Verhalten der SSL-Einstellung zwischen Hosts (hartkodierter Sonderfall statt allgemeiner Regel).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:160 (`client.EnableSsl = client.Host == "smtp.office365.com" || settings.SmtpSslActive;`) - Begründung: Hartkodierte Sonderregel für einen konkreten Hostnamen.
Prüfidee: Konfigurationstest: Host=smtp.office365.com, SmtpSslActive=false setzen, prüfen dass EnableSsl dennoch true ist. Für Web-Neuimplementierung klären, ob dieser Sonderfall fachlich gewollt bleibt oder durch allgemeine Pflichtverschlüsselung ersetzt wird.
Tracelinks: StRS-ADM-03; SyRS-ADM-03
Konsolidierung: nein
Status: belegt; Workaround (hartkodierter Hostname als Sonderfall im Code)
---
ID: SwRS-ADM-10
Titel: Inkonsistente Verschlüsselung von Mailversand-Zugangsdaten
Ebene: SwRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Zugangsdaten für Mailversand werden gespeichert.
Fakt: `MailSettingsBL` verschlüsselt `ExchangePassword` und `GraphAppSecret` mit `AESCryptoLogic` vor dem Speichern (`EncryptText`) bzw. entschlüsselt sie beim Laden (`DecryptText`). Für `SmtpPassword` (Einstellung `MailSmtpPassword`) erfolgt dagegen keinerlei Ver-/Entschlüsselung – der Wert wird als Klartext in `AppSettingsBL.GetSettingsForUpdate`/`UpdateString` gespeichert und gelesen.
Aussage: Das System soll alle im Klartext übertragbaren Zugangsgeheimnisse für den Mailversand (inkl. SMTP-Passwort) einheitlich verschlüsselt in der Konfigurationsdatenbank ablegen.
Ergebnis: Aktuell inkonsistenter Schutz von Zugangsdaten: Exchange/Graph-Geheimnisse sind verschlüsselt, SMTP-Passwort liegt im Klartext in der Datenbank vor.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSettingsBL.cs:110 (SmtpPassword = setting.GetString(AppSettingsConst.MailSmtpPassword)) vs. Zeile 117 (ExchangePassword = this._cryptoLogic.DecryptText(...)) und Zeile 133 (GraphAppSecret = this._cryptoLogic.DecryptText(...)) - Begründung: Direkter Codevergleich zeigt fehlende Verschlüsselung nur beim SMTP-Passwort.
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSettingsBL.cs:205 (UpdateString(AppSettingsConst.MailSmtpPassword, settings.SmtpPassword)) vs. Zeile 212/227 (EncryptText für Exchange/Graph) - Begründung: Bestätigt fehlende Verschlüsselung beim Speichern.
Prüfidee: Sicherheitsreview: DB-Inhalt der Stammdat-Zeile für MailSmtpPassword direkt inspizieren und mit ApplicationSetting für GraphAppSecret vergleichen (Klartext vs. Chiffrat).
Tracelinks: StRS-ADM-03; SyRS-ADM-04 (verwandtes Muster inkonsistenter Zugangsdaten-Verschlüsselung)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-11
Titel: Tolerante Behandlung ungültiger Empfängeradressen
Ebene: SwRS
Typ: funktional
Akteur: System (technisch)
Vorbedingung: E-Mail mit mehreren Empfängern (To/CC/BCC) wird versendet.
Fakt: `SMTPMail.CreateMailMessage` validiert jede Empfängeradresse einzeln über `DeveloperSecurity.Email.ValidateAddress`. Bei ungültiger Adresse wird diese von der jeweiligen Empfängerliste ausgeschlossen und der Ergebnisstatus auf `ResultStatus.Warning` gesetzt (mit Sammel-Meldungstext je ausgeschlossener Adresse), der Versand an die übrigen gültigen Adressen wird jedoch nicht abgebrochen.
Aussage: Das System soll beim Mailversand ungültige Einzeladressen tolerant behandeln: sie werden von der Zustellung ausgeschlossen und dem Absender als Warnung gemeldet, ohne den gesamten Versand an die übrigen validen Empfänger zu verhindern.
Ergebnis: Höhere Zustellzuverlässigkeit bei Massen-/Sammelmails trotz einzelner fehlerhafter Adressen; Nachvollziehbarkeit über Warnmeldung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:218-266 (CreateMailMessage, To/CC/BCC-Schleifen) - Begründung: Zeigt Try/Catch pro Adresse mit Warning-Sammlung statt Gesamtabbruch.
Prüfidee: Test: Mail mit einer gültigen und einer syntaktisch ungültigen To-Adresse versenden; erwartet ResultStatus.Warning und Zustellung an die gültige Adresse.
Tracelinks: StRS-ADM-03; SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-12
Titel: Fehlermeldung bei fehlendem SMTP-Host
Ebene: SwRS
Typ: funktional
Akteur: Systemadministrator
Vorbedingung: SMTP-Host ist in den Mailversand-Einstellungen nicht gepflegt.
Fakt: Wird beim Aufbau des `SmtpClient` ein leerer Host übergeben, fängt `SMTPMail.CreateSmtpClient` die resultierende `ArgumentException` ab und wirft stattdessen eine `ResultException` mit der benutzerorientierten deutschen Fehlermeldung "Der Host in den SMTP-Einstellungen ist nicht gesetzt.".
Aussage: Das System soll bei fehlender SMTP-Host-Konfiguration eine eindeutige, administratorverständliche Fehlermeldung liefern statt eines technischen Low-Level-Fehlers.
Ergebnis: Schnellere Fehlerdiagnose durch Administratoren bei unvollständiger Mailkonfiguration.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:151-159 - Begründung: Konkreter Meldungstext im Catch-Block.
Prüfidee: Test: MailSettingsDTO mit leerem SmtpHost übergeben, prüfen dass ResultException mit exaktem Meldungstext geworfen wird.
Tracelinks: StRS-ADM-03; SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-13
Titel: Mehrstufige Prioritätskette zur Mailvorlagen-Auflösung
Ebene: SwRS
Typ: funktional
Akteur: Sachbearbeiter/Systemadministrator
Vorbedingung: Für ein Geschäftsobjekt (z. B. Angebot, Helpdesk-Ticket) soll eine passende Mailvorlage ermittelt werden.
Fakt: `MailTemplateBL.MailTemplate` (private Methode) löst die zu verwendende Mailvorlage über eine fest dokumentierte Prioritätskette auf: 1. Konto/Kunde (Account), 2. persönlich (Mitarbeiter), 3. Niederlassung (Branch), 4. global, 5. hartkodierter Fallback (leere Vorlage mit Referenzwerten). Eine Vorlage wird nur akzeptiert, wenn sowohl Betreff als auch Klartext-Body nicht leer sind (`CheckMailTemplate`); fehlt Betreff oder Body, wird der jeweilige Default-Text aus der `MailTemplateReference` (`DefaultSubject`/`DefaultBody`) eingesetzt.
Aussage: Das System soll bei der Ermittlung einer E-Mail-Vorlage eine mehrstufige Fallback-Kette (kundenspezifisch → personenspezifisch → niederlassungsspezifisch → global → Systemstandard) anwenden und dabei unvollständige Vorlagen (fehlender Betreff/Text) automatisch durch definierte Standardtexte ergänzen.
Ergebnis: Vorhersagbare, konfigurierbare Mailtexte je Kontext ohne Gefahr leerer Betreffs/Inhalte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:248-317 (MailTemplate-Methode inkl. XML-Doc-Kommentar "MailTemplate priority fallback order") - Begründung: Enthält sowohl expliziten Kommentar zur Reihenfolge als auch die Implementierung inkl. CheckMailTemplate/HandleIfSubjectOrBodyNotDefined.
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:319-361 (GetMailTemplate mit Logging pulledLocation) - Begründung: Zeigt, dass die tatsächlich verwendete Ebene ("customer"/"personal"/"branch"/"global"/"hardcoded default fallback") geloggt wird - starkes Indiz für bewusst gestaltete Fallback-Logik.
Prüfidee: Testmatrix: Für dieselbe MailTemplateReference gezielt nur Branch- und Global-Vorlage anlegen (keine Account-/Personal-Vorlage), erwartete Ergebnis-Ebene "branch" prüfen.
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-14
Titel: Identitätsschema für Mailvorlagen
Ebene: SwRS
Typ: Daten
Akteur: Systemadministrator/Entwickler
Vorbedingung: Eine Mailvorlage soll eindeutig einem fachlichen Anwendungsfall zugeordnet werden.
Fakt: Jede Mailvorlage wird laut Entwicklerdokumentation eindeutig über die Kombination der Felder `ObjectKind`, `ObjectI3D`, `SubObjectKind` und `TemplatePrio` identifiziert (Klasse `MailTemplateReference`); z. B. haben Angebots-Mails `ObjectKind=Offer` mit allen übrigen Feldern NULL, während `ObjectKind=Escalation` mehrere Vorlagen über unterschiedliche `SubObjectKind`-Werte unterscheidet, da kein Bezug zu einer anderen Datenbankzeile (`ObjectI3D`) existiert.
Aussage: Das System soll Mailvorlagen über ein generisches, viergliedriges Identitätsschema (Objektart, Objekt-ID, Unterobjektart, Priorität) eindeutig referenzieren, das sowohl global gültige als auch objekt- oder fallspezifische Vorlagen abbildet.
Ergebnis: Ein einheitliches, erweiterbares Datenmodell für beliebig viele fachliche Mailvorlagen-Typen ohne Schemaänderung je neuem Anwendungsfall.
Belege:
- [SEKUNDÄR] docs/guides/development/create-mail-templates.md:6-33 - Begründung: Erläutert explizit das Identitätsschema mit Beispielen (Offer, Escalation, HelpdeskType).
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:133-156 (CreateExpression) - Begründung: Konkrete Filterlogik nach ObjectKind/SubObjectKind/ObjectI3D/BranchI3D/AccountI3D/IsPersonalMailTemplate/IsActive bestätigt das Schema.
Prüfidee: Datenmodell-Review: Prüfen ob für jede fachliche Verwendung (Offer, Order, Helpdesk, Escalation, ...) eine eindeutige MailTemplateReference in `MailTemplateReferences` registriert ist ohne Kollisionen.
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-15
Titel: Gruppiertes Variablensystem mit Alternativnamen
Ebene: SwRS
Typ: funktional
Akteur: Sachbearbeiter
Vorbedingung: Mailvorlage/Signatur enthält Platzhalter, die vor Versand ersetzt werden sollen.
Fakt: `MailTemplateBL.GenerateVariables` definiert für Outlook-Mailvorlagen benannte Variablen (`TextVariableWithReplacementStrategy`), gruppiert nach fachlichen Kategorien ("Allgemein", "Bearbeiter", "Kunde", "Adresse", "Ansprechpartner"), jeweils mit einer Lambda-Ersetzungsfunktion. Mehrere Variablen besitzen zusätzlich `AlternativeNames` (z. B. "KundenNummer" alternativ "KdNummer"), um Abwärtskompatibilität zu älteren Vorlagen-Platzhaltern sicherzustellen. Die Liste wird abschließend mit `EnsureValidVariableKeys()` validiert.
Aussage: Das System soll ein gruppiertes, benanntes Variablensystem für Mailvorlagen-Platzhalter bereitstellen, das für einzelne Variablen mehrere gültige (auch historische) Bezeichner unterstützt und die Variablendefinitionen beim Laden konsistenzprüft.
Ergebnis: Fachlich verständliche, kategorisierte Platzhalterliste im Vorlagen-Editor; Bestandsvorlagen mit alten Variablennamen bleiben funktionsfähig.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:531-1037 (GenerateVariables) - Begründung: Vollständige Liste der Variablengruppen inkl. AlternativeNames-Mechanismus.
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:1037 (`.EnsureValidVariableKeys()`) - Begründung: Zeigt explizite Validierungsroutine für Variablenschlüssel.
Prüfidee: Test: Vorlage mit historischem Platzhalter "KdNummer" gegen aktuelle Variable "KundenNummer" prüfen, ob beide Schreibweisen korrekt ersetzt werden.
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ADM-16
Titel: RTF-Konvertierung und Leer-Body-Sonderfall bei Mailvorlagen
Ebene: SwRS
Typ: funktional
Akteur: System (technisch)
Vorbedingung: Eine Mailvorlage mit Klartext-Body oder leerem/platzhalterartigem Inhalt wird geladen.
Fakt: `MailTemplateBL.GetRichText` konvertiert Klartext automatisch in RTF anhand der globalen Mailschrift-Einstellungen (`MailSettingsDTO.FontFamily/FontSize/MailFontArt`), sofern der Text noch nicht im RTF-Format vorliegt (`text.IsRtf()`). Zusätzlich existiert ein dokumentierter Sonderfall: Enthält der (in Klartext umgewandelte) Body ausschließlich das Zeichen "-", wird der Body als leer behandelt ("special case when the customer wants to have an empty body").
Aussage: Das System soll Mailvorlagen-Inhalte unabhängig vom Ursprungsformat einheitlich als RTF mit den global konfigurierten Schrifteinstellungen bereitstellen und einen projektspezifischen Sonderfall für "bewusst leerer Body" (Platzhalterzeichen "-") unterstützen.
Ergebnis: Einheitliche Darstellung unabhängig vom Speicherformat; Kundenwunsch nach explizit leerem Mailbody wird technisch abgebildet (kein generisches, dokumentiertes Feature, sondern Einzelfall-Workaround).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:1049-1061 (GetRichText) - Begründung: Zeigt bedingte RTF-Konvertierung anhand globaler Mailschrift-Settings.
- [PRIMÄR] src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:331-333 (bodyContainsDash) - Begründung: Codekommentar bestätigt Kundenspezifischen Sonderfall.
Prüfidee: Test: Vorlage mit Body-Inhalt "-" laden, prüfen dass der zurückgegebene Body leer ist statt des RTF-formatierten Bindestrichs.
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; Workaround (Bindestrich-Sonderfall wirkt als kundenspezifischer Einzelfall, nicht als generische Regel)
---
ID: SwRS-ADM-17
Titel: Domain-Blacklist für Mailversand
Ebene: SwRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Eine E-Mail soll an eine bestimmte Domain versendet werden.
Fakt: `DomainBlacklistBL.IsBlacklisted` prüft die Ziel-Domain der E-Mail-Adresse gegen eine Liste von `DomainBlacklistItem`. Einträge, die mit "@" beginnen, werden als exakte Domain-Sperre behandelt (Exact-Match auf "@"+Domain); alle übrigen Einträge werden über eine dynamisch aus dem Domainstring generierte Regex geprüft (`Regex.Replace(f.Domain, "(.)", "[$1]")` erzeugt ein Zeichen-für-Zeichen-Zeichenklassen-Pattern, kombiniert mit Anker `[@.]`), wodurch Teilstring-/Wildcard-artige Sperren auf Sub-Domain-Ebene möglich sind. Bei nicht auswertbarer E-Mail-Adresse (keine Domain extrahierbar) wird ein Fehler "Malformed E-Mail address" zurückgegeben.
Aussage: Das System soll den Versand von E-Mails an domainbasierte Sperrlisten verhindern können, mit Unterstützung für exakte Domainsperren und musterbasierte (Teil-/Sub-Domain-)Sperren.
Ergebnis: Verhinderung von Mailversand an unerwünschte/gesperrte Empfängerdomains (z. B. Wettbewerber, bekannte Spam-Fallen).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Blacklist/DomainBlacklistBL.cs:15-36 (IsBlacklisted) - Begründung: Vollständige Implementierung inkl. beider Prüfmodi und Fehlerfall.
Prüfidee: Test: Blacklist-Eintrag "@spam.de" (exakt) und "test" (Muster) anlegen; prüfen dass "user@spam.de" gesperrt ist und "user@mytest.de" ebenfalls über Musterprüfung erkannt wird; ungültige Adresse ohne "@" liefert Fehler.
Tracelinks: StRS-ADM-03 (gemeinsamer Kommunikations-/Sicherheitskontext); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; Detailverhalten der Musterprüfung als HYPOTHESE markiert (fehlende Dokumentation der Regex-Absicht im Code)
---
ID: SwRS-ADM-18
Titel: Objektspezifische Mail-Tracking-Schlüsselwörter
Ebene: SwRS
Typ: funktional
Akteur: Systemadministrator
Vorbedingung: Ausgehende Mails zu verschiedenen Geschäftsvorgängen sollen im Antworttext erkennbar sein (Tracking).
Fakt: `MailSettingsBL.GetMailTrackingSettings`/`UpdateMailTrackingSettings` verwalten pro Geschäftsobjekt-Typ ein eigenes Tracking-Schlüsselwort: Angebot (`MailTrackingOffer`), Auftrag (`MailTrackingOrder`), Lieferschein (`MailTrackingDeliveryList`), Rechnung (`MailTrackingInvoice`), Helpdesk (`MailTrackingHelpdesk`).
Aussage: Das System soll für die zentralen vertriebs-/serviceseitigen Mailvorgänge (Angebot, Auftrag, Lieferschein, Rechnung, Helpdesk) jeweils ein eigenständig konfigurierbares Tracking-Schlüsselwort unterstützen.
Ergebnis: Zuordenbarkeit eingehender Antwortmails zu ursprünglichen Geschäftsvorgängen anhand konfigurierbarer Schlüsselwörter.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/MailSettingsBL.cs:233-270 (GetMailTrackingSettings, UpdateMailTrackingSettings) - Begründung: Vollständige DTO-Feldliste der fünf Tracking-Bereiche.
Prüfidee: Funktionstest: Tracking-Keyword für "Angebot" setzen, prüfen dass es korrekt persistiert und beim Laden zurückgegeben wird; Zusammenspiel mit MailScanner (Zuordnungslogik) als Anschlussfrage prüfen.
Tracelinks: StRS-ADM-03 (gemeinsamer Kommunikationskontext); SyRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; HYPOTHESE bzgl. exakter Verwendung der Tracking-Keywords beim Mailempfang (Code der Auswertung nicht in diesem Rechercheumfang gelesen)
---
ID: SwRS-ADM-19
Titel: Rechteprüfung beim Zugriff auf MailScanner-Profile
Ebene: SwRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Ein Benutzer möchte MailScanner-Profile (Postfach-Abholkonfigurationen) einsehen.
Fakt: `MailScannerBL.GetProfiles` prüft vor dem Laden der Profile explizit das Recht `UserRightsConst.VirtualMailAssistant.ACCESS_VMA_MODULE` über `AppRightsBL.CheckRightsFromUser`; fehlt das Recht, wird ein Fehler "Fehlendes Recht VMA Profile zu laden" mit Code `DefaultMessageCodes.RightCheckFailed` zurückgegeben, ohne dass Profildaten (inkl. verschlüsselter Zugangsdaten) geladen werden. Andere Methoden derselben Klasse (`SaveProfile`, `DeleteProfile`, `SaveTasks`) enthalten keine sichtbare Rechteprüfung.
Aussage: Das System soll den lesenden Zugriff auf MailScanner-Profile an ein dediziertes Benutzerrecht ("Virtual Mail Assistant"-Modulzugriff) knüpfen.
Ergebnis: Eingeschränkte Sichtbarkeit sensibler Postfach-Konfigurationen auf berechtigte Benutzer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MailScanner/MailScannerBL.cs:57-72 (GetProfiles) - Begründung: Enthält konkrete Rechteprüfung und Fehlermeldungstext.
Prüfidee: Berechtigungstest: Benutzer ohne ACCESS_VMA_MODULE-Recht ruft GetProfiles auf, erwartet Fehlermeldung statt Daten. Ergänzend: Rechteprüfung für Save/Delete/SaveTasks im Code verifizieren (evtl. Lücke).
Tracelinks: SyRS-ADM-04; StRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; HYPOTHESE bzgl. Vollständigkeit der Rechteprüfung (Save/Delete/SaveTasks zeigten im gelesenen Code keine erkennbare Rechteprüfung - ggf. an anderer Stelle z. B. WebService-Layer abgesichert, nicht abschließend verifiziert)
@@ -0,0 +1,113 @@
ID: SyRS-ADM-01
Titel: POST-basierte Konfigurations-Schnittstelle
Ebene: SyRS
Typ: Schnittstelle
Akteur: Client-Anwendung (WPF, Web, Add-Ins)
Vorbedingung: Einstellungen sollen über die Web-Service-Schnittstelle abgerufen/gespeichert werden.
Fakt: Laut Konvention müssen alle Setting-bezogenen API-Methoden HTTP POST verwenden (`[WebInvoke(Method = "POST", ...)]`); Get-Methoden liefern ein Settings-DTO, Save-Methoden nehmen ein DTO entgegen.
Aussage: Das System soll für sämtliche Konfigurationsabfragen und -änderungen ausschließlich POST-basierte Endpunkte mit strukturierten DTOs anbieten (keine GET-Query-Parameter für Konfigurationsdaten).
Ergebnis: Einheitliches, erweiterbares API-Muster für Konfigurationsdaten.
Belege:
- [SEKUNDÄR] docs/guides/development/settings-management.md:116-135 - Begründung: Explizite API-Pattern-Vorgabe inkl. Codebeispiel.
Prüfidee: Stichprobenprüfung der ICentronRestService.Administration.cs Interface-Definitionen auf WebInvoke-Method-Attribute.
Tracelinks: StRS-ADM-01; SwRS-ADM-01, SwRS-ADM-02, SwRS-ADM-03, SwRS-ADM-04
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ADM-02
Titel: Automatisierte Bereinigung von Systembenachrichtigungen
Ebene: SyRS
Typ: nicht-funktional (Betrieb/Datenhaltung)
Akteur: Systemadministrator
Vorbedingung: Systembenachrichtigungen (CentronNotification, z. B. Batch-/Schnittstellenprotokolle) sammeln sich über Zeit an.
Fakt: `CentronNotificationsBL.CleanupCentronNotifications` löscht Benachrichtigungen automatisch, sofern die Einstellung `CentronNotificationsDeleteAutomatically` aktiv ist; die Aufbewahrungsdauer wird über `CentronNotificationsDeleteAfterXTime` (Default 14 Tage, DTO-Feld `DeleteAfterDays`) konfiguriert. Der Löschzeitpunkt wird als `DateTime.Now.AddDays(-DeleteAfterDays)` berechnet.
Aussage: Das System soll automatisiertes, konfigurierbares Aufräumen von Systembenachrichtigungen nach einer administrierbaren Aufbewahrungsfrist unterstützen, mit einem sinnvollen Standardwert (14 Tage), falls kein Wert gepflegt ist.
Ergebnis: Begrenztes Datenwachstum im Benachrichtigungs-/Protokollbestand ohne manuelle Administration.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs:53-68 (CleanupCentronNotifications) - Begründung: Zeigt bedingte automatische Löschung und Datumsberechnung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Settings/AppSettingsGroupBL.cs:1864-1887 (GetCentronNotificationsSettings/UpdateCentronNotifications) - Begründung: Zeigt Default-Wert 14 Tage und die konkreten ApplicationSettingID-Felder.
Prüfidee: Integrationstest: DeleteAutomatically=true, DeleteAfterDays=5 setzen, Notification mit CreatedDate vor 6 Tagen anlegen, Cleanup ausführen, prüfen dass Eintrag gelöscht wird und neuere Einträge erhalten bleiben.
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SwRS-ADM-07, SwRS-ADM-08
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ADM-03
Titel: Globaler Testmodus für Mailversand
Ebene: SyRS
Typ: nicht-funktional (Testbarkeit/Betrieb)
Akteur: IT-Verantwortlicher/QA
Vorbedingung: Automatisierte Tests oder Staging-Betrieb sollen keine echten E-Mails versenden.
Fakt: `TestMails` implementiert ein statisches Subscriber-Muster (`Start`/`AddMail`), über das während der Aktivierung sämtliche über `CentronMailFactory` erzeugten Mails als `TestMail`-Instanz behandelt werden, die E-Mails nur sammelt statt zu versenden bzw. optional als serialisierte `.eml`-Datei bereitstellt (`waitForMail`).
Aussage: Das System soll einen expliziten, laufzeitweit aktivierbaren Testmodus für den Mailversand bereitstellen, in dem E-Mails abgefangen und inspizierbar gemacht werden, statt real versendet zu werden.
Ergebnis: Sichere automatisierte Tests von mailauslösenden Geschäftsprozessen ohne Risiko echter Zustellung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 - Begründung: Vollständige Implementierung des Subscriber-Patterns.
- [PRIMÄR] src/backend/Centron.BL/Mail/Protocols/TestMail.cs:1-82 - Begründung: Konkrete Mail-Implementierung, die nur sammelt/serialisiert statt versendet.
Prüfidee: Testinfrastruktur-Review: Prüfen, in welchen automatisierten Testsuiten `TestMails.Start` verwendet wird und ob Staging-Umgebungen dies standardmäßig aktivieren.
Tracelinks: StRS-ADM-03; SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ADM-04
Titel: Masterkey-Verschlüsselung für MailScanner-Zugangsdaten
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: MailScanner-Profil mit Zugangsdaten (Passwort, OAuth-Client-Secret) für automatisiertes Postfach-Abholen wird gespeichert/gelesen.
Fakt: `MailScannerBL.EncryptProperties`/`DecryptProperties` verschlüsseln/entschlüsseln die Felder `Password` und `ClientSecret` eines `MailScannerProfile` über `CentronConfigurationDbBL.EncryptWithMasterKey`/`DecryptWithMasterKey`. Diese Methoden verwenden einen zentralen, separat verwalteten "Hotline-Masterkey" (`GetHotlineMasterKey`) für eine zusätzliche AES-Verschlüsselungsebene; ist kein Masterkey hinterlegt, liefert die Operation den Fehler "Es wurde kein Masterkey hinterlegt" statt eines unverschlüsselten Werts.
Aussage: Das System soll Zugangsgeheimnisse für automatisierte Postfachanbindungen (MailScanner-Profile) nur unter Verwendung eines zentral hinterlegten Masterkeys speichern/entschlüsseln können und die Operation bei fehlendem Masterkey mit einer definierten Fehlermeldung verweigern statt unverschlüsselt zu persistieren.
Ergebnis: Zusätzliche Schutzebene für hochsensible Postfach-Zugangsdaten (u. a. OAuth Client Secrets); "Fail-safe" bei fehlendem Masterkey statt stillem Klartext-Fallback.
Belege:
- [PRIMÄR] src/backend/Centron.BL/MailScanner/MailScannerBL.cs:90-116 (DecryptProperties, EncryptProperties) - Begründung: Zeigt zwei verschlüsselte Felder und Fehlerweiterleitung bei Fehlschlag.
- [PRIMÄR] src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:78-110 (EncryptWithMasterKey, DecryptWithMasterKey) - Begründung: Zeigt exakte Fehlermeldung "Es wurde kein Masterkey hinterlegt" und AES-Verschlüsselung mit Masterkey als Parameter.
- [KONTEXT] src/backend/Centron.Entities/Entities/MailScanner/MailScannerProfile.cs:9-23 - Begründung: Zeigt betroffene Felder (Password, ClientSecret, ClientId, TenantId) im Datenmodell.
Prüfidee: Test: Masterkey aus Konfiguration entfernen, SaveProfile mit gesetztem Password aufrufen, erwarteter Fehler statt Speicherung im Klartext.
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SwRS-ADM-10 (verwandtes Muster inkonsistenter Zugangsdaten-Verschlüsselung), SwRS-ADM-19
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ADM-05
Titel: Wählbarer Speicherort für den Masterkey
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Der "Hotline-Masterkey" (siehe SyRS-ADM-04) muss irgendwo persistiert werden.
Fakt: `CentronConfigurationDbBL` unterstützt zwei austauschbare Speicherorte für den Masterkey über das Strategy-Pattern `IMasterPasswordStorage`: `MasterPasswordConfigurationDatabaseStorage` (Konfigurationsdatenbank) und `MasterPasswordSecureFileStorage` (sichere Datei), gesteuert über die Einstellung `MasterPasswordSaveLocation` aus den Password-Manager-Einstellungen.
Aussage: Das System soll dem Administrator die Wahl lassen, den zentralen Masterkey wahlweise in der Konfigurationsdatenbank oder in einer separaten sicheren Datei außerhalb der Datenbank zu speichern.
Ergebnis: Flexibilität zwischen zentraler (datenbankgebundener) und dezentraler (dateibasierter) Schlüsselverwahrung je nach Sicherheitsanforderung des Kunden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:20-33,52-66 (Dictionary _masterPasswordStorages, IsHotlineMasterKeyAvailable, SetHotlineMasterKey) - Begründung: Zeigt zwei konkrete Storage-Implementierungen und settingsgesteuerte Auswahl.
Prüfidee: Konfigurationstest: MasterPasswordSaveLocation zwischen beiden Werten umschalten und prüfen, dass GetHotlineMasterKey konsistent aus dem jeweils aktiven Speicherort liest.
Tracelinks: SyRS-ADM-04 (gemeinsamer Masterkey-Mechanismus); StRS/SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ADM-06
Titel: Externe Lizenzserver-Anbindung
Ebene: SyRS
Typ: Schnittstelle
Akteur: IT-Verantwortlicher
Vorbedingung: Die Anwendung soll ihre Lizenzberechtigung prüfen.
Fakt: `LicenseManager` bezieht Lizenzinformationen über einen externen "c-entron Office"-Lizenzserver-Client (`OfficeClient`/`FakeOfficeClient`), wobei Zusatzdaten zur Lizenzbindung aus der Zieldatenbank stammen (`DatabaseId`, `DatabaseName`, `DatabaseCreatedDate`, `DatabaseOwnerSid` über `SQLManagementBL.GetDatabaseInfosForLicenseServer`) sowie Maschinenname und Windows-Dienstname. Für den Web-Service-Kontext wird statt eines direkten Office-Clients ein `FakeOfficeClient` verwendet, der die Lizenzdatei stattdessen über den eigenen Web-Service bezieht, mit deaktivierter Hardware-ID-Prüfung (`CheckIfLicenseIsValidForHardwareIDs = false`).
Aussage: Das System soll seine Nutzungsberechtigung über einen zentralen, produktübergreifenden Lizenzserver prüfen, wobei die Lizenz an eine konkrete Datenbankinstanz (nicht nur an Hardware) gebunden werden kann, und im mehrstufigen Web-Service-Betrieb einen alternativen Lizenzbezugsweg ohne Hardware-Bindung unterstützen.
Ergebnis: Zentral steuerbare Produktlizenzierung (Feature-/Anzahl-Gating je Lizenz), die für eine SaaS-Multi-Tenant-Architektur grundlegend überarbeitet werden müsste (Hardware-/Einzel-DB-Bindung passt nicht zu Multi-Tenant-SaaS).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 (ILicenseManager Interface: HasLicense, CheckLicense, GetLicenseCount, GetLicenseProducts) - Begründung: Zeigt Funktionsumfang der Lizenzprüfung.
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:47-115 (SettingsForWebService, GetAdditionalData) - Begründung: Zeigt Datenbank-/Maschinenbindung der Lizenz.
- [PRIMÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:117-139 (SettingsForCentronNet, FakeOfficeClient, CheckIfLicenseIsValidForHardwareIDs=false) - Begründung: Zeigt alternativen Lizenzweg für Web-Service-Kontext.
Prüfidee: Architekturklärung mit Fachbereich: Wie soll Lizenzierung/Feature-Gating in einer Multi-Tenant-SaaS-Architektur erfolgen (aktuelles Modell ist On-Premise/Einzelinstallation-zentriert)?
Tracelinks: StRS: keine direkte Verknüpfung (Lücke); SwRS: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; HYPOTHESE bzgl. Übertragbarkeit des Lizenzmodells auf SaaS (im Code keine Aussage zu geplanter SaaS-Lizenzierung, nur aktuelles On-Premise-Modell belegt)
@@ -0,0 +1,27 @@
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-01 | src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:47-65 |
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-02 | src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs:14 |
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-03 | src/backend/Centron.BL/Administration/Settings/AppSettingsBL.cs:106-152 |
| StRS-ADM-01 | SyRS-ADM-01 | SwRS-ADM-04 | src/backend/Centron.BL/Administration/Settings/SettingsCollection.cs:106-123 |
| StRS-ADM-02 | | SwRS-ADM-05 | src/backend/Centron.BL/Modules/ModuleBL.cs:22-42 |
| StRS-ADM-02 | | SwRS-ADM-06 | src/backend/Centron.BL/Modules/ModuleCategoryBL.cs:26-83 |
| | SyRS-ADM-02 | SwRS-ADM-07 | src/backend/Centron.BL/Notifications/CentronNotificationsBL.cs:79-121 |
| | SyRS-ADM-02 | SwRS-ADM-08 | src/backend/Centron.BL/Notifications/UserNotificationBL.cs:41-117 |
| StRS-ADM-03 | SyRS-ADM-03 | SwRS-ADM-09 | src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:160 |
| StRS-ADM-03 | | SwRS-ADM-10 | src/backend/Centron.BL/Mail/MailSettingsBL.cs:110-227 |
| StRS-ADM-03 | | SwRS-ADM-11 | src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:218-266 |
| StRS-ADM-03 | | SwRS-ADM-12 | src/backend/Centron.BL/Mail/Protocols/SMTPMail.cs:151-159 |
| StRS-ADM-03 | SyRS-ADM-03 | | src/backend/Centron.BL/Mail/Factory/TestMails.cs:1-56 |
| StRS-ADM-03 | | SwRS-ADM-17 | src/backend/Centron.BL/Mail/Blacklist/DomainBlacklistBL.cs:15-36 |
| StRS-ADM-03 | | SwRS-ADM-18 | src/backend/Centron.BL/Mail/MailSettingsBL.cs:233-270 |
| StRS-ADM-04 | | | src/backend/Centron.BL/Mail/MailSignatureBL.cs:111-182 |
| StRS-ADM-05 | | | src/backend/Centron.BL/Administration/Company/MandatorBL.cs:19-125 |
| | | SwRS-ADM-13 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:248-317 |
| | | SwRS-ADM-14 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:133-156 |
| | | SwRS-ADM-15 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:531-1037 |
| | | SwRS-ADM-16 | src/backend/Centron.BL/Mail/Templates/MailTemplateBL.cs:1049-1061 |
| | SyRS-ADM-04 | SwRS-ADM-19 | src/backend/Centron.BL/MailScanner/MailScannerBL.cs:57-72 |
| | SyRS-ADM-04 | SwRS-ADM-10 | src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:78-110 |
| | SyRS-ADM-05 | | src/backend/Centron.BL/Administration/CentronConfigDb/CentronConfigurationDbBL.cs:20-33 |
| | SyRS-ADM-06 | | src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 |
@@ -0,0 +1,17 @@
- **I3D**: Bezeichnung für den Primärschlüssel (Datenbank-ID) einer Entität in c-entron.NET; funktionales Pendant zu einer generischen "ID"-Spalte.
- **Mandant**: In c-entron.NET verwaltete Organisationseinheit/Gesellschaft innerhalb einer c-entron-Instanz (Modul "Mandantenverwaltung"); genaue Abgrenzung zu "Filiale" ist laut Recherche nicht abschließend geklärt.
- **Filiale (Branch)**: Niederlassung eines Mandanten mit eigenen Nummernkreisen und rechtebasierten Einschränkungen (z.B. Recht "nur eigene Filiale").
- **Ticket (Session-Ticket)**: Im Login-/Auth-Kontext ein serverseitig ausgestellter, zeitlich begrenzter Authentifizierungs-Token (Plain-Text-String, hier 30 Minuten gültig); nicht zu verwechseln mit einem Helpdesk-/Support-Ticket.
- **ApplicationKind**: Klasse, die alle am c-entron Web-Service anmeldefähigen Anwendungen (z.B. c-entron.NET, Service-Board, WebCart) mit zugehöriger Lizenz-GUID und Ablaufverhalten beschreibt.
- **LicenseGuids**: Zentrale Liste aller GUID-basierten Lizenzmerkmale (ganze Anwendungen und einzelne Features) im System.
- **Dongle-ID**: Aus der Lizenz abgeleitete Kundennummer, die u.a. zur Identifikation einer c-entron-Installation in Analytics/Telemetrie verwendet wird.
- **MEF (Managed Extensibility Framework)**: .NET-Technologie zum dynamischen Laden von Plugin-Assemblies zur Laufzeit; Basis der c-entron "Extension Engine".
- **OIDC / `oid`-Claim**: Im OpenID-Connect-ID-Token enthaltene, eindeutige Objekt-ID des Benutzerkontos in Microsoft Entra ID, über die ein c-entron-Benutzerkonto mit dem externen Identitätsanbieter verknüpft wird.
- **WebAccount**: Eigener Kontotyp für externe Kunden (Kunden der Kunden), getrennt vom internen Mitarbeiter-Login, u.a. für WebCart/c-entron Nexus genutzt.
- **SystemAuthenticationMethod**: Systemweite Einstellung, die das primär zu verwendende Authentifizierungsverfahren (None/Basic/ActiveDirectory/OpenIdConnect) festlegt.
- **ModuleFeatures**: Zentrale Klasse mit booleschen Feature-Flags, über die einzelne Module unabhängig vom Rechtesystem ein-/ausgeblendet werden können.
- **CentronModuleCategory**: Enum zur fachlichen Gruppierung aller registrierten Module (z.B. Sales, Ticket, Billing, Administration).
- **c-entron Nexus**: Separate, web-/Blazor-basierte Anwendung ("c-entron Web") für externe Web-Accounts (u.a. WebCart-Shop), ergänzend zum WPF-Desktop-Client.
- **Sonderpreise**: Im c-entron.NET-Adressstamm hinterlegte kundenspezifische Preise, die die im WebCart für den jeweiligen Web-Account sichtbaren Artikel und Preise bestimmen.
- **TAPI**: Telephony API — Windows-Standardschnittstelle für Telefonie-Integration, hier über die modifizierte Drittanbieterkomponente TraySoft AddTAPI.NET genutzt.
@@ -0,0 +1,3 @@
- **SwRS-ARCH-06** (Fehlende repository-interne Web-Service-API-Referenz): Die zentrale Web-Service-API-Dokumentation existiert offenbar nur als externe PDF auf einem internen Netzlaufwerk (`P:\Entwicklung C#\...`); diese war im Rahmen der Recherche nicht zugreifbar, sodass unklar bleibt, ob/wo eine vollständige, versionierte API-Referenz für die c-entron Web-Service-Schnittstelle tatsächlich existiert.
@@ -0,0 +1,116 @@
ID: StRS-ARCH-01
Titel: GUID-basiertes Lizenzmodell
Ebene: StRS
Typ: funktional / Lizenzierung
Akteur: c-entron-Vertrieb, Kunde, Systemadministrator
Vorbedingung: Kunde hat einen Lizenzvertrag
Fakt: Lizenzen sind GUID-basierte Merkmale mit optionalem `count`, `valid until date`, `valid until version`. Es wird zwischen `Applications` (dürfen sich am Web-Service anmelden, Liste in `ApplicationKind.cs`, ca. 40 Einträge z.B. Centron, ServiceBoard, WebCart, PasswordManager, Outlook Add-In) und reinen Einzel-Feature-Lizenzen (`LicenseGuids.cs`) unterschieden. Single Source of Truth ist ein zentraler Lizenzserver.
Aussage: Das System soll ein zentrales, GUID-basiertes Lizenzmodell mit Zähler-, Ablaufdatum- und Versionsbindung besitzen, das sowohl den Zugang ganzer Anwendungen als auch einzelner Features steuert.
Ergebnis: Feingranulare kommerzielle Steuerung von Funktionsumfang und Zugriff; zentrale Voraussetzung für Feature-Gating in einer SaaS-Variante (z.B. Tarif-/Paketmodell).
Belege:
- [PRIMÄR] docs/reference/security/licensing-system.md:1-44 - Beschreibung GUID/count/valid until date/valid until version, Applications vs. Only Licenses
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs:11-53 - ca. 40 ApplicationKind-Einträge mit LicenseGuids, teils mit `licenseUsageKind: LicenseUsageKind.PerUser`, `expirationKind`
- [SEKUNDÄR] src/backend/Centron.BL/Administration/Licensing/LicenseManager.cs:26-40 - ILicenseManager Interface (HasLicense, GetLicenseCount, CheckLicense)
Prüfidee: Klären, ob Lizenzprüfung offline (Dongle/Cache) funktionsfähig bleibt und wie oft synchronisiert wird (`FileLicenseCache`, `UpdateLicenseInterval`).
Tracelinks: SyRS-ARCH-02, SyRS-ARCH-13, SyRS-ARCH-15
Konsolidierung: nein
Status: belegt
---
ID: StRS-ARCH-02
Titel: Windows-Desktop-Systemvoraussetzung
Ebene: StRS
Typ: nicht-funktional (ISO25010: Kompatibilität / Systemumgebung)
Akteur: IT-Administrator, Endanwender
Vorbedingung: -
Fakt: Der Client (`Centron.WPF.UI.csproj`) zielt auf `net10.0-windows`, ist ein `WinExe` (WPF, WinForms-Abhängigkeiten wie `System.Windows.Forms.Screen`), bindet COM-Interop zu Microsoft Outlook (`Microsoft.Office.Interop.Outlook`) sowie ein modifiziertes Drittanbieter-TAPI-Modul (`Traysoft.AddTapi.dll`) ein. `global.json` fixiert die .NET-SDK-Version auf 10.0.100.
Aussage: Das System (c-entron.NET) soll als natives Windows-Desktop-Programm mit lokalen Windows-/Outlook-/TAPI-Abhängigkeiten betrieben werden und ist somit nicht plattformunabhängig.
Ergebnis: Klare Systemvoraussetzung "Windows + .NET 10 Runtime + ggf. Outlook/TAPI-Hardware" für den Bestandsclient; zentrale Motivation für die geplante Web-/SaaS-Neuimplementierung (Plattformunabhängigkeit als Ziel).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Centron.WPF.UI.csproj:1-24 - TargetFramework net10.0-windows, WinExe, COM-Interop-Referenzen
- [PRIMÄR] global.json:1-6 - SDK-Version 10.0.100
- [SEKUNDÄR] docs/reference/architecture/tapi.md:1-10 - TAPI-Integration nur für Windows-Produkte (c-entron.NET, Outlook Add-In, ServiceBoard)
Prüfidee: Abgleich mit Kunden-Systemvoraussetzungsdokument (falls vorhanden) auf weitere Hardware-/Software-Voraussetzungen (z.B. Terminalserver-Freigabe).
Tracelinks: SyRS-ARCH-08, SyRS-ARCH-11, SyRS-ARCH-14, SyRS-ARCH-17
Konsolidierung: nein
Status: belegt
---
ID: StRS-ARCH-03
Titel: Eingeschränkte Sprachauswahl im Produktivbetrieb
Ebene: StRS
Typ: nicht-funktional (ISO25010: Internationalisierbarkeit) — Abweichung/Workaround
Akteur: Endanwender
Vorbedingung: LoginDialog wird angezeigt
Fakt: Im `LoginDialogViewModel` wird die Sprachliste initial nur mit `de-DE` befüllt; `en-US` wird nur hinzugefügt, wenn `IsDevBuild` (Compile-Symbol `DEV_BUILD`) aktiv ist. Standardsprache ist explizit "German is the default language" (Kommentar im Code). Produktivbenutzer können in der UI somit i.d.R. nur Deutsch wählen, obwohl englische Ressourcendateien im Code existieren.
Aussage: Das System soll (Soll-Zustand im Ist offen) die im Backend vorhandene Mehrsprachigkeit (Deutsch/Englisch) auch produktiv über die Login-/Spracheinstellung zugänglich machen.
Ergebnis: Diskrepanz zwischen technischer Lokalisierungs-Infrastruktur (SyRS-ARCH-09) und tatsächlich für Endanwender nutzbarer Sprachauswahl; für SaaS-Zielbild zu klären, ob Mehrsprachigkeit ein echtes Geschäftsziel ist oder nur Entwickler-/Testzweck.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:93-98 - Languages.Add(en-US) nur `if (IsDevBuild)`
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:197-206 - IsDevBuild liest Compile-Symbol DEV_BUILD
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:239 - Kommentar "German is the default language."
Prüfidee: Produktentscheidung/Product Owner befragen, ob Englisch-Support als Geschäftsziel für die Web-Neuimplementierung gilt (aktuell nur "verstecktes" Dev-Feature).
Tracelinks: SyRS-ARCH-09
Konsolidierung: nein
Status: belegt (Soll-Zustand/Produktentscheidung zu Mehrsprachigkeit offen; HYPOTHESE: fehlende Produktentscheidung, ob Mehrsprachigkeit für Endkunden freigeschaltet werden soll)
---
ID: StRS-ARCH-04
Titel: Mandanten- und Filialverwaltung
Ebene: StRS
Typ: funktional
Akteur: Kunde mit mehreren Gesellschaften/Niederlassungen, Administrator
Vorbedingung: Lizenz "branch functionality" vorhanden (laut licensing-system.md Beispiel)
Fakt: Es existiert ein Modul "Mandantenverwaltung" (`MandatorManagementAppModuleController`, ID `{717AD6A2-...}`, Kategorie Administration) sowie ein separates "BranchManagement" (Filialverwaltung, Nummernkreise) unter demselben Namensraum `Administration.MandatorManagement`.
Aussage: Das System soll die Verwaltung mehrerer Mandanten/Gesellschaften bzw. Filialen (Niederlassungen) innerhalb einer c-entron-Instanz unterstützen, inklusive eigener Nummernkreise je Filiale.
Ergebnis: Mehrmandantenfähigkeit auf Ebene "mehrere Unternehmenseinheiten in einer Datenbank" (kein Hinweis auf Datenbank-pro-Kunde-Mandantentrennung im Sinne von SaaS-Multi-Tenancy); wichtig für SyRS-Datenmodell-Entscheidung bei Neuimplementierung.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/MandatorManagementAppModuleController.cs:9-45 - Modul "Mandanten Verwaltung"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/MandatorManagement/BranchManagement/* - BranchManagementView/ViewModel, NumberGroupsViewModel (Dateiliste)
- [KONTEXT] CentronRights.md:14-26 - Rechte mit Filial-Einschränkung ("nur eigene Filiale") als Beleg für aktive fachliche Nutzung von Filialen/Mandanten in Rechten
Prüfidee: Klären, ob "Mandant" hier = rechtlich eigenständige Gesellschaft (mit eigener Buchhaltung) oder nur Organisationseinheit ist; Datenmodell (MandantI3D-Spalten) verifizieren.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (Abgrenzung "Mandant" vs. "Filiale" nicht abschließend verifiziert; HYPOTHESE: Begriffsdefinition nur aus Namensgebung/Icon abgeleitet, keine Fachdoku gelesen)
---
ID: StRS-ARCH-05
Titel: WebCart als Kundenweb-Kanal
Ebene: StRS
Typ: funktional
Akteur: Kunde des Kunden (Web-Account-Benutzer)
Vorbedingung: Web-Account wurde in c-entron.NET Adressstamm angelegt, Sonderpreise hinterlegt
Fakt: README.md beschreibt "WebCart" als Feature primär für Kunden der Kunden: Login als Web-Account bei "c-entron Nexus" (separate Web-Anwendung, "c-entron Web"), Artikelanzeige basiert auf hinterlegten "Sonderpreisen" im c-entron.NET Adressstamm, Zugriff über Menüpunkt "Shop".
Aussage: Das System soll einen webbasierten Bestellkanal (WebCart) für Endkunden der c-entron-Kunden bereitstellen, dessen Sortiment/Preise zentral im ERP (c-entron.NET) gepflegt werden.
Ergebnis: Bereits vorhandener Web-Kanal (c-entron Nexus) als Blaupause/Vorstufe für die geplante SaaS-Neuimplementierung — zeigt, dass Teile des Systems bereits heute web-basiert sind und mit dem ERP-Kern über Web-Accounts/Sonderpreise integriert sind.
Belege:
- [PRIMÄR] README.md:1,29-35 - Beschreibung WebCart, Web-Account-Login, Sonderpreise, "Shop"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/WebCart (Namensraum in ModuleRegistration.cs Zeile 40) - zugehöriges WPF-Verwaltungsmodul
Prüfidee: Architektur von "c-entron Nexus" (separates Blazor-Projekt laut README-Kontext "azure-blazor") im Detail untersuchen — ggf. eigener Cluster/Repository-Bereich außerhalb des hier untersuchten Scopes.
Tracelinks: SyRS-ARCH-16
Konsolidierung: nein
Status: belegt (Detailarchitektur von c-entron Nexus außerhalb des recherchierten Bereichs; HYPOTHESE: Nexus/Blazor-Code nicht gelesen, nur README)
---
ID: StRS-ARCH-06
Titel: Breites Produkt-/Anwendungsportfolio
Ebene: StRS
Typ: funktional
Akteur: Produktmanagement, Entwickler
Vorbedingung: -
Fakt: `ApplicationKind.cs` listet neben dem Kern-ERP ("NEXOWARE c-entron ERP") ca. 40 weitere, separat lizenzierte Anwendungen/Produkte im selben Ökosystem (u.a. Service-Board, Service-Board Online, c-entron Nexus, Outlook Add-In, PasswordManager, WebCart, WebSuitePro, DocumentSync, Riversuite-Familie [Inventory/Compliance/Monitoring/Mobile/Online/Pro/N13/RFlow/SupRemo], TAPI-Server, Communicator, MailScanner/MailScannerNET, diverse ExternalApp-Connectoren zu Drittsystemen wie c-pra, DocBee, Visoma, WOASI).
Aussage: Das System ist Teil eines breiten Produkt-/Anwendungsportfolios (nicht nur ein einzelnes ERP), das über ein gemeinsames Lizenz- und Authentifizierungssystem am zentralen Web-Service andockt.
Ergebnis: Wichtige Erkenntnis für den StRS-Systemüberblick: Die Web-/SaaS-Neuimplementierung des ERP-Kerns muss die Schnittstellen zu diesem breiteren Produktportfolio (mind. Authentifizierung/Lizenzierung) weiterhin bedienen können, auch wenn die Einzelprodukte selbst außerhalb des Scopes liegen.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Logins/ApplicationKind.cs:11-53 - vollständige Liste der ApplicationKind-Instanzen
Prüfidee: Mit Produktmanagement klären, welche dieser Anwendungen im Rahmen der SaaS-Neuimplementierung migriert/integriert werden müssen vs. weiterhin als separate Legacy-Clients bestehen bleiben.
Tracelinks: SyRS-ARCH-01
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,114 @@
ID: SwRS-ARCH-01
Titel: OIDC-Token-Austausch-Schnittstelle (/jwt/login)
Ebene: SwRS
Typ: Schnittstelle / Sicherheit
Akteur: Endanwender, externe Client-Anwendung
Vorbedingung: OpenID Connect ist serverseitig aktiviert (`JwtEnabled`)
Fakt: Der OIDC-Login-Flow läuft über `GET /config/jwt` (anonym, liefert Authority/Audience/Enabled), MSAL-Tokenakquise (ID-Token, Scopes `openid`,`profile`), `POST /jwt/login` (Bearer-ID-Token, Body `Application`/`AppVersion`/`Device`) und liefert ein c-entron-Ticket (Plain-Text-String) mit 30 Minuten Gültigkeit zurück. Nutzerzuordnung erfolgt über `oid`-Claim gegen Spalte `OpenIdConnectSubjectIdentifier` in Tabelle `Sichbenu`.
Aussage: Das System soll ein Microsoft-Entra-ID-basiertes Single-Sign-On über einen definierten Token-Austausch-Endpunkt (`/jwt/login`) bereitstellen, der ein zeitlich begrenztes Sitzungs-Ticket ausstellt.
Ergebnis: SSO-fähige Schnittstelle, die für Web-/SaaS-Clients wiederverwendbar ist (keine c-entron-spezifischen Credentials nötig, sofern Konto verknüpft).
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md:150-157 - Ticket-Erstellung mit `expireDate = DateTime.Now.AddMinutes(30)`
- [PRIMÄR] src/webservice/Centron.Controllers/Controllers/Unversioned/JwtAuthController.cs (referenziert in Doku Zeile 395) - `/jwt/login` Endpoint
- [KONTEXT] src/backend/Centron.BL/Administration/Logins/Auth/OpenIdConnectAuthenticator.cs (Doku Zeile 397) - User-Lookup per oid-Claim
Prüfidee: Verifizieren der Ticket-Lebensdauer und ob ein Refresh-Mechanismus existiert (nicht in Doku beschrieben).
Tracelinks: SyRS-ARCH-02, StRS-ARCH-01
Konsolidierung: Kandidat: SyRS-ARCH-02
Status: belegt
---
ID: SwRS-ARCH-02
Titel: Entity/DTO/ViewModel-Trennung mit Mapping-Regeln
Ebene: SwRS
Typ: Daten / nicht-funktional (ISO25010: Wartbarkeit)
Akteur: Entwickler (indirekt: alle Endanwender über Datenkonsistenz)
Vorbedingung: -
Fakt: Die Architektur trennt strikt drei Objekttypen: `Entity` (BL-Layer, NHibernate-Mapping via Fluent NHibernate, Primärschlüssel "I3D", ausschließlich virtuelle Properties, keine Logik), `DTO` (WebService/Logics-Layer, `[DataContract]`/`[DataMember]`, `List<T>` statt `IEnumerable<T>` zur JSON-Serialisierung, `DateTime?` statt `DateTime` wegen .NET-Default-Wert-Problem) und `ViewModel` (UI-Layer). Konvertierung Entity→DTO über `ObjectMapper.Map<TEntity,TDTO>()`, DTO→Entity manuell (ObjectMapper hierfür explizit verboten).
Aussage: Das System soll intern konsequent zwischen Datenbank-Entities, Transport-DTOs und UI-ViewModels trennen und definierte Konvertierungsregeln (automatisiertes Mapping nur Entity→DTO, manuelles Mapping DTO→Entity) einhalten.
Ergebnis: Klare Schichtentrennung als Wartbarkeits-/Kapselungsprinzip; wesentliche Randbedingung für Neuimplementierung des Datenzugriffs (z.B. Wahl von EF Core/Dapper und äquivalentem DTO-Konzept für eine Web-API).
Belege:
- [PRIMÄR] docs/reference/architecture/dtos-and-entities.md:15-118 - vollständige Beschreibung Entity/DTO/Mapping-Regeln
Prüfidee: Stichprobe an realen Entity/DTO-Paaren (z.B. Helpdesk/Ticket) auf Einhaltung der Regeln (List<T>, DateTime?, kein ObjectMapper bei DTO→Entity).
Tracelinks: SyRS-ARCH-01, StRS-ARCH-06
Konsolidierung: nein
Status: belegt
---
ID: SwRS-ARCH-03
Titel: Result/Response-Fehlerbehandlungsmuster
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Wartbarkeit) / Schnittstelle
Akteur: Entwickler
Vorbedingung: -
Fakt: Fehlerbehandlung folgt einem zweistufigen Muster: `Result`/`Result<T>` (Business-Logic-Layer, Status Success/Error/Warning, Factory-Methoden `AsSuccess`/`AsError`/`AsWarning`/`FromException`) wird über `Response.FromBLResult(...)`/`Response<T>.FromBLResult(...)` in ein API-`Response`-Objekt (Status Success/Failed, `MessageCode`) übersetzt; `Warning` wird auf API-Ebene als `Success` gemappt.
Aussage: Das System soll einen einheitlichen, geschichteten Result/Response-Mechanismus für Operationsergebnisse und Fehlerbehandlung verwenden, der in der Business-Logik feiner granuliert (inkl. Warnungen) als an der API-Grenze.
Ergebnis: Konsistentes Fehler-/Statusmodell über alle Schichten; direkte Vorlage für ein äquivalentes Response-Envelope-Format einer REST/GraphQL-API in der Web-Neuimplementierung.
Belege:
- [PRIMÄR] docs/reference/architecture/results-and-responses.md:18-147 - Result/Response-Klassenstruktur, Statuswerte, Mapping-Logik
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs:24-59 - clientseitige Zuordnung von `MessageCode` zu lokalisierten Fehlermeldungen (z.B. RightCheckFailed, LicenseNotFound, MandatoryFieldsNotFilled)
Prüfidee: Prüfen, ob alle Webservice-Endpunkte konsequent `Response`/`Response<T>` statt roher Exceptions zurückgeben.
Tracelinks: SyRS-ARCH-01, SyRS-ARCH-10, StRS-ARCH-06
Konsolidierung: Kandidat: SwRS-ARCH-02
Status: belegt
---
ID: SwRS-ARCH-04
Titel: Persistenz benutzerspezifischer UI-Layouts
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Benutzbarkeit) / Daten
Akteur: Endanwender
Vorbedingung: Benutzer passt Ansicht (Grid-Spalten, Fensteranordnung, Docking) an
Fakt: Es existiert eine eigene Layout-Persistenz-Schicht (`Layout/*LayoutSerializer.cs`) für diverse DevExpress-Steuerelemente (GridControl, TreeListControl, DockLayoutManager, NavBarControl, ComboBoxEdit, DateEdit u.a.), die Benutzeroberflächen-Zustand (Spaltenreihenfolge, Fensterlayout etc.) persistiert und wiederherstellt (`ICustomLayoutSavingControl`, `ILayoutSerializerOnlyIfSaveLayoutActive`).
Aussage: Das System soll benutzerspezifische Anpassungen von Ansichten (Spalten, Fensteranordnung, Docking-Layout) dauerhaft je Benutzer speichern und beim nächsten Start wiederherstellen.
Ergebnis: Personalisierung der Arbeitsumgebung als etabliertes Feature; funktionale Anforderung, die in einer Web-Anwendung durch äquivalente Persistenz von UI-Zustand (z.B. je Benutzer serverseitig gespeicherte Grid-/Layout-Einstellungen) nachgebildet werden müsste.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Layout/GridControlLayoutSerializer.cs, DockLayoutManagerLayoutSerializer.cs, TreeListControlLayoutSerializer.cs (Dateiliste) - konkrete Serializer je Steuerelement
- [KONTEXT] src/centron/Centron.WPF.UI/Layout/ILayoutSerializerOnlyIfSaveLayoutActive.cs - Hinweis auf konfigurierbares "Layout speichern"-Verhalten
Prüfidee: Prüfen, wo (Registry/DB/Datei) das Layout gespeichert wird und ob es geräteübergreifend synchronisiert wird (nicht recherchiert).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (Speicherort/Synchronisationsverhalten nicht verifiziert; HYPOTHESE: fehlende Information zu Speicherort)
---
ID: SwRS-ARCH-05
Titel: Einheitliches MVVM-Grundgerüst
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Wartbarkeit) / MVVM
Akteur: Entwickler
Vorbedingung: -
Fakt: Alle recherchierten ViewModels (`LoginDialogViewModel`, Modul-ViewModels) implementieren/erben von DevExpress-MVVM-Basisklassen (`ViewModelBase`, `BindableBase`) sowie einer eigenen Basis `CentronBindableBase` (in `Centron.Core.Mvvm`). Views erben von einer eigenen `BaseModule`-Basisklasse (statt UserControl) für Fachmodule bzw. `BaseSettingControl` für Einstellungsseiten; Rechtevergabe, Initialisierung (`DoInitalize`) und Speichern (`DoSave`) folgen festen Konventionen.
Aussage: Das System soll ein einheitliches MVVM-Grundgerüst mit klar getrennten Verantwortlichkeiten (View: Anzeige/Ribbon, ViewModel: Zustand/Async-Init/Save, Container: Rechte-/Feature-Prüfung) für alle Fachmodule und Einstellungsseiten verwenden.
Ergebnis: Konsistente Entwicklungskonventionen als Wartbarkeitsfaktor; die eigentliche `mvvm-in-centron.md`-Referenzdokumentation ist inhaltsleer (Platzhalter "I don't know, but I would like to - please tell me."), das Muster musste daher aus Code-Konventionen (create-module.md, create-settings-page.md) rekonstruiert werden.
Belege:
- [PRIMÄR] docs/guides/ui/create-module.md:52-103 - BaseModule, IRibbonControlModule*, ViewModel-Konventionen
- [PRIMÄR] docs/guides/ui/create-settings-page.md:1-45 - BaseSettingControl, DoInitalize/DoSave/CanSave/DoAfterSave-Konvention, explizites Verbot eigener MessageBoxen bei Fehlern
- [KONTEXT] src/shared/Centron.Core/Mvvm/CentronBindableBase.cs (Dateiname) - eigene MVVM-Basisklasse
- [KONTEXT] docs/reference/architecture/mvvm-in-centron.md:1-3 - Dokument explizit als Platzhalter/unvollständig markiert
Prüfidee: `CentronBindableBase.cs` und mind. 2-3 reale ViewModel-Klassen lesen, um das Muster über Doku-Rekonstruktion hinaus zu verifizieren.
Tracelinks: SyRS-ARCH-05
Konsolidierung: nein
Status: belegt (Referenzdokumentation mvvm-in-centron.md leer/unvollständig, Muster rekonstruiert; HYPOTHESE: Muster aus Nachbardokumenten und Namenskonventionen rekonstruiert, nicht aus einer autoritativen MVVM-Spezifikation)
---
ID: SwRS-ARCH-06
Titel: Fehlende repository-interne Web-Service-API-Referenz
Ebene: SwRS
Typ: nicht-funktional (ISO25010: Wartbarkeit) / Sonstiges
Akteur: Entwickler
Vorbedingung: -
Fakt: Zentrale technische Basis-Dokumentation (`stanislaus-secret-api-documentation.md`) verweist für die "eigentliche" Web-Service-API-Dokumentation nur auf eine externe PDF-Datei auf einem internen Netzlaufwerk (`P:\Entwicklung C#\...`), nicht auf ein im Repository verfügbares oder generiertes Dokument.
Aussage: (Kein direktes Systemsoll ableitbar) — Dokumentationslücke: Eine vollständige, versionierte API-Referenz der c-entron Web-Service-Schnittstelle ist im Repository nicht auffindbar.
Ergebnis: Für ein RRE-Projekt mit Ziel Web-/SaaS-Neuimplementierung fehlt eine zentrale, im Code-Repository gepflegte API-Spezifikation; dies ist selbst ein Befund (Prozess-/Dokumentationslücke), kein Produktmerkmal.
Belege:
- [PRIMÄR] docs/reference/architecture/stanislaus-secret-api-documentation.md:1-10 - Verweis auf externe PDF ohne Repository-Zugriff
Prüfidee: Klären, ob die referenzierte PDF beschafft werden kann, um die Web-Service-API (`ICentronRestService`) vollständiger zu dokumentieren, ggf. stattdessen `ICentronRestService`-Interface direkt im Code als Quelle nutzen (in anderen Clustern ggf. bereits geschehen).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: HYPOTHESE (externe PDF-Referenz nicht zugreifbar/nicht gelesen, keine Repository-eigene API-Spezifikation auffindbar)
@@ -0,0 +1,346 @@
ID: SyRS-ARCH-01
Titel: Zwei Betriebsarten: Direkt-DB vs. Web-Service
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Übertragbarkeit / Anpassbarkeit)
Akteur: IT-Administrator (Betreiber), Systemarchitekt
Vorbedingung: Installation der c-entron.NET Desktop-Anwendung
Fakt: Der Client unterstützt wahlweise eine direkte SQL-Server-Verbindung oder eine Verbindung über den c-entron Web-Service (`CentronConnectionType.SqlServer` vs. `CentronConnectionType.CentronWebServices`). Jedes Fachmodul deklariert über `ICentronAppModuleController.SupportsConnectionTypes`, welche Verbindungsarten es unterstützt (laut Doku-Kommentar "sollte immer beides sein").
Aussage: Das System soll wahlweise über eine direkte Datenbankverbindung oder über eine Web-Service-Schicht (REST/SOAP-artig) betrieben werden können, wobei Fachmodule beide Betriebsarten unterstützen müssen.
Ergebnis: Zwei-Schichten-Architektur mit austauschbarer Datenzugriffsstrategie; Grundlage für spätere Web-/SaaS-Migration (Web-Service-Pfad ist der näher an SaaS liegende Modus).
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Connections/CentronConnectionType.cs:6-12 - Enum mit den zwei Werten SqlServer/CentronWebServices
- [PRIMÄR] src/centron/Centron.WPF.UI.Extension/Modules/ICentronAppModuleController.cs:46-49 - Property SupportsConnectionTypes mit Kommentar "this should always be both sql and webservice!"
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Modules/Administration/Connections/LoginDialogViewModel.cs:296-313 - Verzweigung PreDoLoginToCentron je nach ConnectionType
Prüfidee: Stichprobenartig prüfen, ob alle 84 registrierten Module tatsächlich beide ConnectionTypes deklarieren; Abweichungen dokumentieren.
Tracelinks: StRS-ARCH-06
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-02
Titel: Mehrere konfigurierbare Authentifizierungsverfahren
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Endanwender (c-entron.NET Benutzer)
Vorbedingung: Anwendungsstart, LoginDialog wird angezeigt
Fakt: Die Authentifizierung unterstützt mehrere Verfahren: `Basic` (c-entron-eigenes Login), `ActiveDirectory`, `OpenIdConnect` (Microsoft Entra ID via MSAL/OIDC) sowie `WebAccount` (Kunden-Login für Web-Funktionen). `AuthenticatorFactory` wählt anhand der Systemeinstellung `SystemAuthenticationMethod` und ggf. Benutzer-spezifischer `AuthentificationKind` mit Fallback-Kette (`FallbackAuthenticator`) den passenden Authenticator.
Aussage: Das System soll mehrere konfigurierbare Authentifizierungsverfahren (Benutzername/Passwort, Active Directory, OpenID Connect/Microsoft Entra ID) unterstützen und pro Benutzer mit Fallback-Logik kombinieren können.
Ergebnis: Zentraler Authentifizierungs-Einstiegspunkt mit Erweiterbarkeit für weitere Identity-Provider; wichtig für SaaS (SSO-Fähigkeit vorhanden).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs:44-146 - GetAuthenticatorWithSystemAuth/GetMainAuthenticator mit Switch über BasicAuthObject/WebAccountAuthObject/OpenIdConnectAuthObject
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md:1-197 - vollständiger OIDC-Login-Flow inkl. Sequenzdiagramm
- [SEKUNDÄR] src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs (JwtAuthority=10351, JwtAudience=10352, SystemAuthenticationMethod=10360) - Konfigurationspunkte laut Doku
Prüfidee: End-to-End-Test aller vier Login-Pfade inkl. Fallback bei Fehlkonfiguration (z.B. AD nicht erreichbar).
Tracelinks: StRS-ARCH-01
Konsolidierung: Kandidat: SwRS-ARCH-01, SyRS-ARCH-03
Status: belegt
---
ID: SyRS-ARCH-03
Titel: TOTP-basierte Zwei-Faktor-Authentifizierung
Ebene: SyRS
Typ: Sicherheit
Akteur: Endanwender, Administrator
Vorbedingung: Benutzer hat einen Zwei-Faktor-Schlüssel in der Personalverwaltung hinterlegt
Fakt: Es existiert eine TOTP-basierte Zwei-Faktor-Authentifizierung (`TwoFactorAuthenticationBL`, `Centron.Core.GoogleAuthenticator.TwoFactorAuthenticator`, Entität `TwoFactorAuthLastLogin`). `ValidateAuthenticationPin` prüft eine eingegebene PIN gegen den hinterlegten Schlüssel.
Aussage: Das System soll optional eine Zwei-Faktor-Authentifizierung (TOTP, z.B. Authenticator-App) pro Benutzer als zusätzliche Absicherung des Logins unterstützen.
Ergebnis: Zusätzliche Sicherheitsstufe für sensible Konten; relevant für SaaS-Compliance-Anforderungen (z.B. Zugriffsschutz bei extern erreichbarem Login).
Belege:
- [PRIMÄR] src/backend/Centron.BL/TwoFactorAuthenticator/TwoFactorAuthenticationBL.cs:43-54 - ValidateAuthenticationPin nutzt GoogleAuthenticator.TwoFactorAuthenticator.ValidatePin
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/Administration/TwoFactorAuthLastLogin.cs - Entität für letzten 2FA-Login
- [KONTEXT] src/shared/Centron.Core/GoogleAuthenticator/TwoFactorAuthenticator.cs, src/shared/Centron.Core/TotpAuth/* - TOTP-Implementierung
Prüfidee: Prüfen, ob 2FA erzwingbar (Pflicht) konfiguriert werden kann oder rein optional ist; wie Wiederherstellung bei Verlust des Geräts erfolgt (nicht recherchiert).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (Umfang Pflicht vs. optional nicht abschließend geklärt; HYPOTHESE: es fehlt Beleg für eine erzwingende Policy)
---
ID: SyRS-ARCH-04
Titel: Entwickler-Schutz vor Kunden-E-Mail-Versand (DEBUG)
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Systemadministrator
Vorbedingung: Anwendung läuft im DEBUG-Build (Entwicklungsumgebung)
Fakt: `DeveloperSecurity.cs` ersetzt in DEBUG-Builds alle E-Mail-Adressen außerhalb der Domain `nexoware.com` automatisch durch `test@nexoware.com`, um versehentliches Versenden an echte Kunden zu verhindern. In RELEASE-Builds ist dieser Schutz nicht aktiv.
Aussage: Das System soll in Entwicklungs-/Testumgebungen automatisch verhindern, dass E-Mails an reale externe Empfänger versendet werden.
Ergebnis: Reduziertes Risiko von Datenlecks/fehlgeleiteter Kommunikation während Entwicklung und Test; Hinweis für Testkonzept einer SaaS-Neuimplementierung (Sandbox-Mailing-Regel sollte übernommen werden).
Belege:
- [PRIMÄR] docs/reference/security/developer-security.md:11-23 - Beschreibung des Verhaltens inkl. Domainregel
Prüfidee: Verifizieren, dass die Regel tatsächlich in `DeveloperSecurity.cs` so implementiert ist (Doku nicht Code gelesen) und ob ein äquivalenter Schutz für RELEASE-Testinstanzen fehlt.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (nur aus Dokumentation, Quellcode DeveloperSecurity.cs nicht gegengelesen; HYPOTHESE: exakte Implementierungsdetails ungeprüft)
---
ID: SyRS-ARCH-05
Titel: Modul-Framework mit einheitlichem Interface
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Modularität / Erweiterbarkeit)
Akteur: Entwickler, Systemarchitekt
Vorbedingung: -
Fakt: Fachmodule implementieren `ICentronAppModuleController` (ID, ModuleName, Description, Icons, MainCategory, SupportsConnectionTypes, CreateModuleInstance, GetSettings, GetRights, Dispose) und werden zentral in `ModuleRegistration.cs` registriert. Aktuell sind 84 Module über `ModuleRegistrationItem.For<T>(...)` eingetragen, gruppiert in 18 Hauptkategorien (`CentronModuleCategory`: MyCentron, Sales, Ticket, Contract, Billing, DataExchange, Logistic, Purchasing, Controlling, Administration, BaseData, PasswordManager, Help, Tests, Automate, Production, QM, NexowareConnect).
Aussage: Das System soll Fachfunktionen als eigenständige, über ein einheitliches Interface registrierte Module bereitstellen, die zur Laufzeit anhand von Rechte- und Feature-Flag-Prüfung ein-/ausgeblendet werden.
Ergebnis: Plugin-artige, kategorisierte Modularchitektur als fachliche Gliederung des Gesamtsystems; direkte Vorlage für die Bounded-Context-/Microservice-Gliederung einer Web-Neuimplementierung.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI.Extension/Modules/ICentronAppModuleController.cs:11-71 - vollständiges Interface
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs:414-416 sowie Zählung (grep) - 84 ModuleRegistrationItem.For-Aufrufe
- [PRIMÄR] src/backend/Centron.Interfaces/UI/Modules/CentronModuleCategory.cs:3-23 - 18 Kategorien
- [SEKUNDÄR] docs/guides/ui/create-module.md:1-116 - Entwickler-Anleitung zur Modulerstellung
Prüfidee: Kategorien gegen die tatsächlich in den Fachclustern untersuchten Module abgleichen (Vollständigkeitscheck der Systemübersicht).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-06
Titel: Rechte- und Feature-Flag-Steuerung je Modul
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: Administrator, Endanwender
Vorbedingung: Modul ist registriert
Fakt: Jede `ModuleRegistrationItem.For<T>` Registrierung erhält einen optionalen Rechte-Ausdruck (`Expression<Func<bool>> rightsCheck`, z.B. `Helper.HasAnyRight(...)`) und einen optionalen Feature-Flag-Check (`Func<bool> moduleFeatureCheck`, z.B. `() => ModuleFeatures.IsThingiesAvailable` oder `() => Debugger.IsAttached`). `ModuleRightsExpressionParser` wertet die Rechte-Ausdrücke zur Laufzeit aus (`CheckRights`, `GetRights`).
Aussage: Das System soll die Sichtbarkeit jedes Fachmoduls unabhängig über (a) ein deklaratives Rechtesystem und (b) Feature-Flags steuern können, ohne Codeänderung am Modul selbst.
Ergebnis: Feingranulare Zugriffssteuerung und kontrollierte Feature-Auslieferung (z.B. Module "in Entwicklung" ausblenden); Vorlage für Rollen-/Rechtekonzept einer SaaS-Variante.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/ModuleRegistration.cs:910-951 - Klasse ModuleRegistrationItem mit CheckModuleFeatures/CheckRights/GetRights
- [SEKUNDÄR] docs/guides/ui/create-module.md:105-116 - Beschreibung "erster Parameter Rechte, zweiter Parameter Feature-Flag"
- [KONTEXT] CentronRights.md:1-80 - Beispielhafte, granulare Rechte inkl. "restricting rights" (nur eigene/nur eigene Filiale)
Prüfidee: Prüfen, ob Rechte pro Mandant/Filiale unterschiedlich vergeben werden können (Hinweis "nur eigene Filiale" in CentronRights.md).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-ARCH-05
Status: belegt
---
ID: SyRS-ARCH-07
Titel: Plugin-/Extension-Engine (MEF)
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Übertragbarkeit / Anpassbarkeit)
Akteur: Entwickler, Drittanbieter/Partner
Vorbedingung: DLLs liegen im Unterordner "Extensions" des Anwendungsverzeichnisses
Fakt: `ExtensionLogic.LoadExtensionEngine()` nutzt MEF (`System.ComponentModel.Composition`, `DirectoryCatalog`) um zur Laufzeit alle `*.dll` im Ordner "Extensions" zu laden und exportierte `ICore`-Implementierungen zu sammeln; `RegisterExtensions()`/`UnregisterExtensions()` rufen `Register(CentronApplication.Instance)`/`Unregister()` auf jeder gefundenen Extension auf.
Aussage: Das System soll eine Plugin-Schnittstelle bereitstellen, über die zusätzliche Erweiterungen als separate Assemblies zur Laufzeit geladen und in die Anwendung integriert werden können, ohne den Kern neu zu kompilieren.
Ergebnis: Erweiterbarkeit für Partner-/Individualintegrationen; architektonisches Merkmal, das bei einer Web-Neuimplementierung durch ein äquivalentes Plugin-/Extension-API (z.B. Webhooks, serverseitige Module) ersetzt werden müsste.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Extension/ExtensionLogic.cs:29-52 - LoadExtensionEngine mit DirectoryCatalog/CompositionContainer
- [PRIMÄR] src/centron/Centron.WPF.UI/Extension/ExtensionLogic.cs:54-67 - RegisterExtensions
- [SEKUNDÄR] src/centron/Centron.WPF.UI/App.xaml.cs:322-325 - DoInitializeExtensionEngine als Teil der Startsequenz
Prüfidee: Prüfen, wie viele produktive Extensions aktuell existieren und ob die Schnittstelle stabil versioniert ist.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-08
Titel: Single-Instance mit Argument-Weiterleitung
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Zuverlässigkeit / Reife)
Akteur: Endanwender
Vorbedingung: Anwendungsstart mit Kommandozeilenargumenten (z.B. Deep-Link via URL-Protokoll)
Fakt: `StartupArgSynchronizer` verwendet einen computerweiten, pfadgebundenen `Mutex`, um zu erkennen, ob bereits eine Instanz der c-entron.NET läuft. Falls ja, werden Argumente über eine Memory-Mapped-File (`FileArgSeparator`, `ArgFileLength=1024`) an den laufenden Prozess übergeben statt eine zweite Instanz zu starten; bei mehreren laufenden Prozessen wird ein Auswahldialog (`SelectTargetProcessView`) gezeigt.
Aussage: Das System soll sicherstellen, dass pro Benutzer/Pfad nur eine Instanz der Anwendung aktiv ist, und Start-Argumente/Deep-Links an eine bereits laufende Instanz weiterleiten können.
Ergebnis: Konsistentes Single-Instance-Verhalten und URL-Protokoll-Aktivierung (z.B. aus E-Mail/Browser heraus ein bestimmtes Modul öffnen); bei Web-Migration äquivalent durch Tab-/Session-Handling und Deep-Links zu ersetzen.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/StartupArgs/StartupArgSynchronizer.cs:18-49 - Mutex-basierte Instanzerkennung
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:97-126 - Nutzung im Startup (TryPassArgsToRunningApp, ReceivedArgs)
- [KONTEXT] src/centron/Centron.WPF.UI/StartupArgs/SelectTargetProcessView.xaml - UI bei mehreren laufenden Instanzen
Prüfidee: Testen des Verhaltens bei mehreren parallel angemeldeten Terminal-Server-Sitzungen (RDP/Citrix) desselben Benutzers.
Tracelinks: StRS-ARCH-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-09
Titel: Mehrsprachige Ressourcendatei-Infrastruktur
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Internationalisierbarkeit / Anpassbarkeit)
Akteur: Endanwender
Vorbedingung: -
Fakt: Lokalisierung erfolgt über .NET-Standard-Ressourcendateien (.resx) pro Assembly (`LocalizedStrings.resx` = Deutsch/Standard, `LocalizedStrings.en.resx` = Englisch), gesteuert über `CultureInfo.CurrentUICulture`. Getrennte Ressourcen existieren für WPF-UI-Layer und Business-Logic-Layer. Web-Service-Antworten werden über den HTTP-Header `Accept-Language` lokalisiert.
Aussage: Das System soll Benutzeroberfläche und fachliche Meldungen mehrsprachig (mind. Deutsch als Standard, Englisch als Zusatzsprache) über eine schichtenweise Ressourcendatei-Struktur bereitstellen, wobei Web-Service-Aufrufe die Sprache über den Accept-Language-Header steuern können.
Ergebnis: Grundlage für Mehrsprachigkeit im gesamten System; Struktur (getrennte Ressourcen je Schicht/Assembly) ist relevant für Übertragung in eine Web-Architektur (z.B. i18n-Framework, Sprachverhandlung über HTTP).
Belege:
- [PRIMÄR] docs/guides/ui/localization.md:1-35 - Ressourcenstruktur, CultureInfo.CurrentUICulture
- [PRIMÄR] docs/guides/ui/localization.md:275-280 - Accept-Language Header Beispiel für Web-Service-Calls
Prüfidee: Vollständigkeitsprüfung, ob wirklich alle Layer (auch Webservice-Fehlermeldungen) konsistent lokalisiert sind (laut Doku-Beispiel nur "einige" Codepfade).
Tracelinks: StRS-ARCH-03
Konsolidierung: Kandidat: StRS-ARCH-03
Status: belegt
---
ID: SyRS-ARCH-10
Titel: Zentrales globales Exception-Handling
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Zuverlässigkeit)
Akteur: Endanwender, Support
Vorbedingung: Unbehandelte Exception oder unbeobachtete Task-Exception tritt auf
Fakt: `App.xaml.cs` registriert globale Handler (`DispatcherUnhandledException`, `TaskScheduler.UnobservedTaskException`), die an `CentronApplication.Instance.ExceptionHandler` (Typ `CentronExceptionHandler`) delegieren. Dieser kennt eine Liste bekannter, bewusst zu ignorierender Exceptions (mit Typ + Stacktrace-Marker, max. Rekursionstiefe 2) sowie eine Tabelle von `MessageCode`→lokalisierter Nutzermeldung.
Aussage: Das System soll unbehandelte Ausnahmen zentral abfangen, protokollieren (NLog) und dem Benutzer eine lokalisierte, verständliche Fehlermeldung anzeigen, statt abzustürzen, mit Ausnahme explizit als harmlos bekannter Fehlerbilder.
Ergebnis: Erhöhte gefühlte Stabilität der Desktop-Anwendung trotz Einzel-Ausnahmen; Verhaltens-Vorlage für zentrales Error-Handling/Logging-Konzept einer Web-Anwendung (globaler Error-Boundary + strukturiertes Logging).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:130-232 - Registrierung globaler Exception-Handler inkl. Fallback-MessageBox vor Initialisierung
- [PRIMÄR] src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs:18-85 - HandleException, ignorierte Exceptions, Message-Mapping
Prüfidee: Prüfen, ob äquivalentes zentrales Error-Handling auch auf Web-Service-Seite existiert (nicht recherchiert in diesem Cluster).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-11
Titel: Stufenweise Splash-Screen-Startsequenz
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Effizienz / Startzeitverhalten)
Akteur: Endanwender
Vorbedingung: Anwendungsstart
Fakt: Der Start läuft über eine sichtbare Splash-Screen-Sequenz mit fünf benannten, sequentiellen Initialisierungsschritten (`DoInitializeClassContainer`, `DoInitializeDevExpressControls`, `DoInitializeObjectMapper`, `DoInitializeDaoFactory`, `DoInitializeExtensionEngine`), jeweils mit lokalisiertem Fortschrittstext. Vor der Anmeldung wird zusätzlich `ProfileOptimization` (.NET Startup-Profil) aktiviert und mehrere produktspezifische Workarounds (FastReport, DevExpress-Ribbon) ausgeführt.
Aussage: Das System soll dem Benutzer während des Anwendungsstarts sichtbares, stufenweises Feedback über den Initialisierungsfortschritt geben und dabei zeitkritische Subsysteme (DB-Zugriff, Objektmapper, Extension-Engine, UI-Theme) in definierter Reihenfolge vorbereiten.
Ergebnis: Vorhersehbare, für den Benutzer nachvollziehbare Startsequenz; bei Web-Migration i.d.R. obsolet (Server-seitiges Preloading statt Client-Splash), aber die fachliche Reihenfolge (Konfiguration→Datenbank→Objektmapper→Erweiterungen) bleibt als Abhängigkeitsgraph relevant.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:236-285 - DoInitializeWithSplashScreen mit Actions-Liste
- [SEKUNDÄR] src/centron/Centron.WPF.UI/App.xaml.cs:287-360 - Einzelmethoden der Initialisierungsschritte
Prüfidee: Startzeit messen und mit Zielwert (falls vorhanden) vergleichen; klären ob preload (DAOFactory/ObjectMapper) bei Web-Service-Verbindung übersprungen wird (Code zeigt: ja, abhängig von `IsDefaultConnectionAWebServiceConnection`/`RememberLogin`).
Tracelinks: StRS-ARCH-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-12
Titel: Anwendungsweite Command Palette
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Benutzbarkeit)
Akteur: Endanwender (Power-User)
Vorbedingung: Anwendung läuft
Fakt: Es existiert eine "Command Palette" (`Start/CommandPalette/*`, u.a. `CommandPaletteViewModel`, diverse `*CommandProvider`-Klassen für Kundensuche, Artikelsuche, Belegsuche, Ticketnummern, Modul-Liste etc.) als zentrales Tastatur-gesteuertes Schnellzugriffs-/Such-Werkzeug über viele Fachbereiche hinweg.
Aussage: Das System soll eine anwendungsweite, tastaturbasierte Befehls-/Suchpalette bereitstellen, über die Module, Datensätze (Kunden, Artikel, Belege, Tickets, Seriennummern) und Aktionen schnell gefunden und ausgeführt werden können.
Ergebnis: Zentrales, cross-modulares Produktivitätsfeature; sollte als eigenständige, modulunabhängige Querschnittsfunktion auch in einer Web-Neuimplementierung erhalten bleiben (z.B. als globale Suchleiste/Command-K-Pattern).
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Start/CommandPalette/CommandPaletteViewModel.cs (Dateiname/Struktur) - zentrale ViewModel-Klasse
- [SEKUNDÄR] src/centron/Centron.WPF.UI/Start/CommandPalette/Provider/*.cs (Dateiliste, u.a. CustomerSearchCommandProvider, ArticleSearchCommandProvider, DocumentSearchCommandProvider, ReceiptNumberCommandProvider, HelpdeskNumberCommandProvider, ModuleListCommandProvider) - modulübergreifende Provider
Prüfidee: Nutzungshäufigkeit/Bedeutung beim Kunden erfragen (aus Code allein nicht ableitbar, ob zentrales oder Nischenfeature).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (Bedeutung/Priorität aus Endnutzersicht nicht belegt; HYPOTHESE: keine Nutzungsstatistik verfügbar)
---
ID: SyRS-ARCH-13
Titel: Lizenz- und benutzerbezogene Nutzungstelemetrie
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Funktionale Eignung) / Datenschutz
Akteur: Produktmanagement, Endanwender (indirekt betroffen)
Vorbedingung: Anwendung ist eingeloggt
Fakt: `CentronAnalyticsManager` abonniert `ModuleOpenedEvent`/`ModuleClosedEvent` über einen zentralen `EventAggregator` und sendet Nutzungsereignisse (Modul-Nutzung) über einen `AnalyticEventsManager`, identifiziert über eine aus der Lizenz abgeleitete `dongleId` (Kundennummer) und die interne Mitarbeiter-ID (`employeeId`). Fehlen beide IDs, wird das Tracking deaktiviert ("Initialisiert...NULL. No events will be tracked!").
Aussage: Das System soll Nutzungstelemetrie (welche Module wie genutzt werden) kundenbezogen (Lizenznummer) und benutzerbezogen erfassen können, sofern eine gültige Lizenz- und Benutzerzuordnung vorliegt.
Ergebnis: Grundlage für produktseitige Nutzungsauswertung; für SaaS-Neuimplementierung datenschutzrechtlich (DSGVO) zu bewerten, da personenbezogene Nutzungsdaten erfasst werden.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Managers/CentronAnalyticsManager.cs:23-50 - Initialize(), Subscribe auf ModuleOpenedEvent/ModuleClosedEvent, dongleId/employeeId-Ermittlung
Prüfidee: Prüfen, ob eine Einwilligung/Opt-out für Telemetrie existiert und wie/wo die Daten gespeichert werden (nicht im gelesenen Ausschnitt ersichtlich).
Tracelinks: StRS-ARCH-01
Konsolidierung: nein
Status: belegt (Opt-out/Einwilligungsmechanismus nicht verifiziert; HYPOTHESE: fehlende Information zu Consent-Handling)
---
ID: SyRS-ARCH-14
Titel: TAPI-Telefonieanbindung
Ebene: SyRS
Typ: Schnittstelle
Akteur: Endanwender (Telefonie-Nutzer), Administrator
Vorbedingung: TAPI-fähige Telefonanlage/Software-Client vorhanden
Fakt: Telefonie-Integration erfolgt über die kommerzielle Komponente "TraySoft AddTAPI.NET", die firmenintern für .NET 5/6-Kompatibilität modifiziert wurde (`ProcessIncomingCall` Workaround wegen entferntem `BeginInvoke`). Genutzt in c-entron.NET (`PhoneManager.cs`, `TapiPhoneConnectionManager.cs`), Outlook Add-In und ServiceBoard.
Aussage: Das System soll eine TAPI-basierte Telefonieanbindung (eingehende/ausgehende Anrufe, Rufnummererkennung) über eine modifizierte Drittanbieterkomponente bereitstellen, die produktübergreifend (Desktop-Client, Outlook Add-In, ServiceBoard) genutzt wird.
Ergebnis: Cross-Produkt-Abhängigkeit von einer proprietären, Windows-gebundenen TAPI-Bibliothek; kritischer Migrationsaspekt für Web-/SaaS-Variante (TAPI ist ein reines Windows-Desktop-Konzept, erfordert Alternativkonzept z.B. Cloud-Telefonie/CTI-API).
Belege:
- [PRIMÄR] docs/reference/architecture/tapi.md:1-36 - Komponente, Produkte, Modifikation, Debugging-Hinweise
- [KONTEXT] src/centron/Centron.WPF.UI/Managers/PhoneManager.cs, TapiPhoneConnectionManager.cs (Dateiliste) - produktinterne Nutzung
Prüfidee: Umfang der TAPI-Nutzung beim Kunden erheben (Pflichtfeature oder Nischenfunktion) für Entscheidung über Migrationsstrategie.
Tracelinks: StRS-ARCH-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-ARCH-15
Titel: Verknüpfung c-entron-Konto mit Microsoft Entra ID
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Aktivierung der Windows-Anmeldung (SSO) über Entra ID gewünscht
Fakt: Für OIDC ist neben der App-Registration in Azure AD eine Verknüpfung jedes c-entron-Benutzers mit seiner Microsoft-Entra-Object-ID (Spalte `OpenIdConnectSubjectIdentifier` in Tabelle `Sichbenu`) nötig, entweder per Self-Service-Endpoint (`POST /jwt/connect_accounts`) oder Admin-Zuweisung über die WPF-UI unter "Persönliche Einstellungen".
Aussage: Das System soll die Verknüpfung eines c-entron-Benutzerkontos mit einem externen Identitätsanbieter-Konto (Microsoft Entra ID) sowohl per Selbstbedienung durch den Benutzer als auch administrativ ermöglichen.
Ergebnis: Flexibles Account-Linking-Modell als Voraussetzung für produktives SSO; Vorlage für generisches "externe Identität verknüpfen"-Konzept bei SaaS mit mehreren Identity Providern.
Belege:
- [PRIMÄR] docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md:180-196 - Self-Service/Admin-Zuweisung, Endpoint-Tabelle
- [KONTEXT] src/centron/Centron.WPF.UI/Modules/MyCentron/PersonalSettings/OpenIdConnectAccount (Namensraum, ModuleRegistration.cs Zeile 137) - zugehöriges UI-Modul "Persönliche Einstellungen"
Prüfidee: Prüfen, ob Entkopplung (Verknüpfung aufheben) ebenfalls möglich ist und wie der Fall "Entra-Konto bereits mit anderem c-entron-User verknüpft" behandelt wird.
Tracelinks: StRS-ARCH-01
Konsolidierung: Kandidat: SyRS-ARCH-02, SwRS-ARCH-01
Status: belegt
---
ID: SyRS-ARCH-16
Titel: Getrennte Authentifizierungspfade Mitarbeiter/Kunde
Ebene: SyRS
Typ: funktional / Sicherheit
Akteur: c-entron-Kunde (Endkunde des Kunden), Web-Account-Benutzer
Vorbedingung: -
Fakt: Neben Mitarbeiter-Logins existiert ein separater Authentifizierungspfad `WebAccountAuthObject`/`WebAccountAuthenticator` sowie `WebLoginType.Customer` (vs. `WebLoginType.User`/`WebLoginType.Domain`), der eigene Kundenkonten (z.B. für WebCart/Web-Shop) gegenüber internen Mitarbeiterkonten unterscheidet.
Aussage: Das System soll zwischen internen Mitarbeiter-Logins und externen Kunden-("Web-Account")-Logins mit eigenem Authentifizierungspfad und eigenen Berechtigungen unterscheiden.
Ergebnis: Grundlage für ein zweistufiges Nutzermodell (intern/extern) im Gesamtsystem; direkt relevant für die Zielarchitektur eines Kundenportals in der SaaS-Variante.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs:89-95,122-123,163-186 - WebAccountAuthObject-Zweig, WebLoginType.Customer
- [KONTEXT] src/backend/Centron.Entities/Entities/Administration/Logins/WebAccount.cs (Dateiname) - eigene Entität für Web-Konten
Prüfidee: Rechte-/Rollenmodell für WebAccount-Benutzer im Detail prüfen (vermutlich stark eingeschränkt ggü. Mitarbeitern).
Tracelinks: StRS-ARCH-05
Konsolidierung: Kandidat: StRS-ARCH-05
Status: belegt
---
ID: SyRS-ARCH-17
Titel: RDP-/Terminalserver-Reconnect-Behandlung (Workaround)
Ebene: SyRS
Typ: nicht-funktional (ISO25010: Kompatibilität)
Akteur: Systemadministrator (Terminalserver-Betrieb)
Vorbedingung: Betrieb über Remote-Desktop-Sitzung (RDP/Terminalserver/Citrix)
Fakt: Es existiert (inzwischen deaktivierter, aber im Code dokumentierter) produktionsrelevanter Workaround-Code für den Fall, dass sich eine RDP-Sitzung neu verbindet: Dies löst laut Kommentar einen bekannten DevExpress-Performance-Bug aus (massive Verlangsamung nach Reconnect), wofür früher ein Warnhinweis mit Neustart-Option angezeigt wurde (Ticket 115706, seit 2024-05 testweise entfernt, Ticket erwähnt in Kommentar SKA 2024-05-08).
Aussage: Das System soll (historisch) den Betrieb über Remote-Desktop-Sitzungen mit Reconnect-Verhalten unterstützen und Performance-Einbußen nach Reconnect erkennen bzw. dem Benutzer eine Neustart-Option anbieten.
Ergebnis: Hinweis auf reale Betriebsumgebung "Terminalserver/RDP" als verbreitetes Deployment-Szenario beim Kunden; relevant für StRS "unterstützte Umgebungen", auch wenn der spezifische Workaround aktuell deaktiviert ist.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:151-155 - Auskommentierter SystemEvents.UserPreferenceChanged-Hook mit Verweis auf Ticket 147477/115706
- [PRIMÄR] src/centron/Centron.WPF.UI/App.xaml.cs:464-526 - vollständige (tote, aber vorhandene) Implementierung SystemEventsOnUserPreferenceChanged inkl. Benutzertext zu RDP-Verbindungsabbruch
Prüfidee: Klären, ob der Workaround dauerhaft entfernt bleibt oder nur testweise; Terminalserver-Nutzung beim Kunden quantitativ erheben.
Tracelinks: StRS-ARCH-02
Konsolidierung: nein
Status: belegt; Workaround (aktuell im Code deaktiviert; unklar ob weiterhin Systemvoraussetzung; HYPOTHESE: Unklar ob RDP-Betrieb weiterhin offizielle Systemvoraussetzung ist oder nur Altlast)
---
ID: SyRS-ARCH-18
Titel: Eindeutige Fehlermeldung bei Auth-Fehlkonfiguration
Ebene: SyRS
Typ: Sicherheit
Akteur: Systemadministrator
Vorbedingung: Active-Directory-Anmeldung konfiguriert (`ActiveDirectoryAuthEnabled`)
Fakt: `AuthenticatorFactory` unterscheidet klar zwischen dem global konfigurierten `SystemAuthenticationMethod` (None/Basic/ActiveDirectory/OpenIdConnect) und einer pro-Benutzer hinterlegten `AuthentificationKind` (CentronLogin/WindowsAuth[obsolet]/OpenIdConnectAuth). Bei Konflikt (z.B. Benutzer ist für WindowsAuth markiert, aber AD ist nicht korrekt konfiguriert) wird ein klar lokalisierter Fehler über `FailingAuthenticator` zurückgegeben statt eines stillen Fallbacks.
Aussage: Das System soll bei inkonsistenter Authentifizierungs-Konfiguration (z.B. Benutzer für einen nicht verfügbaren Auth-Mechanismus markiert) eine eindeutige, lokalisierte Fehlermeldung liefern statt unsicherer stiller Fallbacks.
Ergebnis: Robustheit/Nachvollziehbarkeit bei Fehlkonfiguration von Authentifizierungsmechanismen; wichtige Sicherheitsanforderung, die bei Multi-Provider-Login-Konzepten (SaaS) übernommen werden sollte.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs:66-82 - FallbackAuthenticator mit FailingAuthenticator und lokalisierter Fehlermeldung `AuthenticatorFactory_FallbackMisconfiguredErrorMessage`
Prüfidee: End-to-End-Test: Benutzer mit AuthentificationKind=WindowsAuth bei deaktiviertem AD anmelden lassen, erwartete Fehlermeldung verifizieren.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-ARCH-02
Status: belegt
@@ -0,0 +1,17 @@
| StRS-ARCH-01 | SyRS-ARCH-02 | SwRS-ARCH-01 | docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md |
| StRS-ARCH-06 | SyRS-ARCH-01 | SwRS-ARCH-02 | docs/reference/architecture/dtos-and-entities.md |
| StRS-ARCH-06 | SyRS-ARCH-01 | SwRS-ARCH-03 | docs/reference/architecture/results-and-responses.md |
| | SyRS-ARCH-10 | SwRS-ARCH-03 | src/centron/Centron.WPF.UI/Managers/CentronExceptionHandler.cs |
| | SyRS-ARCH-05 | SwRS-ARCH-05 | docs/guides/ui/create-module.md |
| | | SwRS-ARCH-04 | src/centron/Centron.WPF.UI/Layout/GridControlLayoutSerializer.cs |
| | | SwRS-ARCH-06 | docs/reference/architecture/stanislaus-secret-api-documentation.md |
| StRS-ARCH-02 | SyRS-ARCH-08 | | src/centron/Centron.WPF.UI/StartupArgs/StartupArgSynchronizer.cs |
| StRS-ARCH-02 | SyRS-ARCH-11 | | src/centron/Centron.WPF.UI/App.xaml.cs |
| StRS-ARCH-02 | SyRS-ARCH-14 | | docs/reference/architecture/tapi.md |
| StRS-ARCH-02 | SyRS-ARCH-17 | | src/centron/Centron.WPF.UI/App.xaml.cs |
| StRS-ARCH-01 | SyRS-ARCH-13 | | src/centron/Centron.WPF.UI/Managers/CentronAnalyticsManager.cs |
| StRS-ARCH-01 | SyRS-ARCH-15 | | docs/reference/security/anmelden-mit-microsoft-technische-anleitung.md |
| StRS-ARCH-03 | SyRS-ARCH-09 | | docs/guides/ui/localization.md |
| StRS-ARCH-05 | SyRS-ARCH-16 | | src/backend/Centron.BL/Administration/Logins/Auth/AuthenticatorFactory.cs |
@@ -0,0 +1,15 @@
- **ZUGFeRD**: Deutsches Hybridformat für elektronische Rechnungen, kombiniert ein menschenlesbares PDF/A-3 mit eingebettetem strukturiertem XML (Cross Industry Invoice).
- **XRechnung**: XML-basiertes E-Rechnungsformat nach EN16931, in Deutschland verpflichtend für Rechnungen an öffentliche Auftraggeber; benötigt zwingend eine Leitweg-ID.
- **Leitweg-ID**: Adressierungs-/Routing-Code für öffentliche Auftraggeber in Deutschland, identifiziert die empfangende Behörde in einer XRechnung.
- **Reverse Charge**: Umkehr der Steuerschuldnerschaft auf den Leistungsempfänger gem. §13b UStG; die Rechnung weist dann 0% USt. mit entsprechendem Hinweistext aus.
- **Kontingent (Vertrag)**: Im Wartungs-/Servicevertrag vereinbartes Leistungs- oder Geldvolumen, das über die Vertragslaufzeit durch Rechnungen verbraucht und durch Gutschriften wieder freigegeben wird.
- **RMM (Remote Monitoring & Management)**: Externes System (in c-entron z.B. "Riverbird") zur Fernüberwachung von Kunden-IT-Infrastruktur, liefert Nutzungsdaten als Grundlage für nutzungsbasierte Vertragsabrechnung.
- **Mahnstufe (Dunning Level)**: Eskalationsstufe (1-3) im Mahnwesen, an die Fristen, Gebühren und optionale Belegsperren gekoppelt sind.
- **Titelposition**: Gruppierende Rechnungsposition, die mehrere untergeordnete Artikelpositionen zusammenfasst; kann beim E-Rechnungsexport nur eingeklappt (aggregiert) exportiert werden.
- **Aktionspreis (ActionPrice)**: Zeitlich befristeter Sonderpreis eines Herstellers/Distributors für einen Artikel, angezeigt in der Preismatrix im Gültigkeitszeitraum.
- **Festschreibung (IsFixed)**: Zustand einer Rechnung, ab dem inhaltliche Änderungen softwareseitig gesperrt sind (typischerweise nach Buchung/Export).
- **Belegnummernkreis (NumberGroup)**: Konfigurierbarer, meist mandantenweiter Zähler zur eindeutigen, race-condition-sicheren Vergabe von Belegnummern (Rechnungen, Verträge etc.).
- **SEPA-Mandatsreferenz**: Eindeutige Referenznummer eines SEPA-Lastschriftmandats, ermächtigt den Bankeinzug beim Kunden.
- **AnlageLog**: Zentrale, belegtypübergreifende Protokolltabelle für Audit-Log-Einträge (Erstellung, Änderung, Abrechnung, Kündigung etc.), referenziert Belege über `AnlageI3D`+`AnlageArt`.
- **ContractArticleReferenzes**: Verknüpfungsentität zwischen einem Vertragsartikel und den zugehörigen RMM-Abrechnungsregeln (Kontingentmenge, Über-/Unterbuchungsdeckelung).
- **ReceiptState**: Einheitliche, belegtypübergreifende Statusmaschine mit den Werten Active ("offen"), Completed ("abgeschlossen") und Canceled ("storniert").
@@ -0,0 +1,2 @@
- **SyRS-BILL-19** (Standard-Steuersatz 19% bei leeren Titelpositionen): Regel nur durch zwei übereinstimmende Dokumentationsartefakte belegt (docs/reference/zugferd-feldzuordnung-anwender.md:331, docs/reference/zugferd-field-mapping.md:365), kein PRIMÄR-Codebeleg (konkrete Codezeile in `InvoiceZugferdBL.cs` für den 19%-Default nicht gegengelesen). Für den Risikobereich Abrechnung/Steuerberechnung ist vor Übernahme in die konsolidierte Spezifikation eine Verifikation im Quellcode nötig.
@@ -0,0 +1,74 @@
ID: StRS-BILL-01
Titel: E-Rechnungserzeugung (ZUGFeRD/XRechnung) rechtssicher automatisieren
Ebene: StRS
Typ: funktional
Akteur: Buchhaltung / Finanzbuchhaltung
Vorbedingung: Rechnung/Gutschrift ist im System erfasst und soll elektronisch versendet werden
Fakt: c-entron generiert beim Rechnungs-/Gutschriftexport automatisiert ZUGFeRD- bzw. XRechnung-konforme XML-Dateien (Versionen 1.0 bis 2.1/XRechnung 3.0.1), implementiert in `InvoiceZugferdBL.cs`. Die Formatwahl (ZUGFeRD Comfort vs. XRechnung) erfolgt automatisch anhand des Vorhandenseins einer Leitweg-ID.
Aussage: Das System soll rechtssichere elektronische Rechnungen (ZUGFeRD/XRechnung) automatisiert aus den erfassten Rechnungs- und Gutschriftdaten erzeugen können, ohne manuelle Nacharbeit der Anwenderin.
Ergebnis: Verkäufer kann gesetzeskonforme E-Rechnungen (auch für öffentliche Auftraggeber) versenden.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156 (GenerateZugferdFile, Formatwahl anhand leitwegID) - Begründung: Kernmechanik der automatisierten E-Rechnungserzeugung im Code nachgewiesen
- [SEKUNDÄR] docs/reference/zugferd-feldzuordnung-anwender.md:9-14 - Begründung: Anwenderdokumentation bestätigt unterstützte Versionen
Prüfidee: Export einer Rechnung ohne und mit Leitweg-ID durchführen, resultierendes Dateiformat/-schema prüfen (KOSIT-Validator)
Tracelinks: SyRS-BILL-06, SyRS-BILL-07, SyRS-BILL-08, SyRS-BILL-09, SyRS-BILL-10, SyRS-BILL-11, SyRS-BILL-12, SyRS-BILL-17, SyRS-BILL-19
Konsolidierung: nein
Status: belegt
---
ID: StRS-BILL-02
Titel: Automatisierte wiederkehrende Vertragsabrechnung (Contract-Billing)
Ebene: StRS
Typ: funktional
Akteur: Vertriebsinnendienst / Vertragsmanagement
Vorbedingung: Kunde hat einen laufenden Wartungs-/Servicevertrag mit wiederkehrender Abrechnung
Fakt: c-entron bietet ein eigenständiges Contract-Billing-Subsystem (`ReceiptContract`, `AutomaticFacturaBL.Contracts`), das Verträge nach konfigurierbaren Intervallen (Daily/Monthly/Quarterly/Yearly) automatisiert abrechnet, inkl. Integration externer RMM-Nutzungsdaten (Riverbird) und Kontingentverwaltung.
Aussage: Das System soll wiederkehrende Vertragsleistungen automatisiert, nach konfigurierbarem Abrechnungsintervall und unter Berücksichtigung von Nutzungsdaten/Kontingenten korrekt fakturieren.
Ergebnis: Reduzierter manueller Aufwand bei der Abrechnung von Wartungs-/MSP-Verträgen, korrekte periodengerechte Rechnungsstellung.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs (Felder BillingIntervalKind, BillingIntervalDuration, AutomatedBilling) - Begründung: Entität trägt Konfigurationsfelder für automatisierte Intervallabrechnung
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:721-802 (CheckRMMArticle) - Begründung: Ausführbare Logik zur automatisierten RMM-basierten Rechnungspositionserzeugung
Prüfidee: Testvertrag mit monatlichem Intervall anlegen, automatische Abrechnung anstoßen, Rechnungsperiode/-betrag verifizieren
Tracelinks: SyRS-BILL-13, SyRS-BILL-14, SyRS-BILL-15
Konsolidierung: nein
Status: belegt
---
ID: StRS-BILL-03
Titel: Mahnstufenbasierte Beleg-/Auftragssperre zur Kreditrisikobegrenzung
Ebene: StRS
Typ: funktional
Akteur: Finanzbuchhaltung / Mahnwesen
Vorbedingung: Kunde hat offene, überfällige Forderungen
Fakt: Das System führt ein Mahnstufen-Modell (`DunningLevel1Fees/2/3`, `DunningLetterAfterDays1-3`) je Kunde und kann konfigurierbar ab einer bestimmten Mahnstufe die Neuanlage von Belegen (z.B. Aufträgen) sperren (`LockOrderAfterDunningLevel`, durchgesetzt in `ReceiptBL.CanUserCreateNewReceiptsAtCustomerOrSupplier`).
Aussage: Das System soll säumige Kunden anhand eines Mahnstufenmodells identifizieren und optional automatisch von der Neuanlage weiterer Belege ausschließen, um das Ausfallrisiko zu begrenzen.
Ergebnis: Kreditrisikobegrenzung; Vertrieb kann keine neuen Aufträge/Belege für gesperrte Kunden anlegen, solange die Mahnstufe nicht sinkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 (CanUserCreateNewReceiptsAtCustomerOrSupplier, exakte Fehlermeldung "Aufgrund der Mahnstufe darf kein neuer Beleg ... angelegt werden.") - Begründung: Durchgesetzte Regel im Code, inkl. Fehlermeldungstext
- [PRIMÄR] src/backend/Centron.Entities/Entities/Accounts/AccountCustomer.cs:25 (LockOrderAfterDunningLevel) - Begründung: Persistiertes Feld je Kunde als Datengrundlage der Regel
Prüfidee: Kunde mit LockOrderAfterDunningLevel=2 und aktueller Mahnstufe 2 anlegen, Versuch neuen Auftrag zu erstellen -> erwartete Fehlermeldung
Tracelinks: SyRS-BILL-16, SwRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: StRS-BILL-04
Titel: Rechtssichere Rechnungsstornierung ohne Bruch der Buchhaltungsintegrität
Ebene: StRS
Typ: nicht-funktional (Compliance/Datenintegrität)
Akteur: Buchhaltung / Wirtschaftsprüfung
Vorbedingung: Eine Rechnung wurde bereits weiterverarbeitet (z.B. exportiert, in Buchhaltung übernommen) oder ist eine Barrechnung
Fakt: `ReceiptInvoiceBL.CancelInvoice` verweigert die Stornierung, wenn die Rechnung bereits storniert ist, es sich um eine Barrechnung handelt, sie bereits weiterverarbeitet oder bereits an die Buchhaltung exportiert wurde, oder es sich bei einer Vertragsrechnung nicht um die zuletzt erstellte handelt.
Aussage: Das System soll die Stornierung von Rechnungen nur zulassen, solange keine downstream-Verarbeitung (Export, Weiterverarbeitung) stattgefunden hat, um Inkonsistenzen mit Buchhaltung/Finanzamt zu vermeiden.
Ergebnis: Verhinderung nachträglicher Inkonsistenzen zwischen ERP und exportierten/gebuchten Finanzdaten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:143-206 (CancelInvoice, komplette Prüfkette) - Begründung: Vollständige, im Code durchgesetzte Vorbedingungskette mit exakten Fehlermeldungen
Prüfidee: Testrechnung exportieren (BookKeepingExportBL) und danach Stornoversuch -> Fehlermeldung "...bereits exportiert wurde." erwarten
Tracelinks: SyRS-BILL-01, SyRS-BILL-02, SyRS-BILL-03, SyRS-BILL-04, SyRS-BILL-05, SyRS-BILL-18, SyRS-BILL-20, SwRS-BILL-02, SwRS-BILL-05
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,109 @@
ID: SwRS-BILL-01
Titel: CanUserCreateNewReceiptsAtCustomerOrSupplier – Mahnstufen-Sperrlogik
Ebene: SwRS
Typ: funktional
Akteur: System (Auftrags-/Belegsperre)
Vorbedingung: Benutzer versucht neuen Beleg (z.B. Auftrag) für einen Kunden/Lieferanten anzulegen
Fakt: `ReceiptBL.CanUserCreateNewReceiptsAtCustomerOrSupplier<TReceipt>` (Zeilen 10194-10219) ermittelt zunächst die aktuelle Mahnstufe des Kunden (`GetCustomerOrSupplierDunningLevel<TReceipt>`) und den je Belegtyp konfigurierten Sperr-Schwellwert (`BlockNewReceiptsDunningLevel`, für Aufträge implementiert in `OrderSpecificLogic.cs:687-693` über `customerDetail.OrderLockAfterDunning`). Ist die aktuelle Mahnstufe >= Schwellwert, wird die Anlage mit Fehlermeldung "Aufgrund der Mahnstufe darf kein neuer Beleg vom Typ \"{...}\" angelegt werden." verweigert.
Aussage: Das System soll je Belegtyp konfigurierbar prüfen, ob die aktuelle Mahnstufe eines Kunden die Neuanlage von Belegen sperrt, und die Anlage in diesem Fall mit einer sprechenden Fehlermeldung verweigern.
Ergebnis: Automatisierte Kreditkontrolle direkt in der Belegerfassung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 - Begründung: Vollständige Sperrlogik inkl. exakter Fehlermeldung
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Orders/OrderSpecificLogic.cs:687-693 - Begründung: Konkrete belegtypspezifische Implementierung des Schwellwerts für Aufträge
Prüfidee: Kunde mit LockOrderAfterDunning=1 und aktueller Mahnstufe 1: Auftragsanlage -> Fehlermeldung erwarten; Mahnstufe 0 -> Anlage möglich
Tracelinks: SyRS-BILL-16, StRS-BILL-03
Konsolidierung: nein
Status: belegt
---
ID: SwRS-BILL-02
Titel: Rückbuchung des Rechnungssaldos bei Löschung eines Zahlungseingangs
Ebene: SwRS
Typ: funktional
Akteur: Zahlungseingang / Buchhaltung
Vorbedingung: Ein bereits erfasster Zahlungseingang zu einer Rechnung wird gelöscht
Fakt: `PaymentsBL.DeleteIncomingPayment` (Zeilen 38-78) prüft das Recht `INCOMING_PAYMENT_TRANSACTIONS`; sofern `filter.DontChangeInvoice == false`, wird je betroffener Rechnung die Summe der zu löschenden Zahlungsbeträge negiert (`* -1`) und über `ReceiptBL.UpdateReceiptIsPaid` mit Währungsfaktor (`* invoice.CurrencyFactor`) und Log-Grund "Zahlungseingang gelöscht" zurückgebucht.
Aussage: Das System soll beim Löschen eines Zahlungseingangs den zugehörigen offenen/bezahlten Betrag der Rechnung automatisch um den gelöschten Betrag korrigieren.
Ergebnis: Konsistenter Rechnungssaldo auch nach nachträglicher Korrektur von Zahlungseingängen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Finances/Payments/PaymentsBL.cs:38-78 - Begründung: Vollständige Rückbuchungslogik im Code
Prüfidee: Zahlungseingang zu Rechnung erfassen, Saldo prüfen, Zahlungseingang löschen, Saldo erneut prüfen
Tracelinks: SyRS-BILL-04, StRS-BILL-04
Konsolidierung: nein
Status: belegt
---
ID: SwRS-BILL-03
Titel: Gültigkeitsfilter für Aktionspreise in der Preismatrix
Ebene: SwRS
Typ: funktional
Akteur: Einkauf / Preispflege
Vorbedingung: Aktionspreis (Distributor-Sonderpreis) für Artikel wurde erfasst
Fakt: `PriceMatrixViewModel.GetPriceItemsFromArticleActionPrices` filtert Aktionspreise ausschließlich nach Gültigkeitsfenster: `EffectiveFrom.StartOfDay() <= DateTime.Now && EffectiveUntil >= DateTime.Now` (laut docs/reference/receipts/actionprice-system.md:312, im UI-Modul `PriceMatrixViewModel.cs`). Nur aktuell gültige Aktionspreise werden in der Preismatrix angezeigt.
Aussage: Das System soll in der Preisfindung nur zeitlich gültige Aktionspreise (aktuelles Datum zwischen Gültig-von/-bis) berücksichtigen.
Ergebnis: Verkäufer sehen ausschließlich aktuell gültige Sonderkonditionen bei der Preisfindung.
Belege:
- [SEKUNDÄR] docs/reference/receipts/actionprice-system.md:196-212,306-312 - Begründung: Dokumentierte Filterlogik mit Code-Referenz auf PriceMatrixViewModel.cs, jedoch nicht selbst im Quellcode gegengelesen
Prüfidee: Aktionspreis mit EffectiveUntil in der Vergangenheit anlegen, Preismatrix öffnen -> Preis darf nicht erscheinen
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; nicht im Quellcode direkt verifiziert (nur Dokumentation), daher SEKUNDÄR statt PRIMÄR
---
ID: SwRS-BILL-04
Titel: Fehlende serverseitige Validierung von Aktionspreisen (Gap)
Ebene: SwRS
Typ: Sicherheit / Datenintegrität
Akteur: Einkauf / Preispflege
Vorbedingung: Neuer Aktionspreis wird über den Dialog "Aktionspreis hinzufügen" erfasst
Fakt: Die Pflichtfeldprüfung (Distributor darf nicht leer sein; `EffectiveFrom` darf nicht nach `EffectiveUntil` liegen) ist ausschließlich in der WPF-ViewModel-Schicht implementiert (`AddActionPriceViewModel.cs:69-79`, `Ok()`-Methode mit MessageBox-Abbruch). Die Business-Logic-Schicht `ActionPriceBL.SaveOrUpdateActionPrice` (Zeilen 36-41) führt dagegen nur einen `Guard.NotNull`-Nullcheck durch, keine fachliche Validierung; auch über die REST-API (`SaveOrUpdateActionPrice`) ist kein serverseitiger Constraint ersichtlich.
Aussage: Das System soll die Pflichtfeld- und Plausibilitätsprüfung für Aktionspreise (Distributor vorhanden, gültiger Zeitraum) serverseitig (BL/API/DB) durchsetzen, nicht nur im WPF-Client.
Ergebnis: Verhindert, dass über die REST-API oder zukünftige Web-Clients ungültige Aktionspreise (leerer Distributor, invertierter Zeitraum) persistiert werden können. Wichtiger Befund für die Web-/SaaS-Neuimplementierung: bestehende Lücke nicht unreflektiert übernehmen, sondern serverseitig nachrüsten.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Warehousing/ArticleManagement/OpenDialog/ActionPrice/AddActionPriceViewModel.cs:69-79 - Begründung: Zeigt, dass die Validierung nur clientseitig erfolgt
- [PRIMÄR] src/backend/Centron.BL/Warehousing/ActionPriceBL.cs:36-41 - Begründung: Zeigt Fehlen jeglicher fachlicher Validierung in der Business-Logic-Schicht
Prüfidee: Aktionspreis direkt über REST-Endpoint `SaveOrUpdateActionPrice` mit leerem Distributor bzw. EffectiveFrom > EffectiveUntil senden -> prüfen ob Speicherung dennoch gelingt
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; Workaround (Validierung nur im Legacy-WPF-Client vorhanden, kein serverseitiger Constraint nachweisbar)
---
ID: SwRS-BILL-05
Titel: AnlageLog-Audit-Eintrag für Vertragsereignisse (AnlageArt=22)
Ebene: SwRS
Typ: Daten
Akteur: System (Audit-Log)
Vorbedingung: Vertrag wird angelegt, geändert, abgerechnet oder gekündigt
Fakt: Verträge protokollieren Ereignisse zentral über die Tabelle `AnlageLog` mit `AnlageArt = 22` (Contract-Identifier) und `AnlageI3D` als Verweis auf den Vertrag; dasselbe Muster (`AnlageI3D`+`AnlageArt`) wird für alle Belegtypen verwendet (z.B. 1=Angebot, 2=Auftrag, 4=Rechnung, 6=Gutschrift).
Aussage: Das System soll geschäftsrelevante Ereignisse an Verträgen (Erstellung, Änderung, Abrechnung, Kündigung) in einem zentralen, belegtypübergreifenden Audit-Log erfassen.
Ergebnis: Einheitliche, auswertbare Historie für Compliance- und Support-Zwecke über alle Belegtypen hinweg.
Belege:
- [SEKUNDÄR] docs/reference/receipts/contracts-backend.md:204-220 - Begründung: Dokumentiert Tabellenschema und Verwendung; korrespondierendes Enum/Konstantenwert (AnlageArt=22) nicht separat im Code verifiziert
Prüfidee: Vertragsänderung durchführen, AnlageLog-Eintrag mit AnlageArt=22 und korrektem AnlageI3D erwarten
Tracelinks: SyRS-BILL-18, StRS-BILL-04
Konsolidierung: nein
Status: belegt
---
ID: SwRS-BILL-06
Titel: Rechtebasierte Filterung in der belegtypübergreifenden Suche
Ebene: SwRS
Typ: Schnittstelle
Akteur: System (Belegsuche)
Vorbedingung: Anwenderin sucht über mehrere Belegtypen hinweg (inkl. Rechnungen, Verträge, Gutschriften)
Fakt: `ReceiptSearcher.SearchReceipts` (ReceiptSearcher.cs) iteriert über alle registrierten `ReceiptSearchConfiguration`-Implementierungen je Belegtyp, generiert dynamisch parametrisierte Raw-SQL-Statements (Timeout 5 Minuten) und prüft je Belegtyp konfigurierbare Rechte (`ShowRight`, `OnlyOwnRight`, `OnlyOwnBranchRight`); fehlende Rechte führen dazu, dass für diesen Belegtyp `null` zurückgegeben und er stillschweigend aus dem Suchergebnis ausgeschlossen wird.
Aussage: Das System soll bei der belegtypübergreifenden Suche serverseitig je Belegtyp und Benutzer prüfen, ob Zugriffsrechte bestehen, und Ergebnisse ohne Berechtigung nicht anzeigen.
Ergebnis: Konsistente Rechtedurchsetzung auch in der übergreifenden Belegsuche (z.B. Rechnungen, Verträge), keine Informationslecks über Belegtypgrenzen.
Belege:
- [PRIMÄR] docs/reference/receipts/receipt-search-architecture.md:154-190 (mit Code-Zitat aus ReceiptSearcher.CreateSqlStatementAndParameters) - Begründung: Dokumentation zitiert die tatsächliche Rechteprüfungslogik im Code direkt
Prüfidee: Benutzer ohne Vertragsrecht sucht belegtypübergreifend -> Verträge dürfen nicht im Ergebnis erscheinen
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,365 @@
ID: SyRS-BILL-01
Titel: Einheitliche Belegstatusmaschine (ReceiptState)
Ebene: SyRS
Typ: funktional
Akteur: System (Belegverwaltung)
Vorbedingung: Beleg (Angebot/Auftrag/Lieferschein/Rechnung/Vertrag/Gutschrift/Abholliste) existiert
Fakt: Alle Belegtypen teilen sich eine gemeinsame Statusmaschine `ReceiptState` mit exakt drei Zuständen: `Active` ("offen"), `Completed` ("abgeschlossen"), `Canceled` ("storniert"). Der Enum wird u.a. für Zahlungsstatus (Completed=bezahlt) und Stornostatus verwendet.
Aussage: Das System soll für alle Belegtypen einen einheitlichen, dreiwertigen Lebenszyklus-Status (offen/abgeschlossen/storniert) führen und konsistent für Status- und Zahlungslogik verwenden.
Ergebnis: Einheitliche, belegtypübergreifende Zustandslogik als Basis für Folgeprozesse (Storno, Zahlungsstatus, Reporting).
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 - Begründung: Enum-Definition mit deutschen Beschreibungen, direkter Code-Beleg
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:4942-4951 (UpdateReceiptIsPaid nutzt ReceiptState.Completed/Active für isPaid) - Begründung: Zeigt Wiederverwendung der Statusmaschine für Zahlungsstatus
Prüfidee: Alle Belegtypen (Angebot, Auftrag, Rechnung, Vertrag, Gutschrift) auf konsistente State-Werte in DB prüfen
Tracelinks: StRS-BILL-04
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-02
Titel: Rechnungsstorno als versionierte Belegrevision mit Vorbedingungskette
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Rechnung mit State != Canceled liegt vor
Fakt: `CancelInvoice` (ReceiptInvoiceBL.cs:143-206) prüft nacheinander: Recht `RIGHT_RECHNUNGSTORNIEREN`, State != Canceled, `IsCashAsset == false`, keine Weiterverarbeitung (`GetReceiptForwardedInto`), kein Buchhaltungsexport (`BookKeepingExportBL.IsReceiptExported`), bei Vertragsrechnung Prüfung auf letzte Rechnung des Vertrags (`IsLastContractInvoice`). Erst danach wird eine neue Version mit Menge=0 je Artikel-/Rabattposition erzeugt und State auf `Canceled` gesetzt.
Aussage: Das System soll eine Rechnungsstornierung als neue, versionierte Belegrevision mit auf Null gesetzten Mengen realisieren und dabei alle genannten Vorbedingungen hart erzwingen.
Ergebnis: Nachvollziehbare, versionierte Stornohistorie statt Löschung; harte Sperren bei bereits verarbeiteten Belegen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:157-186 - Begründung: Exakte Prüfkette und Storno-Mechanik (Menge=0, neue Version, State=Canceled) im Code
Prüfidee: Stornierung einer Barrechnung (IsCashAsset=true) versuchen -> Fehlermeldung "...da es sich um eine Barrechnung handelt." erwarten
Tracelinks: StRS-BILL-04
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-03
Titel: Festschreibung (IsFixed) sperrt Rechnungsänderungen
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Rechnung ist noch nicht festgeschrieben (IsFixed=false)
Fakt: `FixInvoice` setzt per Raw-SQL `UPDATE RechKopf SET IsFixed = 1 WHERE I3D = @I3D` und protokolliert den Vorgang im Log (`ReceiptLogKind.FixedState`). `CheckIfInvoiceIsFixed` liefert bei bereits festgeschriebener Rechnung eine Warnung "Die Rechnung ist festgeschrieben. Änderungen nicht möglich."
Aussage: Das System soll eine Funktion zur Festschreibung von Rechnungen bereitstellen, die weitere inhaltliche Änderungen an der Rechnung nach Festschreibung verhindert.
Ergebnis: Nachträgliche Manipulation festgeschriebener (i.d.R. bereits gebuchter/exportierter) Rechnungen wird verhindert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:86-141 (FixInvoice) - Begründung: Direkte SQL-Persistenz des Fixier-Flags plus Audit-Log-Eintrag
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:273-291 (CheckIfInvoiceIsFixed) - Begründung: Exakte Warnmeldung im Code
Prüfidee: Rechnung festschreiben, danach Änderungsversuch an Positionen -> erwartete Blockade/Warnung
Tracelinks: StRS-BILL-04
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-04
Titel: Zahlungsstatus-Update mit Storno-Sperre und Concurrency-Control
Ebene: SyRS
Typ: funktional
Akteur: Zahlungseingang / Buchhaltung
Vorbedingung: Beleg unterstützt Zahlungsinformationen (`IReceiptWithPayment` oder Gutschrift)
Fakt: `ReceiptBL.UpdateReceiptIsPaid` (Zeilen 4902-4971) verweigert die Statusänderung bei stornierten Belegen ("...wurde stoniert und kann daher nicht als bezahlt oder nicht bezahlt eingestellt werden."), prüft optimistisches Locking via `ConcurrencyControlGuid` und mappt `isPaid=true/false` auf `ReceiptState.Completed/Active`.
Aussage: Das System soll den Zahlungsstatus eines Belegs nur bei nicht-stornierten Belegen und unter Berücksichtigung von Optimistic-Concurrency-Control ändern lassen.
Ergebnis: Konsistenter Zahlungsstatus, keine widersprüchlichen Parallel-Änderungen, keine Zahlungsbuchung auf stornierten Belegen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:4936-4951 - Begründung: Durchgesetzte Prüfungen inkl. exakter Fehlermeldung im Code
Prüfidee: Stornierte Rechnung als "bezahlt" markieren -> erwartete Fehlermeldung
Tracelinks: StRS-BILL-04, SwRS-BILL-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-05
Titel: Race-Condition-sichere Belegnummernvergabe
Ebene: SyRS
Typ: funktional
Akteur: System (Belegnummernkreis)
Vorbedingung: Neuer Beleg wird angelegt und benötigt eine Belegnummer
Fakt: `NumberGroupBL.GetNextNumber`/`FindNextNumber` (Zeilen 50-134) ermittelt die nächste freie Nummer durch iterative Prüfung gegen die Zieltabelle (SELECT COUNT), inkrementiert um `Interval`, und persistiert die neue "Current"-Nummer nur, wenn ein optimistischer Update (`WHERE I3D = @I3D AND Current = @altCurrent`) genau 1 Zeile ändert; andernfalls wird die Schleife wiederholt (Race-Condition-Schutz bei paralleler Nummernvergabe).
Aussage: Das System soll Belegnummern eindeutig, kollisionsfrei und race-condition-sicher unter gleichzeitigem Zugriff mehrerer Benutzer vergeben.
Ergebnis: Keine doppelten Belegnummern auch bei paralleler Rechnungserstellung durch mehrere Benutzer/Filialen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs:62-134 - Begründung: Konkrete Optimistic-Locking-Implementierung mit Retry-Schleife im Code
Prüfidee: Lasttest mit parallelen Rechnungsanlagen; auf doppelte Nummern in RechKopf prüfen
Tracelinks: StRS-BILL-04
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-06
Titel: Automatische Formatwahl ZUGFeRD Comfort vs. XRechnung
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Rechnungs-/Gutschriftexport wird angestoßen, optional mit Leitweg-ID
Fakt: `InvoiceZugferdBL.GenerateZugferdFile` (Zeilen 124-156) wählt `ZugferdFileKind.Comfort`, wenn `leitwegID` leer/whitespace ist, sonst `ZugferdFileKind.XInvoice`. Ebenso bestimmt `CreateZugferdConformPdfDocument` (Zeile 193) das PDF-Konformitätslevel (`EN16931` vs. `XRechnung`) anhand desselben Kriteriums.
Aussage: Das System soll automatisch zwischen ZUGFeRD-Comfort- und XRechnung-Format wechseln, gesteuert einzig durch das Vorhandensein einer Leitweg-ID im Beleg.
Ergebnis: Für Rechnungen an öffentliche Auftraggeber wird automatisch das gesetzlich vorgeschriebene XRechnung-Format erzeugt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156,167-193 - Begründung: Direkte Verzweigungslogik im Code
Prüfidee: Export mit und ohne Leitweg-ID vergleichen (Dateikennung/Namespace im XML)
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-07
Titel: Automatische Steuerkategorie-Ermittlung für E-Rechnung
Ebene: SyRS
Typ: funktional
Akteur: System (Steuerlogik E-Rechnung)
Vorbedingung: Rechnungsposition mit Steuersatz, Reverse-Charge-Flag und Handelsart (Inland/EU/Export) liegt vor
Fakt: `InvoiceZugferdBL.GetTaxCategoryCode` (Zeilen 2092-2107) liefert deterministisch: "AE" bei Reverse Charge, sonst bei Steuersatz 0%: "E" (Inland), "K" (EU), "G" (Export außerhalb EU); sonst "S" (Standard).
Aussage: Das System soll die UN/CEFACT-Steuerkategorie jeder Rechnungsposition automatisiert aus Steuersatz, Reverse-Charge-Kennzeichen und Handelsart ableiten.
Ergebnis: Korrekte, normkonforme Steuerkategorien im E-Rechnungs-XML ohne manuelle Zuordnung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2092-2107 - Begründung: Vollständige, deterministische Entscheidungslogik im Code nachgewiesen
Prüfidee: Testfälle für alle vier Kombinationen (Reverse Charge, Inland 0%, EU 0%, Export 0%, Standard) durchspielen
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-08
Titel: Automatische Steuerbefreiungstexte für E-Rechnung
Ebene: SyRS
Typ: funktional
Akteur: System (Steuerlogik E-Rechnung)
Vorbedingung: Steuerkategorie einer Position wurde ermittelt (siehe SyRS-BILL-07)
Fakt: `GetTaxExemptionReason` (InvoiceZugferdBL.cs:2109-2122) liefert feste deutsche Begründungstexte: Reverse Charge -> "Steuerschuldnerschaft des Leistungsempfängers gem. §13B Abs 2 Nr. 10 UStG.", Inland 0% -> "Steuerfrei", EU 0% -> "Kein Ausweis der Umsatzsteuer bei innergemeinschaftlichen Lieferungen", Export 0% -> "Steuer nicht erhoben aufgrund von Export außerhalb der EU".
Aussage: Das System soll bei steuerbefreiten oder Reverse-Charge-Positionen automatisch den vorgeschriebenen Befreiungstext im E-Rechnungs-XML hinterlegen.
Ergebnis: E-Rechnungen erfüllen die formalen Anforderungen an Steuerbefreiungshinweise (§14 UStG / EN16931).
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2109-2122 - Begründung: Exakte Texte im Code
Prüfidee: Reverse-Charge-Rechnung exportieren, XML auf ExemptionReason-Text prüfen
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-09
Titel: Betrags-Toleranzprüfung beim E-Rechnungsexport
Ebene: SyRS
Typ: nicht-funktional (Datenqualität)
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Summe der Positionsnettobeträge weicht vom Rechnungskopf-Nettobetrag ab
Fakt: Konstante `AMOUNT_DIFFERENCE_TOLERANCE = 3.0m` (InvoiceZugferdBL.cs:64); bei Abweichung < Toleranz wird eine Warnung geloggt und der Kopfbetrag automatisch korrigiert ("ZUGFeRD: Bei der Rechnung weicht das Netto der Rechnung ... ab. Bitte prüfen Sie die Rechnung."), bei Abweichung >= Toleranz wird der Export mit `Result.AsError` abgebrochen (Zeilen 1033-1043).
Aussage: Das System soll beim E-Rechnungsexport die Konsistenz zwischen Kopf- und Positionssummen prüfen und bei Abweichungen über 3,00 Euro den Export verweigern statt eine fehlerhafte Rechnung zu versenden.
Ergebnis: Verhindert Versand rechnerisch inkonsistenter E-Rechnungen; kleinere Rundungsdifferenzen werden toleriert und automatisch korrigiert.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:64,1033-1043 - Begründung: Hartkodierte Toleranzgrenze und Fehlerpfad im Code
Prüfidee: Rechnung mit manuell verändertem Kopfbetrag (Abweichung > 3€) exportieren -> Export muss fehlschlagen
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-10
Titel: Behandlung negativer Preise im E-Rechnungsexport
Ebene: SyRS
Typ: funktional
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Rechnungs-/Gutschriftposition mit negativem Nettopreis liegt vor
Fakt: ZUGFeRD/XRechnung unterstützt keine negativen Einzelpreise; c-entron macht laut Code-Kommentaren und Dokumentation den Preis positiv und negiert stattdessen die Menge, sodass die Positionssumme unverändert bleibt (`InvoiceZugferdBL.cs`, Kommentare Zeilen 994-999 zu Vorzeichenbehandlung bei Rabatten; Bestätigung in docs/reference/zugferd-field-mapping.md Abschnitt "Negative Prices").
Aussage: Das System soll negative Einzelpreise beim E-Rechnungsexport durch Vorzeichenumkehr der Menge (statt des Preises) abbilden, um EN16931-Konformität zu wahren.
Ergebnis: Rabatt-/Korrekturpositionen mit negativem Preis werden normkonform exportiert.
Belege:
- [SEKUNDÄR] docs/reference/zugferd-field-mapping.md:272-275,355-359 - Begründung: Ausführliche Beschreibung der Regel, jedoch nur indirekt über Code-Kommentare (Zeilen 994-999) im Quellcode rückbestätigt
- [KONTEXT] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:994-999 - Begründung: Verwandte Vorzeichenlogik für Rabatte im selben Modul bestätigt das Muster
Prüfidee: Gutschriftposition mit negativem Preis exportieren, XML auf positiven ChargeAmount und negierte BilledQuantity prüfen
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-11
Titel: Titelpositionen im E-Rechnungsexport (nur eingeklappt, einheitlicher Steuersatz)
Ebene: SyRS
Typ: funktional
Akteur: System (E-Rechnungs-Export)
Vorbedingung: Rechnung enthält Titelpositionen mit untergeordneten Positionen unterschiedlicher Steuersätze
Fakt: Beim Aggregieren von Titelpositionen wird bei unterschiedlichen Steuersätzen der untergeordneten Positionen der Export mit Fehlermeldung abgebrochen: "In der Titelposition '{Text}' kommen unterschiedliche Mehrwertsteuern vor (...), dass wird nicht unterstützt! Bitte klappen Sie die Titelposition auf, oder splitten Sie die Positionen..." (InvoiceZugferdBL.cs:950-952). Ausgeklappte Titelpositionen werden generell nicht unterstützt (nur eingeklappte/kollabierte Titelpositionen mit Menge=1 werden exportiert).
Aussage: Das System soll beim E-Rechnungsexport gemischte Steuersätze innerhalb einer eingeklappten Titelposition erkennen und den Export mit einer handlungsleitenden Fehlermeldung verweigern.
Ergebnis: Verhindert steuerlich inkorrekte E-Rechnungen bei Titelpositionen; Anwenderin erhält konkrete Lösungshinweise.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:938-953 - Begründung: Exakte Fehlermeldung und Abbruchlogik im Code
Prüfidee: Titelposition mit Kindpositionen zu 19% und 7% MwSt. exportieren -> erwarteter Abbruch mit obiger Meldung
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-12
Titel: Gutschrift-Referenz auf eindeutige Ursprungsrechnung
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung
Vorbedingung: Gutschrift wurde aus einer oder mehreren Rechnungen erzeugt
Fakt: Beim E-Rechnungs-Export einer Gutschrift wird nur dann ein Verweis auf die Ursprungsrechnung (`InvoiceReferencedDocument`) gesetzt, wenn genau eine eindeutige Ursprungsrechnung ermittelt werden kann (`items.Count == 1`, ermittelt über `OriginKind == Invoice` und `DistinctBy(OriginReceiptI3D)`); bei mehreren oder keiner Ursprungsrechnung bleibt das Feld leer.
Aussage: Das System soll bei Gutschriften automatisch auf die zugehörige Ursprungsrechnung im E-Rechnungs-XML verweisen, sofern die Zuordnung eindeutig ist.
Ergebnis: Nachvollziehbarkeit von Gutschriften gegenüber Rechnungen für Kunden/Finanzamt, ohne fehlerhafte Mehrfachreferenzen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:803-811,1873-1878 - Begründung: Eindeutigkeitsprüfung und bedingte Referenzsetzung im Code
Prüfidee: Sammelgutschrift zu zwei Rechnungen exportieren -> InvoiceReferencedDocument darf nicht gesetzt sein
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-13
Titel: RMM-Service-Ausfall bricht automatische Vertragsabrechnung ab
Ebene: SyRS
Typ: funktional
Akteur: System (Contract-Billing / RMM-Integration)
Vorbedingung: Vertrag ist für RMM-Abrechnung konfiguriert (`WhetherRMM=true`) und automatische Rechnungserstellung wird ausgeführt
Fakt: `CheckRMMArticle` (AutomaticFacturaWebServiceBL.cs:721-802) ruft für den Abrechnungszeitraum Nutzungsdaten des externen RMM-Systems (Riverbird, via `RiverConnectionBL.GetContractBillingAmounts`) ab. Ist der RMM-Service nicht erreichbar UND werden RMM-Artikel im Vertrag erwartet, wird eine `RMMServiceUnavailableException` mit Fehlermeldung "Die Rechnung kann nicht erstellt werden. {Message}" geworfen und die gesamte Rechnungserstellung abgebrochen.
Aussage: Das System soll bei RMM-basierter Vertragsabrechnung die automatische Rechnungserstellung abbrechen, wenn die externe Nutzungsdatenquelle nicht erreichbar ist, um Rechnungen mit unvollständigen Nutzungsdaten zu verhindern.
Ergebnis: Kunden werden nicht auf Basis unvollständiger/fehlerhafter Nutzungsdaten fakturiert; Fehlerprotokollierung ermöglicht Nachverfolgung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:790-802,2412-2415 (Exception-Definition und Wurf-Stelle) - Begründung: Vollständige Fehlerbehandlungslogik direkt im Code
- [SEKUNDÄR] docs/reference/receipts/Contract-Billing-RMM-Article-Logic.md:45-52 - Begründung: Bestätigt fachlichen Zweck der Regel
Prüfidee: RMM-Service (Riverbird) für Testzeitraum offline simulieren, automatische Vertragsabrechnung anstoßen -> Abbruch mit Exception erwarten
Tracelinks: StRS-BILL-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-14
Titel: Über-/Unterbuchungsdeckelung bei RMM-Vertragsartikeln
Ebene: SyRS
Typ: funktional
Akteur: System (Contract-Billing)
Vorbedingung: RMM-Nutzungsmenge für einen Vertragsartikel wurde ermittelt, Vertragsartikel hat konfigurierte Kontingentmenge (`ContractAmount`)
Fakt: `ContractArticleReferenzes.CalculateContractBillingAmount(decimal riverbirdAmount)` (Entities/.../ContractArticleReferenzes.cs:27-39): Sind sowohl `ConsiderOverbooking` als auch `ConsiderUnderbooking` gesetzt, wird immer die feste `ContractAmount` abgerechnet; ist nur `ConsiderOverbooking` gesetzt und die Ist-Menge übersteigt die Kontingentmenge, wird auf `ContractAmount` gedeckelt; ist nur `ConsiderUnderbooking` gesetzt und die Ist-Menge liegt darunter, wird ebenfalls auf `ContractAmount` gedeckelt; ansonsten wird die tatsächliche RMM-Menge abgerechnet.
Aussage: Das System soll die abzurechnende Menge eines RMM-Vertragsartikels regelbasiert aus Ist-Nutzung und konfigurierbarer Über-/Unterbuchungsdeckelung ableiten.
Ergebnis: Kontrollierte Abrechnung bei schwankender Nutzung (z.B. Lizenzverträge mit Mindest-/Höchstmenge).
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/CustomerAssets/Contracts/ContractArticleReferenzes.cs:27-39 - Begründung: Vollständige, deterministische Berechnungsmethode im Code
Prüfidee: Testfälle mit ConsiderOverbooking/Underbooking-Kombinationen und Ist-Mengen über/unter ContractAmount durchspielen
Tracelinks: StRS-BILL-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-15
Titel: Kontingent-Saldo-Fortschreibung bei Rechnung/Gutschrift
Ebene: SyRS
Typ: funktional
Akteur: System (Vertrags-Kontingentverwaltung)
Vorbedingung: Rechnung oder Gutschrift mit Bezug zu einem Vertrag mit Kontingent (Geld- oder Mengenkontingent) wird gebucht
Fakt: `ReceiptContractBL.ContractContingentBalanceCalculation` (Zeilen 149-221) berechnet den Kontingentwert entweder als Nettobetrag (`ContingentKinds.Money`) oder als Menge (inkl. Zeitumrechnung via `CalculateContingentWithRecalculationArticle`); bei Gutschriften (`CentronObjectKindNumeric.CreditVoucherClass`) wird der Wert mit `-1` multipliziert (Zeilen 188-190, 194-196), d.h. Gutschriften reduzieren den Kontingentverbrauch. Das Ergebnis wird in der Zuordnungstabelle `VertragRechKopfZuordnung` persistiert.
Aussage: Das System soll bei jeder vertragsbezogenen Rechnung den Kontingentverbrauch erhöhen und bei jeder vertragsbezogenen Gutschrift den Kontingentverbrauch entsprechend wieder verringern.
Ergebnis: Korrekter, buchungsgenauer Kontingentsaldo je Vertrag über Rechnungs- und Gutschriftbuchungen hinweg.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs:149-221 - Begründung: Vollständige Berechnungs- und Vorzeichenlogik im Code
Prüfidee: Vertragsrechnung buchen, danach zugehörige Gutschrift buchen, Kontingentsaldo vor/nach vergleichen
Tracelinks: StRS-BILL-02
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-16
Titel: Mehrstufiges, konfigurierbares Mahngebühren-/Fristenmodell
Ebene: SyRS
Typ: Daten
Akteur: Finanzbuchhaltung (Administration)
Vorbedingung: Mahnlauf wird konfiguriert
Fakt: Anwendungseinstellungen `DunningLevel1Fees=10127`, `DunningLevel2Fees=10128`, `DunningLevel3Fees=10129` (ApplicationSettingID.cs:855-857) sowie je-Kunde-Felder `DunningLetterAfterDays1-3` und `LockOrderAfterDunningLevel` definieren gestaffelte Mahngebühren und Fristen für bis zu drei Mahnstufen.
Aussage: Das System soll bis zu drei konfigurierbare Mahnstufen mit jeweils eigener Gebühr, Frist (Tage nach Fälligkeit) und optionaler Beleg-Sperre unterstützen.
Ergebnis: Flexibles, mehrstufiges Mahnwesen je Mandant konfigurierbar.
Belege:
- [PRIMÄR] src/backend/Centron.Interfaces/Administration/Settings/ApplicationSettingID.cs:855-857 - Begründung: Konkrete Einstellungs-IDs im Code
- [PRIMÄR] src/backend/Centron.DAO/Repositories/Accounts/AccountRepository.cs:660-663 (Mapping MahnungNachTagen/2/3, AuftragsperreNachMahnung) - Begründung: Bestätigt Persistenzfelder je Kunde
Prüfidee: Drei Mahnstufen mit unterschiedlichen Gebühren konfigurieren, Mahnlauf für überfälligen Kunden ausführen, erzeugte Mahngebühr prüfen
Tracelinks: StRS-BILL-03, SwRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-17
Titel: Hierarchische Bankauswahl für E-Rechnungsexport
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (E-Rechnungs-Export, Zahlungsdaten)
Vorbedingung: Rechnung wird für ZUGFeRD/XRechnung exportiert und benötigt eine Bankverbindung
Fakt: Die Bankauswahl für den E-Rechnungs-Export erfolgt hierarchisch: zunächst über die Einstellung `ReceiptInvoiceSettings.UseMandatorBankForInvoice` (Bank1-4), die pro Kunde über `AccountCustomer.MandatorBank` überschrieben werden kann; die konkreten IBAN/BIC-Daten stammen aus den Mandantenstammdaten (`Mandator.Bank1Iban/Bic` ... `Bank4Iban/Bic`). Bei SEPA-Lastschrift wird stattdessen die Kunden-IBAN aus `BankAccount.Iban` sowie die SEPA-Mandatsreferenz aus `BankAccount.AuthorizationNumber` verwendet.
Aussage: Das System soll die für den E-Rechnungsexport verwendete Bankverbindung nach einer festen Priorität (kundenspezifische Einstellung vor globaler Mandanteneinstellung) auflösen und zwischen Überweisung und SEPA-Lastschrift unterscheiden.
Ergebnis: Korrekte Zahlungsinformationen je nach Zahlungsart und Kundeneinstellung im E-Rechnungs-XML.
Belege:
- [SEKUNDÄR] docs/reference/zugferd-field-mapping.md:157-160 - Begründung: Dokumentierte Bankauswahl-Hierarchie mit Verweis auf Datenquellen; Umsetzung im Code (InvoiceZugferdBL.cs Settlement-Bereich) nicht Zeile-für-Zeile nachgelesen
Prüfidee: Kunde mit abweichender MandatorBank-Einstellung anlegen, Rechnung exportieren, verwendete IBAN/BIC im XML mit Erwartungswert vergleichen
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-18
Titel: Vollständige Versionshistorie (Audit-Trail) für alle Belegtypen
Ebene: SyRS
Typ: Daten
Akteur: System (Belegarchitektur)
Vorbedingung: Ein Beleg (Angebot/Auftrag/Lieferschein/Rechnung/Vertrag/Gutschrift/Abholliste) wird gespeichert oder verändert
Fakt: Jede Belegänderung wird über `AssetHeadDAO.SaveAssetVersion` als vollständige 1:1-Kopie in eine Versionstabelle geschrieben (z.B. `VertragKopfVersions`, `RechKopfVersions`); Versionstabellen müssen laut Doku und Code-Konvention exakt dieselben Spalten wie die Basistabelle enthalten (zzgl. `OriginalI3D`/`KopfVersionsI3D`), sonst schlägt die Versionierung zur Laufzeit fehl (`DoGetFieldList()`).
Aussage: Das System soll für alle Belegtypen eine vollständige, spaltengenaue Versionshistorie (Audit-Trail) führen, die jede Änderung als eigenständige, abfragbare Version persistiert.
Ergebnis: Lückenlose Nachvollziehbarkeit aller Belegänderungen inkl. Rollback-Fähigkeit; Grundlage für Compliance-Anforderungen (GoBD).
Belege:
- [PRIMÄR] docs/reference/receipts/receipts-backend-architecture.md:147-204 - Begründung: Detaillierte Beschreibung der 1:1-Versionierungsmechanik inkl. SQL-Beispiel; als architekturelle Konvention durchgängig in den Datenbank-Skripten (Kopf-/Pos-Versions-Tabellen) sichtbar
- [KONTEXT] src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs (Nutzung versionierter Verträge über Contract-Version-Views) - Begründung: Bestätigt praktische Nutzung des Versionierungsmusters bei Verträgen
Prüfidee: Vertrag mehrfach ändern, VertragKopfVersions auf lückenlose OriginalI3D-Kette prüfen
Tracelinks: StRS-BILL-04, SwRS-BILL-05
Konsolidierung: nein
Status: belegt
---
ID: SyRS-BILL-19
Titel: Standard-Steuersatz 19% bei leeren Titelpositionen
Ebene: SyRS
Typ: funktional
Akteur: System (Preisfindung Titelpositionen)
Vorbedingung: E-Rechnungsexport einer Rechnung mit Titelposition ohne untergeordnete Positionen
Fakt: Für Titelpositionen ohne Kindpositionen wird beim ZUGFeRD-Export standardmäßig ein Steuersatz von 19% angenommen (laut docs/reference/zugferd-feldzuordnung-anwender.md:331 "Standard-Steuersatz: Wenn eine Titelposition keine untergeordneten Positionen hat, wird 19% verwendet").
Aussage: Das System soll für leere Titelpositionen beim E-Rechnungsexport einen definierten Standard-Steuersatz (19%) ansetzen, statt den Export mit unbestimmtem Steuersatz zu blockieren.
Ergebnis: Robuster Export auch bei untypischen/leeren Titelpositionen, aber mit Risiko falscher Steuerangabe bei abweichendem tatsächlichem Steuersatz.
Belege:
- [SEKUNDÄR] docs/reference/zugferd-feldzuordnung-anwender.md:331 und docs/reference/zugferd-field-mapping.md:365 - Begründung: In zwei unabhängigen Dokumentationsartefakten übereinstimmend beschrieben, jedoch nicht im Quellcode zeilengenau verifiziert
Prüfidee: Leere Titelposition (keine Kindpositionen) in Rechnung anlegen und exportieren, resultierenden Steuersatz im XML prüfen
Tracelinks: StRS-BILL-01
Konsolidierung: nein
Status: belegt; [HYPOTHESE]-nah, da nur SEKUNDÄR belegt (Code-Stelle nicht gegengelesen) - Risikobereich Steuerberechnung, vor Übernahme in Web-Neuimplementierung im Code verifizieren
---
ID: SyRS-BILL-20
Titel: Stornobeschränkung auf jeweils letzte Vertragsrechnung
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung / Vertragsverwaltung
Vorbedingung: Vertragsrechnung soll storniert werden
Fakt: `ReceiptInvoiceBL.CancelInvoice` erlaubt die Stornierung einer Vertragsrechnung nur, wenn sie laut `IsLastContractInvoice` die aktuell für den Vertrag zuletzt erstellte Rechnung ist (Abgleich über `ReceiptContractBL.GetContractInfos(...).CurrentInvoiceI3D`); andernfalls Fehlermeldung: "Die Rechnung kann nicht storniert werden, da Sie nicht die letzte für den Vertrag erstellte Rechnung ist. Sie können nur jeweils die zuletzt für einen Vertrag erstellte Rechnung stornieren."
Aussage: Das System soll bei Vertragsrechnungen die Stornierung auf die jeweils zuletzt erstellte Rechnung je Vertrag beschränken, um die Konsistenz der Vertragsabrechnungshistorie (Kontingente, Zuordnungen) zu erhalten.
Ergebnis: Verhindert inkonsistente Kontingent-/Zuordnungshistorie bei Verträgen durch Storno "mittendrin liegender" Rechnungen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:170-172,236-251 - Begründung: Exakte Prüf- und Fehlermeldungslogik im Code
Prüfidee: Vertrag mit zwei Abrechnungsperioden abrechnen, Storno der ersten (nicht letzten) Rechnung versuchen -> erwartete Fehlermeldung
Tracelinks: StRS-BILL-04
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,24 @@
| StRS-BILL-01 | SyRS-BILL-06 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:124-156 |
| StRS-BILL-01 | SyRS-BILL-07 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2092-2107 |
| StRS-BILL-01 | SyRS-BILL-08 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:2109-2122 |
| StRS-BILL-01 | SyRS-BILL-09 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:64,1033-1043 |
| StRS-BILL-01 | SyRS-BILL-10 | | docs/reference/zugferd-field-mapping.md:355-359 (nur SEKUNDÄR, kein Primärbeleg vorhanden) |
| StRS-BILL-01 | SyRS-BILL-11 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:938-953 |
| StRS-BILL-01 | SyRS-BILL-12 | | src/backend/Centron.BL/DataExchange/EDI/SaleInvoices/InvoiceZugferdBL.cs:803-811,1873-1878 |
| StRS-BILL-01 | SyRS-BILL-17 | | docs/reference/zugferd-field-mapping.md:157-160 (nur SEKUNDÄR, kein Primärbeleg vorhanden) |
| StRS-BILL-01 | SyRS-BILL-19 | | docs/reference/zugferd-feldzuordnung-anwender.md:331 (nur SEKUNDÄR, kein Primärbeleg vorhanden) |
| StRS-BILL-02 | SyRS-BILL-13 | | src/backend/Centron.BL/WebServices/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaWebServiceBL.cs:790-802,2412-2415 |
| StRS-BILL-02 | SyRS-BILL-14 | | src/backend/Centron.Entities/Entities/Sales/CustomerAssets/Contracts/ContractArticleReferenzes.cs:27-39 |
| StRS-BILL-02 | SyRS-BILL-15 | | src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs:149-221 |
| StRS-BILL-03 | SyRS-BILL-16 | SwRS-BILL-01 | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:10194-10219 |
| StRS-BILL-04 | SyRS-BILL-01 | | src/backend/Centron.Interfaces/Sales/Receipts/ReceiptState.cs:6-14 |
| StRS-BILL-04 | SyRS-BILL-02 | | src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:157-186 |
| StRS-BILL-04 | SyRS-BILL-03 | | src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:86-141 |
| StRS-BILL-04 | SyRS-BILL-04 | SwRS-BILL-02 | src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs:4936-4951 |
| StRS-BILL-04 | SyRS-BILL-05 | | src/backend/Centron.BL/Administration/Company/NumberGroupBL.cs:62-134 |
| StRS-BILL-04 | SyRS-BILL-18 | SwRS-BILL-05 | docs/reference/receipts/receipts-backend-architecture.md:147-204 |
| StRS-BILL-04 | SyRS-BILL-20 | | src/backend/Centron.BL/Sales/Receipts/Invoices/ReceiptInvoiceBL.cs:170-172,236-251 |
| | | SwRS-BILL-03 | docs/reference/receipts/actionprice-system.md:196-212,306-312 |
| | | SwRS-BILL-04 | src/centron/Centron.WPF.UI/Modules/Warehousing/ArticleManagement/OpenDialog/ActionPrice/AddActionPriceViewModel.cs:69-79 |
| | | SwRS-BILL-06 | docs/reference/receipts/receipt-search-architecture.md:154-190 |
@@ -0,0 +1,16 @@
- **I3D**: Primärschlüssel-/Nummernfeld-Konvention der Centron-Datenbank; dient in nahezu allen Entitäten (Kunde, Adresse, Ansprechpartner, Mitarbeiter, Lieferant) als technischer und oft auch fachlich sichtbarer Identifikator (z. B. `CustomerNumber = I3D`).
- **Matchcode**: Kurzbezeichnung/Suchbegriff eines Kunden, der zusätzlich zum Namen für die Freitextsuche verwendet wird.
- **Standardadresse (DefaultCustomer)**: Die als Vorgabe markierte Adresse eines Kunden; pro Kunde ist genau eine Adresse als Standardadresse zulässig.
- **DefaultCreditor**: Analoges Konzept zur Standardadresse, jedoch für Lieferanten (Kreditoren); markiert die Standard-Lieferantenadresse.
- **Mandant (Mandator)**: Rechtlich/organisatorisch abgegrenzte Einheit innerhalb des Systems, der u. a. ein Standardland zugeordnet ist.
- **Kundenherkunft (CustomerAncestry)**: Stammdaten-Klassifikationswert, der die Herkunft/Quelle eines Kunden beschreibt (z. B. Akquisekanal); wird über `Customer.CustomerOriginI3D` referenziert.
- **USt-IdNr. (Umsatzsteuer-Identifikationsnummer)**: Steuerliche Kennung eines Geschäftspartners für innergemeinschaftliche Geschäfte; im System an mehreren Stellen redundant geführt (siehe SwRS-CRM-07).
- **IBAN-Prüfsummenverfahren (Modulo 97)**: Algorithmus nach ISO 7064 zur Erkennung von Tippfehlern in einer IBAN; im System nur im WPF-Client implementiert (siehe SyRS-CRM-09).
- **DSGVO-Löschung (Anonymisierung)**: Prozess, bei dem personenbezogene Daten einer Kontaktperson auf Anfrage entfernt/überschrieben werden, ohne den Datensatz technisch vollständig zu löschen (Soft-Anonymisierung mit Audit-Trail); siehe StRS-CRM-02.
- **AppUser vs. Employee**: `Employee` bildet die Personal-Stammdaten ab (Mitarbeiter als Person), `AppUser` das zugehörige technische Login-/Benutzerkonto für die Anwendung; beide Entitäten führen eigene, nicht deckungsgleiche "aktiv"-Konzepte.
- **WebAccount**: Kundenseitiger Web-Portal-Zugang (z. B. für Webshop/Self-Service), technisch getrennt von internen `AppUser`-Konten, aber im selben Login-Namensraum eindeutigkeitsgeprüft.
- **RFID-Token**: Verschlüsselt gespeicherte Kennung eines physischen Transponders (z. B. für Zutritts-/Zeiterfassung), einem Mitarbeiter zugeordnet.
- **Sentinel-Datum (1900-01-01)**: Im Legacy-Datenmodell verwendeter technischer Ersatzwert für "kein Datum gesetzt" bei `LeavingDate`, anstelle von NULL.
- **State/Locked**: Zwei getrennte Felder zur Steuerung der Nutzbarkeit eines Kunden – `State` (aktiv/inaktiv als Ganzzahl) und `Locked` (boolesches Sperr-Flag); beide müssen für "aktiv nutzbar" positiv sein.
- **Adviser1I3D…Adviser6I3D ("Betreuer")**: Kundenbezogene Zuordnung mehrerer Mitarbeiterrollen (Innendienst, Außendienst, Techniker 1/2, zwei weitere unbenannte Rollen).
@@ -0,0 +1,9 @@
- **StRS-CRM-01** (Statusmodell für Geschäftspartner): Ob Lieferanten-Sperre über ein anderes Feld/Modul realisiert wird – im gesichteten `Supplier`-Entity fehlt ein zu `Customer.Locked` äquivalentes Feld.
- **StRS-CRM-04** (Dubletten-Erkennung und Zusammenführung von Geschäftspartnern): Negativbefund (keine Dubletten-/Merge-Logik gefunden) beruht auf gezielter Grep-Suche über einen begrenzten Verzeichnisbereich; nicht abschließend geprüft, ob Logik in einem nicht durchsuchten Modul oder externen Tool existiert.
- **SyRS-CRM-07** (Rechtebeschränkung Kundenzugriff): Ob `RIGHT_KUNDENSTAMM` und `SEARCH_CUSTOMER` bewusst unterschiedliche Berechtigungsstufen abbilden oder ein historisches Duplikat sind.
- **SwRS-CRM-07** (Redundante USt-IdNr. ohne Formatvalidierung): Welches der drei redundanten Felder (`Address.AdressSalesTaxIdentificationNumber`, `CustomerFinanceInfo.SalesTaxIdentificationNumber`, `Customer.VATNotActive`) tatsächlich führend ist und ob eine Formatvalidierung an anderer, hier nicht durchsuchter Stelle existiert.
- **SwRS-CRM-10** (Fehlende Duplikatsprüfung bei RFID-Tokens): Ob Eindeutigkeit von `RfidTokenEncrypted` ggf. per DB-Unique-Index sichergestellt ist – DAO-/Mapping-Definitionen wurden für dieses Cluster nicht vollständig durchsucht.
- **SwRS-CRM-11** (Kundenbetreuerrollen (Adviser1-6)): Fachliche Bezeichnung/Verwendung von `Adviser5I3D`/`Adviser6I3D` ist im gesichteten Code nicht dokumentiert.
- **SwRS-CRM-12** (Kundenindividuelle Pflichtangaben-Flags): Ob und wie `PurchaseOrderNumberRequiered`/`ProjNrNeeded`/`ProductionConfigurationRequiring` tatsächlich in der Auftragserfassung ausgewertet/durchgesetzt werden, wurde außerhalb dieses Clusters nicht verifiziert.
@@ -0,0 +1,75 @@
ID: StRS-CRM-01
Titel: Statusmodell für Geschäftspartner
Ebene: StRS
Typ: Daten
Akteur: Vertrieb, Buchhaltung
Vorbedingung: -
Fakt: Der Kundenstatus wird über zwei getrennte, unabhängig setzbare Attribute abgebildet: `State` (int, wirkt wie "aktiv/inaktiv", Vergleich `== 1`) und `Locked` (bool, "gesperrt"). Es existiert kein enumeriertes Statusmodell mit benannten Zuständen (z. B. "gelöscht", "archiviert", "Bonitätssperre") im gesichteten BL-Code.
Aussage: Das System soll den Lebenszyklus-Status eines Kunden (aktiv/inaktiv, gesperrt/entsperrt) als eigenständiges fachliches Konzept abbilden, das im Zielsystem klar benannte, erweiterbare Zustände (z. B. Enum statt Rohint) unterstützt.
Ergebnis: Migrationsrelevanter Fakt: Legacy-Datenmodell nutzt zwei binäre/int-Felder statt eines State-Machine-Modells.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:15,30 (`State`, `Locked`) - Begründung: Felddefinition.
- [KONTEXT] src/backend/Centron.Entities/Entities/Businesspartner/Supplier.cs:8-9 - Begründung: Lieferant besitzt nur `State`, kein `Locked`-Äquivalent – Asymmetrie zwischen Kunden- und Lieferanten-Stammdatenmodell.
Prüfidee: Klärung mit Fachbereich, ob Lieferanten je gesperrt werden können und wie das aktuell (ohne `Locked`-Feld) gehandhabt wird.
Tracelinks: SyRS-CRM-03
Konsolidierung: nein
Status: HYPOTHESE (fehlende Information: ob Lieferanten-Sperre über anderes Feld/Modul realisiert wird – im gesichteten `Supplier`-Entity nicht vorhanden)
---
ID: StRS-CRM-02
Titel: DSGVO-konforme Löschung von Kontaktpersonen
Ebene: StRS
Typ: Sicherheit / Compliance
Akteur: Buchhaltung, Vertrieb, Datenschutzbeauftragter
Vorbedingung: Löschantrag zu einer Kontaktperson (DSGVO/Art. 17 DSGVO)
Fakt: `DataSecurityBL` implementiert eine "DSGVO löschen"-Funktion für `ContactPerson`: personenbezogene Felder (Geburtsdatum, Beruf, Telefon 1-5, Fax 1-2, E-Mail 1-2, Mailing-Flags, Kommentarfelder, Abteilung, Bild, Active-Directory-SID, Website, Web-Zugangsdaten) werden geleert bzw. mit dem Platzhaltertext "DSGVO: Auf Anfrage gelöscht. (Durchgeführt von {ShortSign} am {Datum} um {Uhrzeit} Uhr)" überschrieben; jeder gelöschte Wert wird vor dem Löschen in ein Lösch-Protokoll (`deleteProtocol`) geschrieben; die Kontaktperson erhält `IsDsgvoDeleted=true`, `DsgvoDeletedEmployeeI3D`, `DsgvoDeletedDate` und wird (außer bei `Standard`-Kontakt) deaktiviert (`Status=0`).
Aussage: Das System soll auf Anfrage die personenbezogenen Daten einer Kontaktperson DSGVO-konform anonymisieren, den Vorgang inkl. verantwortlichem Mitarbeiter und Zeitpunkt nachvollziehbar protokollieren und die vorherigen Werte für Nachweiszwecke in einem Löschprotokoll festhalten.
Ergebnis: Kontaktperson ist nach Ausführung anonymisiert, als DSGVO-gelöscht markiert und (i. d. R.) deaktiviert; ein Audit-Trail bleibt erhalten.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:1152-1276 - Begründung: Vollständige Feld-für-Feld-Anonymisierungslogik inkl. Protokollierung und Statusmarkierung.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:26-27 - Begründung: Konstanten für den Lösch-Kommentartext.
Prüfidee: DSGVO-Löschung einer Testkontaktperson auslösen; prüfen, dass alle genannten Felder geleert sind, `IsDsgvoDeleted=true` gesetzt ist und ein lesbares Protokoll erzeugt wird.
Tracelinks: SwRS-CRM-08 (kein SyRS-Zwischenschritt im Cluster vorhanden – Lücke auf SyRS-Ebene)
Konsolidierung: Kandidat: SwRS-CRM-08, StRS-CRM-03 (gemeinsames Thema DSGVO-Datenlöschung/-bereinigung)
Status: belegt
---
ID: StRS-CRM-03
Titel: Übersicht löschrelevanter Altdatenbestände (DSGVO)
Ebene: StRS
Typ: Compliance / Sicherheit
Akteur: Datenschutzbeauftragter
Vorbedingung: Durchführung einer DSGVO-Datenbereinigung
Fakt: `DataSecurityBL.GetDataSecurityCleanUpStats` liefert Statistiken zu löschrelevanten Datenbeständen (Kunden mit letzter Aktion älter als Datum X, bereits gelöschte Kunden, CRM-Aktivitäten älter als Datum X, Belege [Angebote/Aufträge/Lieferscheine/Abholscheine/Rechnungen/Gutschriften] älter als Datum X, mit Filter nach Kundenart/Objektart/Abschlussstatus). Zugriff ist an das Recht `UserRightsConst.DsgvoModule.ACCESS_CLEANUP_DATABASE` UND ein Feature-Flag `ModuleFeatures.IsDsgvoDatabaseCleanupAvailable` gekoppelt.
Aussage: Das System soll autorisierten Benutzern eine Übersicht über lösch-/archivierungsrelevante Alt-Datenbestände (Kunden, CRM-Aktivitäten, Belege) auf Basis konfigurierbarer Aufbewahrungsfristen bereitstellen, bevor eine Bereinigung ausgeführt wird.
Ergebnis: Statistik-Report vor Ausführung der eigentlichen Löschung; feature-geflaggt und rechtebeschränkt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:34-62 (`GetDataSecurityCleanUpStats`) - Begründung: Zeigt Filter- und Rechtekombination.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:64-70 (`DataSecurityExecuteCleanUp`) - Begründung: Ausführungsmethode ist rechtegeschützt, der eigentliche Bereinigungsvorgang liefert im gesichteten Ausschnitt nur `Result.AsSuccess()` ohne sichtbare Löschlogik an dieser Stelle (weitere Implementierung evtl. in nicht gelesenen Codeteilen der 1900-Zeilen-Datei).
Prüfidee: Statistikabruf mit und ohne Recht `ACCESS_CLEANUP_DATABASE` testen; Feature-Flag deaktivieren und Verhalten prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: StRS-CRM-02, SwRS-CRM-08 (gemeinsames Thema DSGVO-Datenlöschung/-bereinigung)
Status: belegt (Ausführungslogik nur teilweise gesichtet – Datei hat 1900 Zeilen, nicht vollständig gelesen)
---
ID: StRS-CRM-04
Titel: Dubletten-Erkennung und Zusammenführung von Geschäftspartnern
Ebene: StRS
Typ: nicht-funktional (Datenqualität)
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Anlage/Pflege von Kunden- und Lieferanten-Stammdaten über die Zeit
Fakt: Im gesamten gesichteten `Centron.BL`-Code (Customer-, Address-, ContactPerson-, Supplier-Bereich) wurde keine Dubletten-Erkennung (z. B. Ähnlichkeitssuche über Name/Adresse/USt-IdNr.) und keine Merge-Funktion für zwei Geschäftspartner-Datensätze gefunden; die einzige Unterstützung ist die Freitext-Suche nach Matchcode/Name/I3D vor manueller Neuanlage (`SearchCustomerBL`, `SearchCustomerBySearchText`).
Aussage: Das System soll Vertriebs- und Buchhaltungsmitarbeiter bei der Neuanlage von Geschäftspartnern durch eine aktive Dubletten-Prüfung (z. B. Ähnlichkeitssuche) unterstützen und eine Funktion zum Zusammenführen (Merge) versehentlich doppelt angelegter Datensätze bereitstellen.
Ergebnis: Fehlende Funktionalität im Ist-System; Dublettenvermeidung liegt vollständig in der manuellen Sorgfalt des Sachbearbeiters.
Belege:
- [KONTEXT] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99 (`SearchCustomerBySearchText`) - Begründung: Zeigt, dass nur eine einfache Textsuche als Vorab-Prüfung existiert.
- [KONTEXT] Negativbefund aus gezielter Suche (`grep -rniE "dublette|duplicate|merge"` über `Sales/Customers`, `EmployeeArea`, `CountryArea`, `BusinessPartner`) - Begründung: Keine Treffer zu fachlicher Dubletten-/Merge-Logik für Geschäftspartner (nur technische Login-Duplikatsprüfungen, siehe SyRS-CRM-05).
Prüfidee: Fachbereich befragen, ob Dublettenbereinigung ggf. über ein separates, hier nicht durchsuchtes Modul (z. B. externes Datenqualitäts-Tool) erfolgt, das nicht Teil von `Centron.BL` ist.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein (explizit abgegrenzt von SyRS-CRM-05: dort nur technische Login-Namen-Eindeutigkeit, keine fachliche Geschäftspartner-Dublette)
Status: HYPOTHESE (fehlende Information: Negativbefund – Abwesenheit von Funktionalität kann nicht abschließend über Quellcode-Grep bewiesen werden, ggf. existiert Logik in einem nicht durchsuchten Modul oder als externes Tool)
@@ -0,0 +1,223 @@
ID: SwRS-CRM-01
Titel: Pflichtfeld Kundenname
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb
Vorbedingung: Neuanlage eines Kunden (Geschäftspartner Typ Kunde)
Fakt: Beim Speichern eines neuen `Customer` prüft `StoreCustomerBL.DoValidateValues` ausschließlich, ob `entity.Name` leer/whitespace ist; ist dies der Fall, wird der Speichervorgang mit der Meldung "Bitte geben Sie einen Namen ein" abgebrochen. Kein anderes Feld (z. B. Adresse, USt-IdNr., Bankverbindung) wird beim Speichern serverseitig validiert.
Aussage: Das System soll beim Anlegen und Ändern eines Kunden-Geschäftspartners zwingend einen nicht-leeren Namen verlangen und den Speichervorgang andernfalls mit einer Fehlermeldung ablehnen.
Ergebnis: Speichern schlägt fehl mit Fehlermeldung "Bitte geben Sie einen Namen ein", solange `Name` leer ist; alle übrigen Felder sind serverseitig ungeprüft.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:39-51 (`DoValidateValues`) - Begründung: Einzige serverseitige Pflichtfeldprüfung beim Kunden-Speichern.
Prüfidee: Kunde ohne Namen über Backend-API/BL anlegen und Fehlermeldungstext/-code prüfen; Kunde mit Namen aber ohne Adresse/USt-IdNr. anlegen und beobachten, dass kein Fehler auftritt.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SwRS-CRM-07, SyRS-CRM-09 (gemeinsames Thema: fehlende serverseitige Formatvalidierung von Stammdatenfeldern)
Status: belegt
---
ID: SwRS-CRM-02
Titel: Default-Status neuer Kunden
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb
Vorbedingung: Neuanlage eines Kunden über `CustomerBL.GetEmptyCustomer`
Fakt: Ein neu instanziierter Kunde erhält per Default `State = 1` (aktiv) und `Locked = false` (nicht gesperrt); zusätzlich wird automatisch eine leere Standard-Adresse (`DefaultCustomer = true`) angelegt.
Aussage: Das System soll neu angelegte Kunden standardmäßig als aktiv und ungesperrt initialisieren und automatisch eine als Standard markierte Adresse anlegen.
Ergebnis: Neuer Kunde ist sofort `State=1`, `Locked=false`, mit genau einer Default-Adresse.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:12-17 (`State = 1` im Konstruktor) - Begründung: Basis-Default.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:198-211 (`GetEmptyCustomer`) - Begründung: Explizite Zuweisung `State=1; Locked=false;` plus Default-Adresse.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:30-34 - Begründung: Bei `isNew` wird `State=1`/`Locked=false` beim Speichern erneut erzwungen.
Prüfidee: Neuen Kunden über UI/BL anlegen, DB-Werte für `Status`/`Sperre` und Adress-Flag `DefaultCustomer` prüfen.
Tracelinks: SyRS-CRM-03, StRS-CRM-01
Konsolidierung: Kandidat: SwRS-CRM-04
Status: belegt
---
ID: SwRS-CRM-03
Titel: Adresse erfordert Kunden- oder Lieferantenzuordnung
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb, Buchhaltung (Kunden und Lieferanten teilen die Adress-Entität)
Vorbedingung: Anlage/Änderung einer Adresse
Fakt: `AddressBL.DoValidateValues` verlangt, dass eine Adresse entweder einer `CustomerI3D` oder einer `SupplierI3D` zugeordnet ist; ansonsten Fehlermeldung "Die Anschrift muss entweder einem Kunden oder einem Lieferanten zugeordnet sein."
Aussage: Das System soll jede Adresse zwingend genau einem Geschäftspartner (Kunde oder Lieferant) zuordnen und darf keine „verwaisten" Adressen speichern.
Ergebnis: Speichern einer Adresse ohne Kunden- oder Lieferanten-Referenz wird abgelehnt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:225-238 (`DoValidateValues`) - Begründung: Wortlaut der Validierungsregel und Fehlermeldung.
Prüfidee: Adresse ohne `CustomerI3D`/`SupplierI3D` speichern und Fehlermeldung prüfen.
Tracelinks: SyRS-CRM-01
Konsolidierung: Kandidat: SyRS-CRM-01, SyRS-CRM-02
Status: belegt
---
ID: SwRS-CRM-04
Titel: Automatische Vervollständigung von Kunde, Adresse, Ansprechpartner und Kundennummer
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Neuer Kunde ohne explizite Adresse/Ansprechpartner wird gespeichert
Fakt: `StoreCustomerBL.DoBeforeStoreTrans` legt bei fehlender Default-Adresse automatisch eine neue Adresse an (`AddressBL.CreateNewAddressForCustomer`) bzw. markiert die erste vorhandene Adresse als Standard; analog wird bei fehlendem Standard-Ansprechpartner automatisch einer erzeugt (`ContactPersonBL.GetEmptyContactPersonForAddress`) oder der erste vorhandene als Standard markiert. Die I3D (Kundennummer) eines neuen Kunden wird, falls `<=0`, über `Session.GetGenericDAO<Customer>().GetMaxValue() + 1` vergeben.
Aussage: Das System soll beim Anlegen eines Kunden automatisch eine gültige Mindeststruktur (genau eine Standardadresse mit genau einem Standard-Ansprechpartner) sowie eine fortlaufende Kundennummer sicherstellen.
Ergebnis: Jeder gespeicherte Kunde besitzt danach mindestens eine Default-Adresse mit mindestens einem Default-Ansprechpartner und eine eindeutige numerische Kundennummer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:53-106 (`DoBeforeStoreTrans`) - Begründung: Vollständige Auto-Vervollständigungslogik inkl. I3D-Vergabe (Zeile 61-64).
Prüfidee: Kunde ohne Adressliste anlegen; DB-Zustand nach Speichern prüfen (Adresse + Ansprechpartner vorhanden, `DefaultCustomer=true`, `Default=true`).
Tracelinks: SyRS-CRM-01, SyRS-CRM-02
Konsolidierung: Kandidat: SwRS-CRM-02
Status: belegt; Workaround (Kundennummernvergabe per `MAX(I3D)+1` ohne erkennbare Sperre/Transaktion gegen Race Conditions im gesichteten Code – HYPOTHESE bzgl. Nebenläufigkeitssicherheit, da keine expliziten Locks sichtbar sind)
---
ID: SwRS-CRM-05
Titel: Automatische Verzeichnisstruktur bei Kundenanlage
Ebene: SwRS
Typ: Schnittstelle / Daten
Akteur: Vertrieb, IT-Administration
Vorbedingung: Neuanlage eines Kunden
Fakt: `CustomerBL.CreateCustomerDirectories` legt beim Neuanlegen eines Kunden automatisch eine feste Verzeichnisstruktur im Dokumentenmanagement an (u. a. Bestellungen, Angebote, Aufträge, Service, Lieferscheine, Abholscheine, Rechnungen, Helpdesk, Geräte, Verträge, Projekte, Aktivitäten, Mails, Gutschriften) plus konfigurierbare Zusatzverzeichnisse aus `CustomerDirectory`.
Aussage: Das System soll bei Kundenanlage automatisch eine standardisierte, prozessbezogene Ablagestruktur im Dokumentenmanagement erzeugen.
Ergebnis: Jeder neue Kunde erhält ~14 Standardverzeichnisse plus rekursive Zusatzverzeichnisse.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:438-597 (`CreateCustomerDirectories`, `InsertSpecialCustomerDirectories`) - Begründung: Vollständige Verzeichnisliste und Rekursionslogik.
Prüfidee: Neuen Kunden anlegen und Verzeichnisbaum im DMS-Modul auf Vollständigkeit prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein (thematisch mit Cluster „Dokumentenmanagement" verknüpft, außerhalb dieses Clusters)
Status: belegt
---
ID: SwRS-CRM-06
Titel: Berechneter Mitarbeiter-Aktivstatus
Ebene: SwRS
Typ: Daten
Akteur: Personalabteilung
Vorbedingung: Mitarbeiter-Stammdatensatz vorhanden
Fakt: `EmployeeBL.GetEmployeeCompactValidationExpression<T>()` definiert einen Mitarbeiter als "aktiv" gemäß: `State == 1 AND (CommencementDate == null OR CommencementDate <= heute) AND (LeavingDate == null OR LeavingDate > heute OR LeavingDate <= 1900-01-01)`. Das Datum `1900-01-01` wird also als Sentinel-Wert für "kein Austrittsdatum gesetzt" interpretiert.
Aussage: Das System soll einen Mitarbeiter automatisch anhand von Status, Eintritts- und Austrittsdatum als aktiv/inaktiv einstufen, ohne dass ein separates manuelles "Aktiv"-Flag gepflegt werden muss.
Ergebnis: Aktivitätsstatus ergibt sich aus drei Feldern kombiniert; `1900-01-01` fungiert als technischer Nullwert-Ersatz für `LeavingDate`.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs:671-676 (`GetEmployeeCompactValidationExpression`) - Begründung: Exakte Formel der Aktiv-Berechnung.
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/EmployeeArea/EmployeeBase.cs:15-23 (`CommencementDate`, `LeavingDate`, `IsActive`) - Begründung: Zeigt, dass zusätzlich noch ein eigenständiges `IsActive`-Feld existiert, das parallel gepflegt werden kann (`GetAllInactiveEmployees` nutzt `IsActive==false` statt der Expression, Zeile 321-324).
Prüfidee: Mitarbeiter mit `LeavingDate = 1899-01-01` bzw. `LeavingDate = null` anlegen und prüfen, ob beide als "aktiv" gelten (sofern `State=1`); Vergleich mit `IsActive`-Feld auf Inkonsistenzen prüfen.
Tracelinks: SyRS-CRM-06
Konsolidierung: Kandidat: SyRS-CRM-06 (konkurrierendes Aktiv-Kriterium für verwandte Entität AppUser/Employee)
Status: belegt; Workaround (Sentinel-Datum 1900-01-01 statt NULL-Semantik; zwei redundante Aktiv-Konzepte im Datenmodell)
---
ID: SwRS-CRM-07
Titel: Redundante USt-IdNr. ohne Formatvalidierung
Ebene: SwRS
Typ: Daten
Akteur: Buchhaltung
Vorbedingung: Kunde mit Umsatzsteuer-relevanten Daten
Fakt: Die Umsatzsteuer-Identifikationsnummer wird redundant an zwei Stellen geführt: pro Adresse als `Address.AdressSalesTaxIdentificationNumber` und separat auf Kundenebene als `CustomerFinanceInfo.SalesTaxIdentificationNumber`; zusätzlich existiert `Customer.VATNotActive` (bool) sowie identisch benannt `CustomerFinanceInfo.VATNotActive`. Ein Format-/Prüfsummen-Check (z. B. gegen EU-USt-IdNr.-Schema) wurde im BL-Code nicht gefunden.
Aussage: Das System soll die Umsatzsteuer-Identifikationsnummer als eindeutiges, konsistentes Attribut je Geschäftspartner führen und deren Format serverseitig validieren (kein Duplikat auf Adress- und Kundenebene).
Ergebnis: Migrationsrelevanter Datenmodell-Befund: redundante/uneindeutige Führung der USt-IdNr., keine Formatprüfung serverseitig.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Address.cs:30 (`AdressSalesTaxIdentificationNumber`) - Begründung: Feld auf Adressebene.
- [PRIMÄR] src/backend/Centron.Entities/Entities/Sales/Customers/CustomerFinanceInfo.cs:9,11 (`SalesTaxIdentificationNumber`, `VATNotActive`) - Begründung: Zweites, konkurrierendes Feld auf Kundenebene.
- [KONTEXT] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:131 (`VATNotActive`) - Begründung: Drittes Feld gleichen Namens direkt auf `Customer`.
Prüfidee: Prüfen, welches der Felder tatsächlich in Rechnungsstellung/EDI (z. B. ZUGFeRD) verwendet wird; Format-Grep in Validierungs-/Regex-Bibliotheken.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SwRS-CRM-01, SyRS-CRM-08, SyRS-CRM-09 (gemeinsames Thema: fehlende serverseitige Validierung/Redundanz von Stammdatenfeldern)
Status: HYPOTHESE (fehlende Information: welches Feld führend ist und ob eine Formatvalidierung an anderer Stelle – z. B. UI-Layer, hier nicht vollständig durchsucht – existiert)
---
ID: SwRS-CRM-08
Titel: Fehlende DSGVO-Löschfunktion auf Kundenebene
Ebene: SwRS
Typ: Compliance
Akteur: Datenschutzbeauftragter, Buchhaltung
Vorbedingung: DSGVO-Löschantrag bezieht sich auf einen gesamten Kunden (nicht nur eine Kontaktperson)
Fakt: Die Methode `DataSecurityBL.DoDeleteCustomer(int i3d, bool isReferenceDelete)` ist im Quellcode vorhanden, wirft aber unbedingt `throw new NotImplementedException("DoDeleteCustomer is not ready for use!")`. Der zugehörige Aufrufcode ist zudem auskommentiert (`// DoDeleteCustomer(...)`).
Aussage: Das System soll eine vollständige, DSGVO-konforme Löschung/Anonymisierung auf Kundenebene (nicht nur auf Ebene einzelner Kontaktpersonen) bereitstellen.
Ergebnis: Im Ist-System existiert aktuell keine produktiv nutzbare Funktion zur Löschung eines kompletten Kundendatensatzes im Rahmen der DSGVO-Bereinigung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:856-858 (`DoDeleteCustomer`) - Begründung: Explizite `NotImplementedException`.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:803 - Begründung: Auskommentierter Aufruf bestätigt, dass die Funktion nicht im aktiven Ablauf verwendet wird.
Prüfidee: Im laufenden System versuchen, eine kundenbezogene DSGVO-Löschung auszuführen, und den resultierenden Fehler dokumentieren.
Tracelinks: StRS-CRM-02
Konsolidierung: Kandidat: StRS-CRM-02, StRS-CRM-03 (gemeinsames Thema DSGVO-Datenlöschung/-bereinigung)
Status: belegt; Workaround (Funktion bewusst deaktiviert/nicht fertiggestellt)
---
ID: SwRS-CRM-09
Titel: Löschsperre für referenzierte Kundenherkunft
Ebene: SwRS
Typ: Daten / funktional
Akteur: Vertrieb
Vorbedingung: Kunde besitzt eine "Kundenherkunft" (`CustomerAncestry`, z. B. Konzernzugehörigkeit/Quelle)
Fakt: `CustomerAncestryBL.DeleteCustomerAncestry` verhindert das Löschen eines `CustomerAncestry`-Datensatzes, solange mindestens ein `Customer` mit `CustomerOriginI3D` darauf verweist (`Count`-Prüfung vor `Delete`), und liefert sonst die (englischsprachige) Fehlermeldung "Couldn´t be deleted, because the ancestry is used by customers".
Aussage: Das System soll referenzierte Stammdaten-Klassifikationswerte (hier: Kundenherkunft) erst dann zur Löschung zulassen, wenn keine Kunden mehr darauf verweisen.
Ergebnis: Referentielle Integrität wird anwendungsseitig (nicht per DB-Fremdschlüssel-Exception) sichergestellt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerDetails/CustomerAncestryBL.cs:33-43 (`DeleteCustomerAncestry`) - Begründung: Zeigt Zähl-Check und Fehlermeldung.
Prüfidee: Kundenherkunft löschen, die noch von einem Kunden referenziert wird; Fehlermeldung/-verhalten dokumentieren; feststellen, ob Fehlermeldung an Endnutzer tatsächlich englischsprachig ausgegeben wird (i18n-Lücke).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt
---
ID: SwRS-CRM-10
Titel: Fehlende Duplikatsprüfung bei RFID-Tokens
Ebene: SwRS
Typ: Daten / Sicherheit
Akteur: Personalabteilung, IT-Administration
Vorbedingung: Mitarbeiter erhält RFID-Token (z. B. für Zeiterfassung/Zutrittskontrolle)
Fakt: `EmployeeRfidTokenBL.SaveOrUpdateEmployeeRfidTokens` speichert `EmployeeRfidToken`-Datensätze mit AES/Master-Key-verschlüsseltem `RfidTokenEncrypted`-Wert (`CentronConfigurationDbBL.EncryptWithMasterKey`), prüft dabei aber weder auf Ebene der Methode noch erkennbar per DB-Constraint, ob derselbe Token bereits einem anderen Mitarbeiter zugeordnet ist oder ob ein Mitarbeiter bereits einen Token besitzt.
Aussage: Das System soll sicherstellen, dass ein RFID-Token eindeutig genau einem aktiven Mitarbeiter zugeordnet ist, um Fehlzuordnungen bei Zeiterfassung/Zutritt zu verhindern.
Ergebnis: Ohne zusätzliche DB-Constraints besteht das Risiko doppelt vergebener Tokens.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/EmployeeRfidTokenBL.cs:39-57 (`SaveOrUpdateEmployeeRfidTokens`) - Begründung: Keine Duplikatsprüfung im Methodenkörper sichtbar (nur `Guard.NotNull`).
Prüfidee: Zwei `EmployeeRfidToken`-Datensätze mit identischem entschlüsseltem Tokenwert für unterschiedliche Mitarbeiter anlegen und prüfen, ob dies zugelassen wird.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: HYPOTHESE (fehlende Information: ob Eindeutigkeit ggf. per DB-Unique-Index auf `RfidTokenEncrypted` sichergestellt ist – DAO/Mapping-Definitionen wurden für dieses Cluster nicht vollständig durchsucht)
---
ID: SwRS-CRM-11
Titel: Kundenbetreuerrollen (Adviser1-6)
Ebene: SwRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Kunde besitzt Vertriebsbetreuer
Fakt: `CustomerBase` besitzt sechs Betreuer-Referenzen `Adviser1I3D`…`Adviser6I3D`, von denen die ersten vier im Code kommentiert sind als "Innendienst" (Adviser1), "Aussendienst" (Adviser2), "Techniker 1" (Adviser3), "Techniker 2" (Adviser4); `SearchCustomerBL.GetCustomerFromEmployeeExpression` nutzt genau diese vier Felder, um Kunden eines Mitarbeiters zu ermitteln (Adviser5/6 werden dort nicht berücksichtigt).
Aussage: Das System soll einem Kunden mehrere Betreuerrollen (u. a. Innendienst, Außendienst, Techniker) mit je einem zuständigen Mitarbeiter zuordnen können und Mitarbeitern ihre zugeordneten Kunden anzeigen.
Ergebnis: Vier feste Betreuerrollen sind fachlich benannt und in der Kundensuche nach Mitarbeiter aktiv genutzt; zwei weitere Felder (`Adviser5/6I3D`) sind im Modell vorhanden, aber ohne erkennbare fachliche Bezeichnung/Verwendung in den gesichteten Dateien.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:19-24 - Begründung: Kommentare benennen die Rollen.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/SearchCustomerBL.cs:82-90 (`GetCustomerFromEmployeeExpression`) - Begründung: Nutzung von Adviser1-4, Auslassung von Adviser5/6.
Prüfidee: UI-Bezeichnungen der Felder Adviser5/Adviser6 im WPF-Client (nicht Teil dieses Clusters) abgleichen, um deren fachliche Bedeutung zu klären.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt (Rollen 1-4); HYPOTHESE bzgl. Adviser5/6 (fehlende Information zur fachlichen Bezeichnung)
---
ID: SwRS-CRM-12
Titel: Kundenindividuelle Pflichtangaben-Flags
Ebene: SwRS
Typ: Daten
Akteur: Vertrieb
Vorbedingung: Kunde benötigt Bestellnummer-Pflicht bei Auftragserfassung
Fakt: `Customer.PurchaseOrderNumberRequiered` (bool) ist ein pro Kunde konfigurierbares Flag; ebenso `Customer.ProjNrNeeded` (Projektnummer-Pflicht) und `Customer.ProductionConfigurationRequiring`.
Aussage: Das System soll pro Kunde konfigurierbar erzwingen können, dass bei der Auftrags-/Belegerfassung bestimmte Zusatzangaben (Bestellnummer des Kunden, Projektnummer, Produktionskonfiguration) verpflichtend sind.
Ergebnis: Kundenindividuelle Pflichtfeld-Schalter, die vermutlich in nachgelagerten Modulen (Auftragserfassung) ausgewertet werden (dort nicht verifiziert, da außerhalb des Clusters).
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:48 (`PurchaseOrderNumberRequiered`) - Begründung: Feld inkl. auffälligem Schreibfehler im Bezeichner ("Requiered" statt "Required").
- [KONTEXT] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:208,235-236 (`ProjNrNeeded`, `ProductionConfigurationRequiring`, `PrintProductionConfiguration`) - Begründung: Weitere kundenindividuelle Pflicht-/Steuerflags.
Prüfidee: Auftrag für Kunden mit `PurchaseOrderNumberRequiered=true` ohne Bestellnummer anlegen (im Auftragsmodul, nicht Teil dieses Clusters) und Systemverhalten prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein (Auswertung vermutlich im Cluster „Vertrieb/Auftragsabwicklung" gegenzuprüfen)
Status: belegt (Feldexistenz); HYPOTHESE bzgl. Durchsetzung außerhalb dieses Clusters nicht verifiziert
@@ -0,0 +1,220 @@
ID: SyRS-CRM-01
Titel: Eindeutige Standardadresse je Kunde/Lieferant
Ebene: SyRS
Typ: funktional / Daten
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Kunde besitzt mehrere Adressen
Fakt: `AddressBL.DoAfterStoreTrans` erzwingt nach dem Speichern einer Adresse mit `DefaultCustomer = true`, dass alle anderen Adressen desselben Kunden `DefaultCustomer = false` erhalten (analog für Lieferanten mit `DefaultCreditor`).
Aussage: Das System soll sicherstellen, dass ein Kunde (bzw. Lieferant) zu jedem Zeitpunkt genau eine als Standard markierte Adresse besitzt.
Ergebnis: Beim Setzen einer neuen Standardadresse werden alle vorherigen Standard-Flags desselben Kunden automatisch zurückgesetzt.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:257-287 (`DoAfterStoreTrans`) - Begründung: Zeigt Kaskadenlogik für eindeutige Standardadresse/-kreditor.
Prüfidee: Zweite Adresse eines Kunden als Standard markieren und speichern; prüfen, dass die erste Adresse automatisch entmarkiert wird.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-CRM-02, SwRS-CRM-03 (gemeinsame Kernregelgruppe der Adressverwaltung)
Status: belegt
---
ID: SyRS-CRM-02
Titel: Eindeutiger Standard-Ansprechpartner je Adresse
Ebene: SyRS
Typ: funktional / Daten
Akteur: Vertrieb
Vorbedingung: Adresse besitzt mehrere Ansprechpartner
Fakt: `ContactPersonBL.DoAfterStoreTrans` → `DoUpdateDefaultFlagFromOtherContacts` setzt beim Speichern eines Ansprechpartners mit `Default = true` alle anderen Ansprechpartner derselben Adresse auf `Default = false`.
Aussage: Das System soll sicherstellen, dass jede Adresse höchstens einen als Standard markierten Ansprechpartner besitzt.
Ergebnis: Eindeutigkeit des Standard-Ansprechpartners je Adresse wird durch die Business-Logik erzwungen (kein DB-Constraint, sondern Anwendungslogik).
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:190-220 (`DoAfterStoreTrans`, `DoUpdateDefaultFlagFromOtherContacts`) - Begründung: Explizite Kaskadenlogik.
Prüfidee: Zwei Ansprechpartner derselben Adresse abwechselnd als Standard markieren, DB-Zustand prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-CRM-01
Status: belegt
---
ID: SyRS-CRM-03
Titel: Definition aktiver/entsperrter Kunde
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb, Buchhaltung
Vorbedingung: Kunde wird für Folgeprozesse (Auftrag, Angebot, Rechnung) referenziert
Fakt: `CustomerBL.IsCustomerActiveUnlocked(Customer)` definiert einen Kunden als "aktiv/entsperrt" genau dann, wenn `customer.State == 1 && !customer.Locked`; diese Prüfung wird u. a. in `GetActiveUnlockedCustomer` verwendet.
Aussage: Das System soll einen Kunden als geschäftlich nutzbar (aktiv) nur dann behandeln, wenn sowohl der Status "aktiv" (`State=1`) gesetzt als auch keine Sperre (`Locked=false`) vorliegt.
Ergebnis: Zwei unabhängige Felder (`State`, `Locked`) steuern gemeinsam die Nutzbarkeit eines Kunden im System.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:382-391 (`IsCustomerActiveUnlocked`, `IsCustomerActiveAndNotLocked`) - Begründung: Zentrale Statuslogik.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99, 182-196 (`SearchCustomerBySearchText`, `GetActiveCustomerCompact`) - Begründung: Kundensuche filtert konsistent auf `State==1 && !Locked`.
Prüfidee: Kunden mit `State=1, Locked=true` und `State=0, Locked=false` anlegen und prüfen, dass beide in Standard-Kundensuchen nicht erscheinen.
Tracelinks: StRS-CRM-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-CRM-04
Titel: Rechtebeschränkung Mitarbeiterstammdatenpflege
Ebene: SyRS
Typ: Sicherheit
Akteur: Personalabteilung
Vorbedingung: Bearbeitung eines Mitarbeiter-Stammdatensatzes
Fakt: `EmployeeBL.SaveOrUpdateEmployee` prüft vor jedem Speichern das Recht `UserRightsConst.Administration.EmployeeManagement.ADMINISTRATE_ALL_EMPLOYEES`; ohne dieses Recht wird der Aufruf mit "You do not have the necessary rights to perform this action." abgelehnt.
Aussage: Das System soll das Anlegen und Ändern von Mitarbeiter-Stammdaten auf Benutzer mit dem Recht "Mitarbeiterverwaltung" beschränken.
Ergebnis: Rechteprüfung vor jeder Mitarbeiter-Speicherung; Fehlermeldung bei fehlendem Recht.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs:128-131 (`SaveOrUpdateEmployee`) - Begründung: Explizite Rechteprüfung als erste Anweisung der Methode.
Prüfidee: Benutzer ohne `ADMINISTRATE_ALL_EMPLOYEES` versuchen lassen, einen Mitarbeiter zu speichern; Fehlermeldung/-code prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-CRM-05, SyRS-CRM-07 (analoge Rechte-gesteuerte Schreib-/Lesezugriffe auf Stammdaten)
Status: belegt
---
ID: SyRS-CRM-05
Titel: Eindeutigkeit von Benutzer-Login und SSO-Kennung
Ebene: SyRS
Typ: Sicherheit / Daten
Akteur: Personalabteilung, IT-Administration
Vorbedingung: Anlegen/Ändern eines Benutzerkontos (`AppUser`), das mit einem Mitarbeiter verknüpft ist
Fakt: `AppUserBL.SaveOrUpdateAppUser` prüft das Recht `RIGHT_PERSONALMANAGEMENT`; verlangt bei Neuanlage einen bereits gespeicherten `Employee`; prüft die Eindeutigkeit des Login-Namens (`Name`, case-insensitive, getrimmt) unter allen `AppUser` UND zusätzlich gegen alle `WebAccount.Username` (kundengebundene Web-Zugänge); bei Kollision mit einem WebAccount wird der zugehörige Kunde in der Fehlermeldung genannt. Zusätzlich wird `OpenIdConnectSubjectIdentifier` global eindeutig geprüft.
Aussage: Das System soll sicherstellen, dass ein Login-Name eines internen Benutzerkontos systemweit eindeutig ist – sowohl unter internen Benutzerkonten als auch gegenüber Web-Kundenzugängen – und dass eine externe SSO-Kennung (OpenID Connect Subject) global eindeutig bleibt.
Ergebnis: Speichern schlägt fehl mit spezifischer Fehlermeldung, wenn Login-Name oder OIDC-Kennung bereits vergeben sind; Meldung nennt bei WebAccount-Kollision explizit Kundenname und -nummer.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:136-186 (`SaveOrUpdateAppUser`) - Begründung: Vollständige Validierungs-/Rechtekette inkl. Fehlermeldungstexte.
Prüfidee: Zwei AppUser mit gleichem (Groß-/Kleinschreibung abweichendem) Login anlegen; AppUser-Login identisch zu bestehendem WebAccount-Username anlegen; Fehlermeldungen prüfen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein (cross-cluster Relevanz für "Benutzer-/Rechteverwaltung" und "Web-Portal"; siehe Abgrenzungshinweis in StRS-CRM-04)
Status: belegt
---
ID: SyRS-CRM-06
Titel: Aktivstatus interner Benutzerkonten
Ebene: SyRS
Typ: funktional / Daten
Akteur: IT-Administration, Personalabteilung
Vorbedingung: Ermittlung aktiver interner Benutzer
Fakt: `AppUserBL.GetActiveAppUsers` definiert einen aktiven `AppUser` über eine Kombination aus `IsAccountDisabled == false`, einem Zeitfenster-Check auf `AccountDisabledFromDate`/`AccountDisabledToDate` (Konto kann zeitlich befristet deaktiviert sein) UND zusätzlich `Employee.IsActive == true`.
Aussage: Das System soll ein Benutzerkonto nur dann als aktiv betrachten, wenn weder eine permanente noch eine zeitlich befristete Kontosperre vorliegt und der zugehörige Mitarbeiter als aktiv geführt wird.
Ergebnis: Aktivstatus eines Logins hängt von drei Feldern des `AppUser` plus dem Aktivstatus des verknüpften `Employee` ab.
Belege:
- [PRIMÄR] src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:38-55 (`GetActiveAppUsers`) - Begründung: Komplexe, mehrteilige Bedingung im Code sichtbar.
Prüfidee: AppUser mit `AccountDisabledFromDate` in der Zukunft anlegen und prüfen, ob er aktuell noch als aktiv gilt (erwartet: ja, da Sperre erst ab Datum wirkt).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SwRS-CRM-06 (konkurrierendes "Mitarbeiter/Benutzer aktiv"-Kriterium: `Employee.IsActive` hier vs. berechneter Ausdruck dort – mögliche Dateninkonsistenz)
Status: belegt; Workaround (zwei unterschiedliche "Mitarbeiter aktiv"-Kriterien im Code: `EmployeeBL.GetEmployeeCompactValidationExpression` vs. hier direktes `Employee.IsActive` – mögliche Dateninkonsistenz)
---
ID: SyRS-CRM-07
Titel: Rechtebeschränkung Kundenzugriff
Ebene: SyRS
Typ: Sicherheit
Akteur: Vertrieb
Vorbedingung: Kundensuche/-anzeige
Fakt: `CustomerBL.HasUserReadCustomersRight` prüft das Recht `UserRightsConst.Sales.Customer.CustomerCommon.SEARCH_CUSTOMER`; `SearchCustomerBL.SearchCustomerBySearchTextWithPaging` prüft zusätzlich das (offenbar ältere/parallele) Recht `UserRightsConst.RIGHT_KUNDENSTAMM`.
Aussage: Das System soll den lesenden Zugriff auf Kundenstammdaten an ein dediziertes Benutzerrecht koppeln.
Ergebnis: Kundensuche/-liste liefert bei fehlendem Recht einen Fehler bzw. eine leere/verweigerte Antwort.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:234-240 (`HasUserReadCustomersRight`) - Begründung: Rechteprüfung `SEARCH_CUSTOMER`.
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/SearchCustomerBL.cs:113-121 (`SearchCustomerBySearchTextWithPaging`) - Begründung: Zweites, abweichendes Recht `RIGHT_KUNDENSTAMM`.
Prüfidee: Benutzer mit nur einem der beiden Rechte gegen beide Endpunkte testen, um Inkonsistenz zu bestätigen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: HYPOTHESE (fehlende Information: ob `RIGHT_KUNDENSTAMM` und `SEARCH_CUSTOMER` fachlich bewusst unterschiedliche Berechtigungsstufen abbilden oder ein historisches Duplikat sind)
---
ID: SyRS-CRM-08
Titel: Redundante Bankverbindungsdaten am Kunden
Ebene: SyRS
Typ: nicht-funktional / Daten
Akteur: Buchhaltung
Vorbedingung: Erfassung von Bankverbindungen am Kunden
Fakt: `Customer` führt zwei vollständige, redundant modellierte Bankverbindungssätze direkt als Entity-Felder (`BankIBAN`, `BankSWIFT`, `BankCountry`, `BankCity`, `BankStreet` sowie `Bank02`/`BankCode02`/`BankAccountNumber02`/`BankIBAN02`/`BankSWIFT02`/`BankCountry02`/`BankCity02`/`BankStreet02`) statt einer normalisierten 1:n-Beziehung zu Bankkonten.
Aussage: Das System soll Bankverbindungen eines Kunden als normalisierte, beliebig erweiterbare Liste (nicht als fest verdrahtete Feldpaare "01"/"02") modellieren.
Ergebnis: Datenmodell begrenzt einen Kunden technisch auf maximal zwei Bankverbindungen.
Belege:
- [PRIMÄR] src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:134-146 - Begründung: Zeigt die verdoppelten Feldsätze `Bank...`/`Bank...02`.
Prüfidee: Fachbereich befragen, ob mehr als zwei Bankverbindungen je Kunde jemals benötigt wurden (z. B. bei Konzernkunden/Sammelkonten).
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SwRS-CRM-07 (gemeinsames Thema: redundante/unvalidierte Finanz-Stammdatenfelder)
Status: belegt
---
ID: SyRS-CRM-09
Titel: IBAN-Prüfsummenvalidierung nur clientseitig
Ebene: SyRS
Typ: nicht-funktional / Sicherheit
Akteur: Buchhaltung, Vertrieb
Vorbedingung: Erfassung/Änderung der Bankverbindung eines Kunden in der WPF-Oberfläche
Fakt: Die IBAN-Prüfsummenvalidierung (Modulo-97-Verfahren nach ISO 7064) ist ausschließlich im WPF-Client implementiert (`IbanValidation.IbanChecksumCheck`) und wird konkret im Bankdaten-Formular des Kunden (`CrmFinanceView.xaml.cs`, Fehlertext "Keine gültige IBAN") aufgerufen. Im Backend (`Centron.BL`) wurde keine entsprechende Prüfung gefunden (weder in `StoreCustomerBL` noch in `BankAccountBL`).
Aussage: Das System soll die Prüfsummenvalidität einer IBAN serverseitig (nicht nur clientseitig) vor dem Persistieren erzwingen.
Ergebnis: Eine über einen anderen Kanal (z. B. API, Import, zukünftiges Web-Frontend) gespeicherte, prüfsummenungültige IBAN wird vom Backend nicht abgelehnt.
Belege:
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/Finances/Crm/Finance/CrmFinanceView.xaml.cs:30-39 - Begründung: Aufruf der Validierung nur im UI-Eventhandler.
- [PRIMÄR] src/centron/Centron.WPF.UI/Modules/DataExchange/DataImport/AccountImport/IbanValidation.cs:10-35 (`IbanChecksumCheck`) - Begründung: Implementierung des Mod-97-Verfahrens, referenziert externe Quelle "dotnet-snippets.de".
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:39-51 - Begründung: Zeigt, dass die serverseitige Validierung IBAN nicht prüft (Negativbeleg).
Prüfidee: IBAN mit falscher Prüfsumme über eine Web-Service-/API-Schnittstelle (unter Umgehung der WPF-Oberfläche) speichern und prüfen, ob das Backend dies zulässt.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SwRS-CRM-07, SyRS-CRM-08 (gemeinsames Thema: fehlende serverseitige Validierung/Redundanz von Finanz-Stammdatenfeldern)
Status: belegt; Workaround (Validierung nur clientseitig vorhanden – Lücke bei Neuimplementierung als Web-/SaaS-System zu schließen, da UI-Client dort nicht die einzige Eingabequelle ist)
---
ID: SyRS-CRM-10
Titel: Automatische Kunden-/Kontakterkennung per E-Mail
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb (Helpdesk/Support)
Vorbedingung: Eingehende E-Mail soll automatisch einem Kunden/Ansprechpartner zugeordnet werden
Fakt: `ContactPersonBL.SearchAddressContactByEmailAddress` sucht Kontaktpersonen anhand der Absender-E-Mail über eine benannte Query (`SearchAddressContactByEmailAddress`) mit mehreren Prioritätsstufen (exakte E-Mail, Domain, Domain+Web, Domain+TLD). Das Verhalten wird über `WorkflowSetting` gesteuert: `IsCustomerDetectionOverEMailDomainActive` schaltet die Domain-basierte Erkennung ein/aus; `CustomerDetectionOverContactEMail1`/`CustomerDetectionOverContactEMail2` steuern, ob E-Mail-Feld 1 bzw. 2 der Kontaktperson für die Zuordnung herangezogen wird; zusätzlich wird die Domain gegen eine Blacklist (`DomainBlacklistBL.IsBlacklisted`, z. B. generische Provider wie gmail.com) geprüft, bevor eine Domain-Zuordnung erfolgt.
Aussage: Das System soll eingehende Kommunikation (z. B. Helpdesk-Mails) automatisch anhand konfigurierbarer Regeln (exakte Kontakt-E-Mail, Domain-Zugehörigkeit, Blacklist generischer Domains) einem Kunden bzw. einer Kontaktperson zuordnen können.
Ergebnis: Priorisierte, konfigurierbare automatische Kunden-/Kontakterkennung über E-Mail.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:310-411 (`SearchAddressContactByEmailAddress`, `FilterSearchAddressContactResults`) - Begründung: Zeigt vollständige Priorisierungs- und Konfigurationslogik.
Prüfidee: Test-Mail von bekannter Domain mit und ohne aktivierte Domain-Erkennung senden; Blacklist-Domain (z. B. gmail.com) testen und prüfen, dass keine Domain-Zuordnung erfolgt.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-CRM-12 (analoges Prinzip "Geschäftspartner per E-Mail identifizieren", dort für Lieferanten)
Status: belegt
---
ID: SyRS-CRM-11
Titel: Ableitung des Standardlandes für neue Adressen
Ebene: SyRS
Typ: funktional
Akteur: Vertrieb
Vorbedingung: Länderstammdaten für Adressen/Kunden
Fakt: `CountryBL.GetDefaultCountry()`/`GetDefaultCountryI3D()` ermitteln genau ein Land mit `Default == true` (`.First()` bei der I3D-Variante, was bei keinem gesetzten Default-Land eine Exception auslösen würde); `GetInlandCountry` leitet das "Inland" hingegen aus `MandatorBL.GetDefaultMandator().Country` ab, mit explizitem TODO-Kommentar "TODO: Check the country of the branch for the current user...", d. h. eine niederlassungsspezifische (Branch-)Länderzuordnung ist noch nicht implementiert.
Aussage: Das System soll für jede Adresse automatisch ein Vorgabeland setzen (Neuanlage), abgeleitet aus dem für den Benutzer/die Niederlassung gültigen Mandanten- bzw. Niederlassungsland.
Ergebnis: Aktuell wird global das Mandanten-Standardland verwendet, unabhängig von der Niederlassung des angemeldeten Benutzers.
Belege:
- [PRIMÄR] src/backend/Centron.BL/CountryArea/CountryBL.cs:190-207 (`GetInlandCountry`, `GetDefaultCountryI3D`, `GetDefaultCountry`) - Begründung: Zeigt Implementierung und offenes TODO.
- [SEKUNDÄR] src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:46-51,248-249 - Begründung: `GetInlandCountry`/`GetDefaultCountry` werden beim Anlegen neuer Adressen als Default gesetzt.
Prüfidee: Benutzer einer Niederlassung mit abweichendem Land eine neue Kundenadresse anlegen lassen und beobachten, welches Land vorbelegt wird.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: nein
Status: belegt; Workaround (TODO im Code bestätigt unvollständige Niederlassungs-Länderzuordnung)
---
ID: SyRS-CRM-12
Titel: Lieferantensuche per E-Mail-Adresse
Ebene: SyRS
Typ: funktional
Akteur: Buchhaltung, Vertrieb
Vorbedingung: Lieferant/Kontaktperson mit E-Mail-Adresse
Fakt: `SearchSupplierBL.SearchSupplierByEmail` sucht zunächst Lieferanten mit exakt passender `Supplier.Email`; findet sie keine, sucht sie aktive `ContactPerson` mit passender `Email1`/`Email2`, deren Adresse `DefaultCreditor = true` markiert ist, und leitet daraus den zugehörigen Lieferanten ab.
Aussage: Das System soll einen Lieferanten sowohl über eine direkt hinterlegte Firmen-E-Mail als auch über die E-Mail-Adresse des Standard-Ansprechpartners (an der als Standard-Kreditor markierten Adresse) auffindbar machen.
Ergebnis: Zweistufige Fallback-Suche für Lieferantenidentifikation per E-Mail.
Belege:
- [PRIMÄR] src/backend/Centron.BL/BusinessPartner/SearchSupplierBL.cs:84-121 (`SearchSupplierByEmail`) - Begründung: Zeigt zweistufige Suchlogik inkl. `DefaultCreditor`-Filter.
Prüfidee: Lieferant ohne eigene E-Mail, aber mit Standard-Ansprechpartner-E-Mail anlegen; Suche nach dieser E-Mail testen.
Tracelinks: keine direkte Verknüpfung (Lücke)
Konsolidierung: Kandidat: SyRS-CRM-10 (analoges Prinzip "Geschäftspartner per E-Mail identifizieren", dort für Kunden)
Status: belegt
@@ -0,0 +1,26 @@
| StRS-CRM-01 | SyRS-CRM-03 | SwRS-CRM-02 | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:382-391 |
| StRS-CRM-02 | | SwRS-CRM-08 | src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:856-858 |
| StRS-CRM-02 | | | src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:1152-1276 |
| StRS-CRM-03 | | | src/backend/Centron.BL/Administration/DataSecurity/DataSecurityBL.cs:34-62 |
| StRS-CRM-04 | | | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:73-99 |
| | SyRS-CRM-01 | SwRS-CRM-03 | src/backend/Centron.BL/Sales/Customers/Addresses/AddressBL.cs:225-238 |
| | SyRS-CRM-01 | SwRS-CRM-04 | src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:53-106 |
| | SyRS-CRM-02 | SwRS-CRM-04 | src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:190-220 |
| | SyRS-CRM-04 | | src/backend/Centron.BL/EmployeeArea/EmployeeBL.cs:128-131 |
| | SyRS-CRM-05 | | src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:136-186 |
| | SyRS-CRM-06 | SwRS-CRM-06 | src/backend/Centron.BL/EmployeeArea/AppUserBL.cs:38-55 |
| | SyRS-CRM-07 | | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:234-240 |
| | SyRS-CRM-08 | | src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:134-146 |
| | SyRS-CRM-09 | | src/centron/Centron.WPF.UI/Modules/Finances/Crm/Finance/CrmFinanceView.xaml.cs:30-39 |
| | SyRS-CRM-10 | | src/backend/Centron.BL/Sales/Customers/ContactPersonBL.cs:310-411 |
| | SyRS-CRM-11 | | src/backend/Centron.BL/CountryArea/CountryBL.cs:190-207 |
| | SyRS-CRM-12 | | src/backend/Centron.BL/BusinessPartner/SearchSupplierBL.cs:84-121 |
| | | SwRS-CRM-01 | src/backend/Centron.BL/Sales/Customers/StoreCustomerBL.cs:39-51 |
| | | SwRS-CRM-05 | src/backend/Centron.BL/Sales/Customers/CustomerBL.cs:438-597 |
| | | SwRS-CRM-07 | src/backend/Centron.Entities/Entities/CustomerArea/Address.cs:30 |
| | | SwRS-CRM-09 | src/backend/Centron.BL/Sales/Customers/CustomerDetails/CustomerAncestryBL.cs:33-43 |
| | | SwRS-CRM-10 | src/backend/Centron.BL/EmployeeArea/EmployeeRfidTokenBL.cs:39-57 |
| | | SwRS-CRM-11 | src/backend/Centron.Entities/Entities/CustomerArea/CustomerBase.cs:19-24 |
| | | SwRS-CRM-12 | src/backend/Centron.Entities/Entities/CustomerArea/Customer.cs:48 |
@@ -0,0 +1,12 @@
- **DocuBoard**: Namespace/Ordnername im Quellcode (`Centron.BL/DocuBoard` u. a.), der entgegen der Erwartung KEIN Dokumentenmodul bezeichnet, sondern IT-Asset-/Gerätemanagement (Partner, Artikelzuordnung, AD-Systembenutzer-Ausschluss). Die tatsächliche Dokumentenverwaltung liegt unter `Administration/FileManagement`.
- **docuFORM**: Name eines externen Drittsystems für Multifunktionsdrucker-Fleet-Management (Geräte, Zählerstände), an das c-entron über `Centron.Api.docuFORM` per REST/OAuth2 angebunden ist. Nicht zu verwechseln mit Dokumentgenerierung.
- **I3D**: In der gesamten Codebasis durchgängig verwendete Bezeichnung für den technischen Primärschlüssel (Integer-ID) einer Entität, vergleichbar mit einer klassischen `Id`-Spalte.
- **OwnerDocument**: Selbstreferenz eines `Document`-Datensatzes auf den „Kopf"-Datensatz einer Versionskette; alle Versionen eines logischen Dokuments teilen dieselbe OwnerDocument-Referenz.
- **ZUGFeRD**: Deutscher Standard für hybride elektronische Rechnungen, bei dem strukturierte XML-Rechnungsdaten in ein PDF/A-3-Dokument eingebettet werden.
- **PDF/A-3b**: ISO-Standard zur Langzeitarchivierung von PDF-Dokumenten mit eingebetteten Dateianhängen (Voraussetzung für ZUGFeRD); erzwingt u. a. eingebettete Schriften.
- **Anrede/Abrede**: Fachbegriffe für Textbausteine am Anfang („Anrede", z. B. Begrüßung) bzw. Ende („Abrede", z. B. Grußformel/AGB-Hinweis) eines Belegs oder einer Mail.
- **Textbaustein (TextModule)**: Konfigurierbarer, wiederverwendbarer Textabschnitt (Anrede/Abrede/Prozesstext) mit Platzhaltern, der kunden-, benutzer- oder global-spezifisch hinterlegt werden kann.
- **SharedDocument**: Dokument-Entität, die im elektronischen Signaturprozess (C-Sign) als Basis-, Abrede-, Anrede- oder Signaturdatei verwendet wird; verhindert bei aktivem, unsigniertem Prozess das Löschen des zugrunde liegenden Dokuments.
- **ReportGroup/ReportData**: Grundstruktur der FastReport-basierten Reporting-Engine — `ReportGroup` bündelt Reports eines Belegtyps (z. B. Rechnung), `ReportData` ist der einzelne Report (FastReport-Definition, Base64-serialisiert) mit Parametern und Abfragen.
- **DMS-Sync**: Mechanismus zur Kennzeichnung, ob und wann ein `Document` in ein externes Dokumentenmanagementsystem synchronisiert wurde (Felder `DMSSyncUniqueID`, `DMSSyncDate`, `DMSSyncType`, `DMSSyncEmployeeI3D`).
- **State-Flag**: Wiederkehrendes Muster in mehreren Entitäten (Documentation, TextModule, ReportData), bei dem ein Integer-Feld `State` (0/1) Aktivierung bzw. logisches Löschen (Soft-Delete) abbildet, statt physischem Löschen.
@@ -0,0 +1,3 @@
- **SwRS-DOC-03** (S/MIME-Signaturprüfung bei archivierten E-Mail-Dokumenten): Unklar, ob die geloggte Warnung bei fehlgeschlagener S/MIME-Verifikation tatsächlich bis in die Benutzeroberfläche durchgereicht wird oder nur im Server-Log verbleibt — WPF-Client-Code wurde in diesem Cluster nicht geprüft.
- **SyRS-DOC-08** (Schnittstelle zu externem Drucker-Fleet-Management docuFORM): Kein Aufrufer/Consumer des `DocuFormRestApiClient` wurde in `Centron.BL` innerhalb des untersuchten Bereichs gefunden; Verwendungszweck (Abrechnung? Controlling?) und aufrufende Business-Logik sind unklar, ggf. in einem anderen Cluster (Administration/Gerätemanagement) verortet.
@@ -0,0 +1,37 @@
ID: StRS-DOC-01
Titel: Zentrale Dokumentenablage in Ordnerstruktur
Ebene: StRS
Typ: funktional (Geschäftsziel)
Akteur: Sachbearbeiter (Vertrieb/Verwaltung), Administrator
Vorbedingung: Benutzer ist an c-entron angemeldet und besitzt Zugriff auf einen Ordner (Directory)
Fakt: `DocumentBL.AddFileToDirectory` legt Dokumente in einer Ordnerstruktur (`Directory`) ab, verknüpft Metainformationen (`DocumentMetaInformation`), setzt einen Dokumenttyp-abhängigen Icon-Index (`GetImageIndexForDocumentType`) und aktualisiert die Trefferanzahl des Ordners (`NumDocuments`). Bei Helpdesk-Ordnern wird zusätzlich ein Historieneintrag erzeugt (`HelpdeskHistoryBL.CreateHistoryForDocument`).
Aussage: Das System soll es Sachbearbeitern ermöglichen, beliebige Dateien in einer hierarchischen Ordnerstruktur abzulegen, automatisch nach Dateityp zu kategorisieren (Icon/Typ) und bei fachlichem Bezug (z. B. Helpdesk-Vorgang) automatisch eine Historie zu führen.
Ergebnis: Zentrale, typisierte Dokumentenablage mit Prozessanbindung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:587-648 - Begründung: `AddFileToDirectory` Implementierung inkl. MetaInformations, ImageIndex, Historie.
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/Administration/FileManagement/Document.cs:17-54 - Begründung: Entity-Felder bestätigen Typ/Version/Directory-Modell.
Prüfidee: UI-Test: Datei in Kundenordner hochladen, prüfen ob Icon nach Dateityp korrekt vergeben wird und `NumDocuments` im Elternordner steigt.
Tracelinks: SyRS-DOC-01, SyRS-DOC-02, SyRS-DOC-03, SyRS-DOC-04
Konsolidierung: nein
Status: belegt
---
ID: StRS-DOC-02
Titel: Trennung öffentliche/interne Dokumentation
Ebene: StRS
Typ: funktional (Geschäftsziel)
Akteur: Sachbearbeiter (interne Dokumentation/Wissensdatenbank), Management
Vorbedingung: Benutzer hat Recht `READ_DOCUMENTATION` bzw. `READ_INTERNAL_DOCUMENTATION`
Fakt: `DocumentationBL` verwaltet fachliche „Dokumentationen" (z. B. zu Helpdesk-Vorgängen) mit zwei getrennten Sichtbarkeitsstufen: `PublicDocumentation` (immer sichtbar) und `InternalDocumentation` (wird aus dem Ergebnis entfernt, falls der Benutzer nicht das Recht `READ_INTERNAL_DOCUMENTATION` besitzt — in allen Get-Methoden konsequent per Schleife `documentation.InternalDocumentation = null`).
Aussage: Das System soll bei Wissens-/Vorgangsdokumentationen zwischen einer öffentlichen und einer nur intern sichtbaren Textkomponente unterscheiden und die interne Komponente rechteabhängig aus der Antwort entfernen (nicht nur UI-seitig ausblenden).
Ergebnis: Informationstrennung zwischen kundenseitig sichtbaren und internen Vermerken.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs:27-95 - Begründung: Mehrere GetDocumentation*-Methoden mit identischem Muster (Rechteprüfung + Entfernen von InternalDocumentation).
- [SEKUNDÄR] src/backend/Centron.Entities/Entities/DocumentationArea/Documentation.cs:19-23 - Begründung: Entity-Felder PublicDocumentation/InternalDocumentation.
Prüfidee: Dokumentation mit beiden Feldern anlegen, mit Benutzer ohne READ_INTERNAL_DOCUMENTATION abrufen → InternalDocumentation muss `null` sein, nicht nur UI-verborgen.
Tracelinks: keine direkte SyRS-Verknüpfung (Lücke - im Kandidatenset wurde keine SyRS-Ebene zur Dokumentations-Sichtbarkeit erhoben); fachlich direkt umgesetzt durch SwRS-DOC-05
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,239 @@
ID: SwRS-DOC-01
Titel: Append-Only-Versionierung von Dokumenten
Ebene: SwRS
Typ: Daten / nicht-funktional (Versionierung)
Akteur: System (automatisiert)
Vorbedingung: Dokument wird aktualisiert (UpdateDocument, CheckInDocument, AddNewDocumentVersion)
Fakt: Jede Dokumentaktualisierung erzeugt einen **neuen** `Document`-Datensatz mit inkrementierter `Version` (`document.Version + 1`) statt eines Updates des bestehenden Datensatzes; alle Versionen referenzieren über `OwnerDocument` den „Kopf"-Datensatz. `GetDocumentsFromDirectory` filtert pro `OwnerDocument`-Gruppe nur die jeweils neueste Version (`Max(f => f.Version)`).
Aussage: Das System soll Dokumentversionen unveränderlich (append-only) verwalten: jede neue Version ist ein eigener Datensatz, verknüpft über eine Ankerreferenz (OwnerDocument), wobei Standardlisten nur die aktuellste Version anzeigen.
Ergebnis: Nachvollziehbare Versionshistorie ohne Datenverlust.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:538-585 - Begründung: UpdateDocument-Methode, Erzeugung neues Document-Objekt mit Version+1.
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:94-112 - Begründung: GetDocumentsFromDirectory gruppiert nach OwnerDocument, wählt max. Version.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:843-876 - Begründung: AddNewDocumentVersion als expliziter Versionierungs-Endpunkt.
Prüfidee: Datei zweimal hochladen (gleicher Name/Ordner) → prüfen ob zwei Datensätze mit Version 1/2 und gemeinsamer OwnerDocument-Referenz entstehen.
Tracelinks: SyRS-DOC-01, StRS-DOC-01
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-02
Titel: Duplikaterkennung bei automatisch archivierten Beleg-PDFs
Ebene: SwRS
Typ: nicht-funktional (Performance/Datenintegrität)
Akteur: System (automatisiert)
Vorbedingung: Dokument (z. B. PDF eines Belegs) wird wiederholt exportiert/gedruckt
Fakt: `DocumentBL.GetIdenticalDocumentInDirectory` (referenziert Ticket 160276) prüft vor dem Speichern, ob im Zielordner bereits ein Dokument mit identischem Namen, identischer Version und identischer Dateigröße existiert, um mehrfaches Ablegen desselben Report-PDFs bei wiederholtem Druck/Export zu vermeiden.
Aussage: Das System soll beim automatischen Ablegen generierter Belegdokumente (z. B. Rechnungs-PDFs) Duplikate anhand von Name, Version und Dateigröße erkennen und vermeiden.
Ergebnis: Reduzierte Datenredundanz im Dokumentenarchiv.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:74-92 - Begründung: Methode inkl. Code-Kommentar mit Ticket-Referenz 160276.
Prüfidee: Denselben Beleg zweimal exportieren, prüfen ob nur ein Dokumentdatensatz im Zielordner entsteht.
Tracelinks: SyRS-DOC-05
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-03
Titel: S/MIME-Signaturprüfung bei archivierten E-Mail-Dokumenten
Ebene: SwRS
Typ: Sicherheit
Akteur: Sachbearbeiter, Administrator
Vorbedingung: Dokument (.msg/.eml) enthält S/MIME-Signatur
Fakt: `DocumentBL.GetMailDocumentFromEml` verifiziert bei signierten E-Mail-Anhängen (MultipartSigned/ApplicationPkcs7Mime) die S/MIME-Signatur über `TemporarySecureMimeContext`. Bei Fehlschlag der Verifikation wird nur eine Warnung geloggt (`Logger.Warn`), die Mail wird trotzdem unverifiziert angezeigt.
Aussage: Das System soll beim Anzeigen archivierter E-Mail-Dokumente (.eml) vorhandene S/MIME-Signaturen prüfen und dem Benutzer erkennbar machen, wenn die Signatur ungültig oder nicht verifizierbar ist.
Ergebnis: Vertrauenswürdigkeit archivierter E-Mail-Kommunikation.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:196-234 - Begründung: Verifikationslogik inkl. Warn-Logging bei Fehlschlag.
Prüfidee: Signierte E-Mail mit ungültiger Signatur importieren und im FileManagement öffnen — prüfen ob Warnhinweis im UI sichtbar ist (aktuell nur Log, kein UI-Hinweis erkennbar).
Tracelinks: StRS-DOC-01 (keine direkte SyRS-Verknüpfung - Lücke, im Kandidatenset keine SyRS zu Mail-Dokumentsicherheit erhoben)
Konsolidierung: nein
Status: HYPOTHESE (fehlende Information: Es ist im BL-Code nicht erkennbar, ob die Warnung tatsächlich bis in die UI durchgereicht wird oder nur im Server-Log verbleibt — WPF-Client-Code wurde in diesem Cluster nicht geprüft.)
---
ID: SwRS-DOC-04
Titel: Zeichensatzbereinigung von Dokumentnamen
Ebene: SwRS
Typ: Daten / Validierung
Akteur: System (automatisiert)
Vorbedingung: Dokumentname enthält Nicht-ASCII/Sonderzeichen
Fakt: `DocumentBL.SaveOrUpdateDocument` bereinigt den Dokumentnamen mit Regex `[^ -ÿ]+` (entfernt alle Zeichen außerhalb Latin-1), da die DB-Spalte `Name` als `varchar` (kein Unicode) definiert ist und laut Code-Kommentar "auf manchen DBs auch indiziert" ist und nicht mehr geändert werden kann.
Aussage: Das System soll beim Speichern eines Dokumentnamens Zeichen außerhalb des Latin-1-Zeichensatzes entfernen, um Beschädigungen durch die nicht-Unicode-fähige Datenbankspalte zu vermeiden.
Ergebnis: Verhinderung von Zeichensatzproblemen/Datenkorruption bei Dokumentnamen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:680-686 - Begründung: Code inkl. erklärendem Kommentar zur technischen Schuld.
Prüfidee: Datei mit z. B. kyrillischem oder emoji-haltigem Dateinamen hochladen, prüfen welche Zeichen im gespeicherten Namen verloren gehen.
Tracelinks: StRS-DOC-01 (keine direkte SyRS-Verknüpfung - Lücke)
Konsolidierung: nein (Migrationshinweis: Einschränkung ist technikbedingt/Legacy-DB-Schema und entfällt vermutlich bei Unicode-fähiger DB im Web/SaaS-Neubau)
Status: belegt; Workaround (Altlast wegen Legacy-DB-Schema)
---
ID: SwRS-DOC-05
Titel: Versions-Snapshot bei Änderung einer Dokumentation
Ebene: SwRS
Typ: Daten / Versionierung
Akteur: System (automatisiert)
Vorbedingung: Bestehende `Documentation` wird geändert (`isNew == false`)
Fakt: `DocumentationBL.DoBeforeStoreTrans` legt vor jeder Änderung einer bestehenden Documentation einen Snapshot als `DocumentationVersion` an (Caption, Category, ChangedBy/Date, CreatedBy/Date, State, Version, PublicDocumentation, InternalDocumentation etc.), inkl. TODO-Kommentar "ska 2013-02-20: temporary solution. We have to improve our logic to get the current application version." bei `ChangedVersion`.
Aussage: Das System soll bei jeder Änderung einer Dokumentation automatisch eine unveränderliche Versions-Kopie (Snapshot) mit Autor, Zeitstempel und Anwendungsversion erzeugen.
Ergebnis: Nachvollziehbare Änderungshistorie von Wissensdokumentationen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/DocumentationArea/DocumentationBL.cs:317-347 - Begründung: DoBeforeStoreTrans-Implementierung inkl. TODO-Kommentar zur unfertigen Versionsermittlung.
Prüfidee: Bestehende Dokumentation zweimal ändern, prüfen ob zwei DocumentationVersion-Datensätze mit korrekten Feldwerten entstehen.
Tracelinks: StRS-DOC-02 (keine direkte SyRS-Verknüpfung - Lücke)
Konsolidierung: Kandidat: SwRS-DOC-01 (analoges Append-Only-Versionierungsmuster wie bei Document, jedoch andere Entität „Documentation" — Vereinheitlichung im Neubau prüfen)
Status: belegt; Workaround (ChangedVersion-Ermittlung laut Code-Kommentar seit 2013 unvollständig gelöst)
---
ID: SwRS-DOC-06
Titel: PDF-Erzeugungsstrategie mit automatischem Fallback
Ebene: SwRS
Typ: funktional / Fehlerbehandlung
Akteur: System (automatisiert)
Vorbedingung: PDF-Erzeugung über alternativen PDF-Drucker (COM-Interface) schlägt fehl
Fakt: `PdfStrategies.GetPdfStrategy` wählt zwischen mehreren PDF-Erzeugungsstrategien (`DefaultPdfStrategy`, `PdfCreatorPdfStrategy`, `SevenPdfStrategy`, Fallback `FastReportPdfStrategy`) abhängig von Benutzereinstellungen. Schlägt eine alternative Strategie fehl, wird sie über `MarkStrategyAsFailed` für **30 Minuten** in einer statischen In-Memory-Dictionary (`_failedStrategies`) gesperrt; in diesem Zeitraum wird automatisch auf `FastReportPdfStrategy` zurückgefallen (`CreatePdf` in `ReportDataBL`). PDF/A-3-Pflicht (ZUGFeRD) wird nur unterstützt, wenn der gewählte Drucker `ExportsInPdfA3 == true` ist, sonst ebenfalls Fallback auf FastReport.
Aussage: Das System soll bei Fehlschlag eines konfigurierten alternativen PDF-Druckertreibers automatisch für einen Zeitraum von 30 Minuten auf eine interne Standard-PDF-Erzeugung (FastReport) ausweichen, um Reportdruck trotz Druckerfehler nicht zu blockieren.
Ergebnis: Ausfalltoleranz der PDF-Erzeugung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/PdfStategy/PdfStrategies.cs:23-157 - Begründung: Vollständige Strategie-Auswahl- und Fallback-/Circuit-Breaker-Logik inkl. 30-Minuten-Konstante.
- [SEKUNDÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1317-1345 - Begründung: CreatePdf nutzt Strategie, fängt Fehler ab und erzwingt Fallback FastReportPdfStrategy.
Prüfidee: Alternativen PDF-Drucker simuliert nicht verfügbar machen, prüfen ob nach Fehlschlag automatisch FastReport verwendet wird und ob nach 30 Minuten erneut versucht wird.
Tracelinks: SyRS-DOC-05, SyRS-DOC-06
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-07
Titel: Erkennung zyklischer Report-Query-Abhängigkeiten
Ebene: SwRS
Typ: funktional / Datenintegrität
Akteur: Administrator (Reportentwicklung)
Vorbedingung: ReportData-Query-Kette mit `SuperQuery`-Verweisen
Fakt: `ReportDataBL.HasQueryLoop` erkennt zyklische Abhängigkeiten zwischen `ReportDataQuery`-Objekten (über `SuperQuery`-Referenzen) mittels iterativem Erreichbarkeits-Algorithmus. Bei erkannter Schleife bricht `Register()` mit Fehlermeldung „Loop detected in ReportData: '<Name>'" ab, bevor irgendeine Query ausgeführt wird.
Aussage: Das System soll bei der Registrierung eines Reports zyklische Abhängigkeiten zwischen verketteten Unterabfragen (Query-Chains) erkennen und die Reportausführung mit einer Fehlermeldung verhindern.
Ergebnis: Schutz vor Endlosschleifen/Fehlausführung bei fehlerhaft konfigurierten Reports.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:969-985 - Begründung: HasQueryLoop-Implementierung.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:626-633 - Begründung: Aufruf und Fehlerabbruch in Register().
Prüfidee: Zwei ReportDataQuery-Objekte mit sich gegenseitig referenzierendem SuperQuery anlegen und Reportausführung testen.
Tracelinks: SyRS-DOC-05
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-08
Titel: Automatischer Abgleich von Reportparametern bei Report-Änderung
Ebene: SwRS
Typ: funktional (Diff/Migration von Parametern)
Akteur: Administrator (Reportentwicklung)
Vorbedingung: Ein im Report-Designer geänderter Report (`ReportData.ReportBase64`) wird gespeichert (`UpdateFastreport`)
Fakt: `ReportDataBL.CheckReportDataParameters` vergleicht die FastReport-Parameterliste des alten und neuen Reports (Name, Typ, Expression, Description). Parameter, die im Namen fehlen oder deren Typ sich geändert hat, werden aus `ReportDataParameters` gelöscht (`DeleteFRParameters`); neue/geänderte werden für alle betroffenen `ReportGroupsToReportData`-Zuordnungen neu angelegt (`AddFRParameters`); reine Beschreibungsänderungen werden aktualisiert (`UpdateFRParametgers`, Methode-Name enthält Tippfehler im Original).
Aussage: Das System soll beim Speichern eines geänderten Reports automatisch erkennen, welche benutzerdefinierten Reportparameter entfernt, neu hinzugefügt oder nur in der Beschreibung geändert wurden, und die zugehörigen Parameter-Konfigurationsdatensätze je Gruppenzuordnung entsprechend synchronisieren.
Ergebnis: Konsistente Parameterkonfiguration nach Report-Design-Änderungen ohne manuellen Abgleich.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1172-1249 - Begründung: CheckReportDataParameters + UpdateFastreport, inkl. Diff-Logik für Name/Typ/Description.
Prüfidee: Parameter in FastReport-Designer umbenennen/Typ ändern, Report speichern, prüfen ob ReportDataParameters-Tabelle korrekt aktualisiert wird.
Tracelinks: SyRS-DOC-09
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-09
Titel: Katalog der Textbaustein-Typen je Belegart
Ebene: SwRS
Typ: Daten / Konfiguration
Akteur: Sachbearbeiter, Administrator
Vorbedingung: -
Fakt: `TextModuleType` (Enum in `Centron.WebServices.Core`) definiert für jeden Belegtyp (Angebot, Auftrag, Lieferschein, Abholschein, Rechnung, Gutschrift) je eine „Anrede" (AN_*) und „Abrede" (AB_*) Variante, zusätzlich Mahnstufen (AP_MAHNUNG1-3), Helpdesk-Textbausteine getrennt nach intern/extern/andere (je Anrede/Abrede), sowie Prozess-Mailtexte für Anfrage, Bestellung, Wareneingang, Kalkulation, Rücksendung, Angebot, Auftrag, Lieferschein, Abholschein, Rechnung, Gutschrift, OPOS, Lieferantengutschrift (Präfix AP_).
Aussage: Das System soll für jeden relevanten Belegtyp und Kommunikationsanlass einen eigenen, konfigurierbaren Textbaustein-Typ vorsehen (mind. 30 unterschiedliche Verwendungszwecke), getrennt nach Anrede/Abrede bzw. reinem Prozesstext.
Ergebnis: Feingranulare Steuerung der Standardtexte je Geschäftsvorfall.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:75-155 - Begründung: Vollständige Aufzählung aller TextModuleType-Werte in GetFilteredTextModuleList.
- [KONTEXT] src/webservice/Centron.WebServices.Core/EntitiesWrongPlace/TextModuleArea/TextModuleType.cs - Begründung: Enum-Definition selbst (Datei lokalisiert, Inhalt in diesem Lauf nicht mehr im Detail gelesen).
Prüfidee: Katalog aller TextModuleType-Werte aus der Enum-Datei extrahieren und mit Fachbereich abgleichen, welche im Web-Redesign noch benötigt werden.
Tracelinks: SyRS-DOC-07
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-10
Titel: Platzhalterersetzung in Text- und RTF-Textbausteinen
Ebene: SwRS
Typ: funktional (Platzhalterlogik)
Akteur: System (automatisiert)
Vorbedingung: Textbaustein wird in Beleg/Mail eingefügt (Anrede/Abrede)
Fakt: `ReplacementBL.ReplaceVariables` ersetzt Platzhalter in Klartext sowie – bei erkanntem RTF-Format (`source.IsRtf()`) – direkt im RTF-Dokumentmodell (`RichEditDocumentServer`), inkl. Ersetzung in Hyperlink-Zielen (`hyperLink.NavigateUri`). Es gibt einen Fast-Path: Enthält der Text den Platzhalter-Bezeichner nicht, wird keine Ersetzung durchgeführt.
Aussage: Das System soll Platzhalter sowohl in Klartext- als auch in RTF-formatierten Textbausteinen (inkl. in Hyperlinks) ersetzen können, ohne die RTF-Formatierung zu zerstören.
Ergebnis: Konsistente Platzhalterersetzung unabhängig vom Textformat.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Core/ReplacementBL.cs:39-96 - Begründung: Vollständige Implementierung inkl. RTF-Sonderpfad und Hyperlink-Behandlung.
Prüfidee: RTF-Textbaustein mit Platzhalter in einem Hyperlink anlegen (z. B. `mailto:@@KdEMail@@`), Ersetzung prüfen.
Tracelinks: SyRS-DOC-07
Konsolidierung: nein (Grundlage für SwRS-DOC-11, keine Funktionsduplikat)
Status: belegt
---
ID: SwRS-DOC-11
Titel: Platzhalterkatalog für Anrede/Abrede-Textbausteine
Ebene: SwRS
Typ: Daten (Platzhalterkatalog)
Akteur: Sachbearbeiter
Vorbedingung: Anrede-/Abrede-Textbaustein wird für einen Kundenauftrag/-anlage aufbereitet
Fakt: `SalutationAndAgreementReplacementBL.ReplaceSalutationAndAgreement` definiert einen Katalog von >45 Platzhaltern im Format `@@Bezeichner@@` (z. B. `@@KdNummer@@`, `@@KdName@@`, `@@AnsprechVorname@@`, `@@BearbeiterEMail@@`, `@@VertriebsgebietKurz@@`), wobei viele Platzhalter mit Suffix „2"/„3" (`AddSameAsLast`) denselben Wert für mehrfach vorkommende Platzhalter im selben Text bereitstellen. Werte werden aus Kunde, Adresse, Ansprechpartner, Vertriebsgebiet und Bearbeiter (Editor) sowie zugeordnetem Mitarbeiter (Adviser1) gezogen; leere/fehlende Referenzen liefern Leerstring statt Fehler.
Aussage: Das System soll einen festen, dokumentierten Katalog von Platzhaltern für Kunden-, Kontakt-, Vertriebsgebiets- und Bearbeiterdaten bereitstellen, mehrfaches Vorkommen desselben Platzhalters im Text unterstützen und bei fehlenden Referenzdaten robust mit Leerwerten statt Fehlern reagieren.
Ergebnis: Wiederverwendbare, ausfallsichere Personalisierung von Textbausteinen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/SalutationAndAgreementReplacementBL.cs:40-215 - Begründung: Vollständiger Platzhalterkatalog mit Datenquellen.
- [SEKUNDÄR] src/backend/Centron.BL/TextModuleArea/SalutationAndAgreementReplacementBL.cs:224-326 - Begründung: GetFrom*-Hilfsmethoden zeigen einheitliches Null-safe-Muster (Leerstring bei fehlender Referenz).
Prüfidee: Kundenanlage ohne hinterlegten Ansprechpartner verwenden, prüfen ob `@@AnsprechVorname@@` als Leerstring statt Exception im Ergebnistext erscheint.
Tracelinks: SyRS-DOC-07
Konsolidierung: nein (ergänzt SwRS-DOC-10 zur vollständigen Platzhalterlogik, keine Duplikat-Funktion)
Status: belegt
---
ID: SwRS-DOC-12
Titel: Kunden-/Lieferanten-spezifische Mail-Platzhalter
Ebene: SwRS
Typ: funktional / Mail-Integration
Akteur: Sachbearbeiter
Vorbedingung: Beleg (Angebot, Auftrag, Rechnung etc.) wird per E-Mail versendet
Fakt: `TextModuleBL.ReplaceReceiptMailVariables` unterscheidet über `receipt.GetAccount()` (Pattern-Matching auf `IsCustomer`), ob der Beleg einen Kunden- oder Lieferantenbezug hat, und nutzt entsprechend unterschiedliche Platzhaltersätze (`ReplaceCustomerTextBlockVariables` via `MailTextBlockRepository.GetCustomerTextBlockVariables` inkl. `MailTrackingDTO`-Einstellungen, bzw. `ReplaceMailSupplierVariables` via `GetSupplierTextBlockVariables`). Der Kontakt für die Mail wird über `SpecificLogics.Execute(receipt, f => f.GetContactForMail(receipt))` ermittelt.
Aussage: Das System soll bei E-Mail-Versand eines Belegs automatisch erkennen, ob es sich um einen Kunden- oder Lieferantenvorgang handelt, und den jeweils passenden Platzhaltersatz inkl. Mail-Tracking-Konfiguration anwenden.
Ergebnis: Korrekte Personalisierung unabhängig von Belegrichtung (Verkauf/Einkauf).
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:510-529 - Begründung: ReplaceReceiptMailVariables mit Pattern-Matching auf Account-Typ.
Prüfidee: Lieferantenbestellung und Kundenangebot jeweils per Mail versenden, prüfen ob korrekte Platzhaltergruppe angewendet wird.
Tracelinks: SyRS-DOC-07
Konsolidierung: nein
Status: belegt
---
ID: SwRS-DOC-13
Titel: Konfigurierbare Druckparameter je Report
Ebene: SwRS
Typ: funktional (Druckparameter)
Akteur: Sachbearbeiter
Vorbedingung: Report wird gedruckt (nicht nur exportiert)
Fakt: `ReportDataBL.ConvertToSetting` bildet aus `ReportDataSettings`/`ReportDataBinSettings` ein `ReportPrintSettingDTO` mit granularen Druckparametern: Collate (Sortiert drucken), Duplex, Druckername, Farbdruck, Fax-Flag, Papierschacht (`PaperSourceRawKind`), Papierformat (`PaperSizeRawKind`), Kopienanzahl, Querformat, "Druckdialog anzeigen", "Druckereinstellungen verwenden", Skalierung, Seitengrößen-Art.
Aussage: Das System soll je Report und Reportgruppe granulare, persistente Druckeinstellungen (Papierschacht, Papierformat, Duplex, Farbe, Kopienanzahl, Skalierung, Sortierung, Querformat) verwalten können, die beim Drucken automatisch angewendet werden.
Ergebnis: Wiederholbare, konfigurierbare Druckausgabe ohne manuelle Neueinstellung je Druckvorgang.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1055-1075 - Begründung: ConvertToSetting-Mapping aller Druckparameter.
Prüfidee: Druckeinstellungen (z. B. Duplex + Schacht 2) für eine Reportgruppe konfigurieren, Druckvorgang auslösen und physische/simulierte Druckerparameter verifizieren.
Tracelinks: SyRS-DOC-05
Konsolidierung: nein
Status: belegt
@@ -0,0 +1,170 @@
ID: SyRS-DOC-01
Titel: Check-out/Check-in-Sperrmechanismus für Dokumente
Ebene: SyRS
Typ: funktional
Akteur: Sachbearbeiter
Vorbedingung: Dokument existiert bereits (documentI3D > 0)
Fakt: `DocumentBL.CheckOutDocument`/`CheckInDocument`/`UndoCheckOut` implementieren ein Sperr-(Lock-)Konzept über `LockedBy` (Employee), `LockedByWorkstation`, `LockedFilePath`. `CanCheckOutDocument` verweigert das Auschecken, wenn bereits gesperrt. `UpdateDocument` verweigert ein Update, wenn das Dokument von einem anderen Benutzer gesperrt ist (`document.LockedBy != currentUser.User.Employee` → return null, kein Fehlertext).
Aussage: Das System soll ein Check-out/Check-in-Verfahren für Dokumente bereitstellen, das gleichzeitige Bearbeitung durch mehrere Benutzer durch eine Sperre (Employee, Workstation, Dateipfad) verhindert.
Ergebnis: Kollisionsfreie kollaborative Dokumentbearbeitung.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:878-951 - Begründung: CanCheckOutDocument/CheckOutDocument/CheckInDocument/UndoCheckOut.
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:538-585 - Begründung: UpdateDocument prüft Sperre vor Änderung, gibt bei Fremdsperre `null` zurück (kein sprechender Fehlercode).
Prüfidee: Zwei parallele Sessions: Benutzer A checkt aus, Benutzer B versucht Update → erwartete Ablehnung.
Tracelinks: StRS-DOC-01
Konsolidierung: nein
Status: belegt; Workaround (UpdateDocument liefert bei Sperre `null` statt Fehlermeldung/Result-Objekt — inkonsistent zum übrigen Result-Pattern)
---
ID: SyRS-DOC-02
Titel: Löschsperre bei aktivem Signierprozess
Ebene: SyRS
Typ: Sicherheit
Akteur: Sachbearbeiter, Administrator
Vorbedingung: Löschversuch eines Dokuments
Fakt: `DocumentBL.CanDeleteDocument` verhindert das Löschen eines Dokuments, wenn es (a) in einem aktiven, noch nicht abgeschlossenen elektronischen Signierprozess (`SharedDocument`, `IsSigned == false`, nicht abgelaufen) als Basis-, Abrede-, Anrede- oder Signaturdatei verwendet wird, oder (b) in den globalen Einstellungen (`AppSettingsGroupBL.GetSharedDocumentSettings`) als Standard-Abrede/-Anrede/-Signatur für einen der sechs Belegtypen (Angebot, Auftrag, Lieferschein, Abholschein, Rechnung, Gutschrift, Vertrag) hinterlegt ist. Jeder Fall liefert eine spezifische deutsche Fehlermeldung mit `DefaultMessageCodes.DocumentInActiveSigningProcess` bzw. `.ErrorMessage`.
Aussage: Das System soll das Löschen von Dokumenten verhindern, solange diese in einem laufenden elektronischen Unterschriftsprozess referenziert oder als Systemvorlage für Signaturprozesse konfiguriert sind, und dem Benutzer den konkreten Verwendungszweck als Fehlermeldung mitteilen.
Ergebnis: Schutz vor Datenverlust bei referenzierten Vorlagen/aktiven Rechtsvorgängen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:425-536 - Begründung: Vollständige CanDeleteDocument-Logik mit allen Fehlermeldungstexten.
Prüfidee: Dokument, das als Signatur-Einstellung für Rechnungen hinterlegt ist, löschen → erwartete Fehlermeldung "...als Signatur für den Signierungs-Prozess für Rechnungen eingestellt".
Tracelinks: StRS-DOC-01
Konsolidierung: nein (Hinweis: mögliche fachliche Überschneidung mit Cluster „C-Sign/Signierprozesse" (SharedDocument) — dort ggf. tiefergehend behandelt; clusterübergreifende Prüfung erfolgt zentral)
Status: belegt
---
ID: SyRS-DOC-03
Titel: Lizenzpflichtige Volltextindizierung von Dokumenten
Ebene: SyRS
Typ: funktional / Lizenzierung
Akteur: Sachbearbeiter
Vorbedingung: Lizenz "c-entron Office" (`LicenseGuids.DocumentProcessing`) vorhanden
Fakt: Volltextindizierung von Dokumenten (`CreateIndexesForDocument`) ist an eine Lizenzprüfung gebunden (`LicenseManager.Instance.HasLicense(LicenseGuids.DocumentProcessing)`); ohne Lizenz liefert die Methode Fehler „Lizenz für c-entron Office nicht vorhanden". Unterstützte Formate: .txt, .rtf, .docx, .pdf, .html, .doc, .msg, .eml (via DevExpress RichEdit/Pdf sowie MsgReader). Nicht erkannte Dateitypen erhalten keinen Index (`Result<int>.AsSuccess(-1)`).
Aussage: Das System soll Dokumente lizenzabhängig automatisch volltextindizieren (Formate: TXT, RTF, DOC/DOCX, PDF, HTML, MSG, EML) und bei fehlender Lizenz die Indizierung mit einer eindeutigen Fehlermeldung verweigern.
Ergebnis: Volltextsuche über Dokumentinhalte als lizenzpflichtiges Zusatzmodul.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:1122-1199 - Begründung: CreateIndexesForDocument mit Lizenzprüfung und Format-Switch.
- [SEKUNDÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:689-708 - Begründung: SaveOrUpdateDocument löst Indizierung synchron oder asynchron (je nach Einstellung `IsDocumentGenerateFulltextIndexAsyncActive`) nach jedem Speichern aus.
Prüfidee: Ohne Lizenz ein Dokument hochladen und Volltextsuche versuchen → erwartete Fehlermeldung; mit Lizenz PDF-Inhalt suchen.
Tracelinks: StRS-DOC-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-DOC-04
Titel: Rechteabhängige paginierte Dokumentensuche
Ebene: SyRS
Typ: funktional
Akteur: Sachbearbeiter
Vorbedingung: Benutzer hat Recht `RIGHT_DOCUMENTFILEREAD`
Fakt: `DocumentBL.SearchDocumentsThroughPaging` prüft zunächst das Benutzerrecht, unterstützt eine Sonderform `id:<Zahl>` für direkte I3D-Suche, kombiniert bei Volltextsuche pro Suchwort Indextreffer (nur Dokumente, die **alle** Suchwörter enthalten, mit Fallback auf Dokumente mit mind. einem Treffer) und begrenzt Ergebnisse aus Performancegründen hart auf 2000 Dokument-IDs sowie ein SQL-Timeout von 30 Sekunden.
Aussage: Das System soll eine rechteabhängige, paginierte Dokumentensuche mit Volltext- und Attributfiltern (Name, Typ, Größe, Ersteller, Datum) bereitstellen, wobei die Volltextsuche auf maximal 2000 Treffer-IDs begrenzt ist und Anfragen nach 30 Sekunden abgebrochen werden.
Ergebnis: Performante, rechtegeschützte Dokumentensuche auch bei großen Archiven.
Belege:
- [PRIMÄR] src/backend/Centron.BL/Administration/FileManagement/DocumentBL.cs:953-1118 - Begründung: SearchDocumentsThroughPaging + CreateFilterExpression inkl. Rechteprüfung, ID-Suche, 2000er-Limit, 30s-Timeout.
Prüfidee: Suche ohne Recht `RIGHT_DOCUMENTFILEREAD` ausführen → erwartete Fehlermeldung "Sie haben kein Recht, Dokumente zu lesen".
Tracelinks: StRS-DOC-01
Konsolidierung: nein
Status: belegt
---
ID: SyRS-DOC-05
Titel: Automatische PDF-Archivierung mit Platzhalter-Dateinamen
Ebene: SyRS
Typ: funktional
Akteur: System (automatisiert), Sachbearbeiter
Vorbedingung: Report wird aus einer Reportgruppe (z. B. Angebot, Rechnung) erzeugt
Fakt: `ReportDataBL.ConvertReportToPdfStream` archiviert das erzeugte PDF automatisch über `ArchivePdf`, außer (a) für die Gruppen Rechnung/Gutschrift (dort erfolgt Archivierung separat/anders), (b) `group.PDFExportActive == false`, (c) `ignoreReportGroupExport == true` (z. B. bei Vorschau), (d) Parameter `@NoPdfExport == "1"` oder `@Vorschau == "1"` gesetzt ist. Bei aktivierter Gruppe mit `CustomExportFilename` wird der Dateiname über `ReportGroupBL.GetExportFilename`/`PdfExportFilenameReplacementBL` anhand von Platzhaltern (Belegnummer, Version, Kundennummer, Datum) generiert.
Aussage: Das System soll erzeugte Belegreports (PDF) automatisch im Dokumentenarchiv ablegen, sofern die Reportgruppe dies erlaubt und es sich nicht um eine Vorschau handelt, wobei der Archiv-Dateiname über ein konfigurierbares Platzhalterschema (Nummer/Version/Kunde/Datum) gebildet wird.
Ergebnis: Automatische, konfigurierbare Belegarchivierung ohne Benutzerinteraktion.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1289-1420 (ConvertReportToPdfStream/ArchivePdf) - Begründung: Bedingungslogik für Archivierung inkl. Parameter-Flags.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportGroupBL.cs:46-132 - Begründung: GetExportFilename mit Belegarten-Mapping und Platzhalter-Dateinamen.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReplacementBLs/PdfExportFilenameReplacementBL.cs:17-58 - Begründung: Platzhalter-Konstanten (NUMBER, VERSION, CUSTOMER_ID, DATE) inkl. Regex-Rückwandlung für Dateisuche.
Prüfidee: Angebot mit aktivierter PDF-Archivierung und benutzerdefiniertem Dateinamensschema drucken; prüfen ob Datei mit erwartetem Muster im Kundendokumentenordner abgelegt wird.
Tracelinks: keine direkte StRS-Verknüpfung (Lücke - im Kandidatenset wurde kein StRS-Geschäftsziel zu Reporting erhoben)
Konsolidierung: nein (Hinweis: Sonderbehandlung Rechnung/Gutschrift ggf. eigenständig geregelt, vgl. SyRS-DOC-06 ZUGFeRD/GoBD-Pflichtarchivierung)
Status: belegt
---
ID: SyRS-DOC-06
Titel: ZUGFeRD/PDF-A-3b-Pflicht für Rechnungsdokumente
Ebene: SyRS
Typ: Daten / Compliance
Akteur: Buchhaltung, System (automatisiert)
Vorbedingung: Reportgruppe = Rechnung (GUID `23EC705E-3C04-4B8F-AAB9-0C06C0C80759`), ZUGFeRD aktiviert
Fakt: `ReportDataBL.GetReportForPrinting`/`ConvertReportToPdfStream` prüft für die Rechnungsgruppe (`ReportGroupConstants.RECHNUNG`) über `InvoiceZugferdBL.IsZugferdEnabled()`, ob PDF/A-3b-Konformität (`requiresPdfA3`) erforderlich ist. `CustomZugferdPdfGenerator` registriert die Rechnungsgruppe als Ziel für einen speziellen ZUGFeRD-PDF-Generator. `PdfExportSettingsBL.ApplyPdfExportSettings` erzwingt bei PDF/A-3 fest `PdfCompliance = PdfA_3b` und `EmbeddingFonts = true` (nicht konfigurierbar), während Farbraum/Kompression/JPEG-Komprimierung konfigurierbar bleiben.
Aussage: Das System soll Rechnungsdokumente bei aktivierter ZUGFeRD-Funktion zwingend als PDF/A-3b mit eingebetteten Schriften erzeugen (E-Rechnungs-Konformität), unabhängig von den sonst konfigurierbaren PDF-Exporteinstellungen.
Ergebnis: Rechtskonforme elektronische Rechnungsstellung (ZUGFeRD/PDF-A3).
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:1012-1020 - Begründung: requiresPdfA3 wird aus IsZugferdEnabled() für die Rechnungsgruppe abgeleitet.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/PdfExport/PdfExportSettingsBL.cs:169-216 - Begründung: ApplyPdfExportSettings erzwingt PdfA_3b + EmbeddingFonts bei requiresPdfA3.
- [SEKUNDÄR] src/backend/Centron.BL/ReportEngine/CustomPdfGenerators/CustomZugferdPdfGenerator.cs:1-18 - Begründung: Feste GUID-Zuordnung Rechnungsgruppe → ZUGFeRD-Generator.
Prüfidee: Rechnung mit aktivierter ZUGFeRD-Einstellung drucken, PDF/A-3b-Konformität des Ergebnisses technisch validieren (z. B. veraPDF).
Tracelinks: keine direkte StRS-Verknüpfung (Lücke - im Kandidatenset wurde kein StRS-Geschäftsziel zu Reporting/Rechnungswesen erhoben)
Konsolidierung: nein (Hinweis: mögliche Überschneidung mit Cluster „Rechnungswesen/EDI" (ZugferdExportItem, InvoiceZugferdBL) — dort vermutlich tiefer behandelt; clusterübergreifende Prüfung erfolgt zentral)
Status: belegt
---
ID: SyRS-DOC-07
Titel: Dreistufige Priorisierung von Textbausteinen
Ebene: SyRS
Typ: funktional
Akteur: Sachbearbeiter (Angebot/Auftrag/Rechnung/Mahnung/Helpdesk)
Vorbedingung: Beleg wird per Mail versendet oder gedruckt, TextModule vom Typ „Anrede"/„Abrede" wird benötigt
Fakt: `TextModuleBL.GetTextModule(int,int,TextModuleType)` löst Textbausteine nach einer festen Prioritätsreihenfolge auf: 1) kundenspezifischer, aktiver Textbaustein (`CustomerI3D` passend, `State==1`, kleinste I3D bei Mehrfachtreffern), 2) benutzerspezifischer aktiver Textbaustein (`UserI3D` passend, größte I3D), 3) globaler Standard-Textbaustein (`CustomerI3D==0 && UserI3D==0`, größte I3D). Kommentare im Code verweisen auf Delphi-Kompatibilität der Sortierreihenfolge.
Aussage: Das System soll beim Ermitteln von Anrede-/Abrede-Textbausteinen eine dreistufige Priorität anwenden: kundenspezifisch vor benutzerspezifisch vor global, wobei bei Mehrfachtreffern eine dokumentierte, altsystem-kompatible Sortierregel (älteste vs. neueste I3D) gilt.
Ergebnis: Konsistente, personalisierbare Standardtexte in Belegen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/TextModuleArea/TextModuleBL.cs:396-418 - Begründung: GetTextModule-Implementierung mit expliziten Kommentaren zur Delphi-Kompatibilität der Sortierung.
Prüfidee: Für denselben TextModuleType je einen kunden-, benutzer- und globalen Textbaustein anlegen, prüfen ob der kundenspezifische priorisiert wird.
Tracelinks: keine direkte StRS-Verknüpfung (Lücke - im Kandidatenset wurde kein StRS-Geschäftsziel zu Textbausteinen erhoben)
Konsolidierung: nein
Status: belegt
---
ID: SyRS-DOC-08
Titel: Schnittstelle zu externem Drucker-Fleet-Management (docuFORM)
Ebene: SyRS
Typ: Schnittstelle
Akteur: System (automatisiert), Administrator (Gerätepark/Drucker)
Vorbedingung: Externer docuFORM-Server (Multifunktionsdrucker-Fleet-Management) konfiguriert, OAuth2-Zugangsdaten vorhanden
Fakt: `Centron.Api.docuFORM` ist entgegen des generischen Namens **kein Dokumentengenerierungs-API**, sondern ein REST-Client für ein externes Drucker-/Multifunktionsgeräte-Fleet-Management-System („docuFORM"): Endpunkte für OAuth2-Autorisierung (`/auth/v2/token`, `/auth/v2/authorize`), Geräteliste (`/dfmserver/v2/devices`) und Zählerstände pro Gerät (`/dfmserver/v2/devices/{id}/counters`, optional mit UTC-Datum).
Aussage: Das System soll über eine dedizierte REST-Schnittstelle (OAuth2, Client Credentials/Auth Code) Gerätestammdaten und Zählerstände (Seiten-/Kopierzähler) eines externen Drucker-Fleet-Management-Systems abrufen können.
Ergebnis: Integration von Druck-/Kopierzählern (vermutlich für Abrechnung/Controlling) externer MFP-Flotten.
Belege:
- [PRIMÄR] Centron.Api.docuFORM/DocuFormRestApiClient.cs:1-131 - Begründung: Vollständige Client-Implementierung inkl. Auth-Flow und Device/Counter-Endpunkten.
- [PRIMÄR] Centron.Api.docuFORM/DocuFormRestApiConstants.cs:1-15 - Begründung: Endpunkt-Konstanten bestätigen Domäne „dfmserver" (Device Fleet Management).
- [SEKUNDÄR] Centron.Api.docuFORM/IDocuFormApiClient.cs:1-21 - Begründung: Interface bestätigt Methodenumfang (RequestAuthorization, RequestToken, GetAllDevices, GetDeviceCounters).
Prüfidee: Mit Fachbereich klären, wofür Gerätezählerstände in c-entron verwendet werden (Leasingabrechnung? Verbrauchsmaterial-Controlling?) — im BL-Code dieses Clusters kein Aufrufer dieser Schnittstelle gefunden.
Tracelinks: keine direkte StRS-Verknüpfung (Lücke - kein Aufrufer/Geschäftsziel im untersuchten Bereich identifiziert)
Konsolidierung: nein
Status: HYPOTHESE (fehlende Information: Kein Aufrufer/Consumer dieses API-Clients wurde in `Centron.BL` innerhalb des untersuchten Bereichs gefunden; Verwendungszweck und aufrufende Business-Logik sind unklar. Ggf. anderes Cluster — Administration/Gerätemanagement — zuständig.)
---
ID: SyRS-DOC-09
Titel: Zustandsverwaltung bei Report-Aktivierung/-Deaktivierung
Ebene: SyRS
Typ: funktional (Zustandsautomat)
Akteur: Administrator (Reportverwaltung)
Vorbedingung: Report ist einer oder mehreren Reportgruppen zugeordnet
Fakt: `ReportDataBL.SetActivity` (zwei Überladungen) verwaltet den Aktivierungszustand eines Reports (`ReportData.State`, `ReportGroupsToReportData.State`) sowohl global als auch pro Gruppe. Beim Deaktivieren werden alle Standard-Zuweisungen entfernt (`ReportDataDefaultBL.RemoveAllDefaults`); wird ein Report in einer Gruppe als einziger aktiver Report aktiviert, wird er automatisch als Standard für Fax, Mail und Druck gesetzt (`SetDefault(..., ReportDefaultType.Fax/Mail/Print)`). `SetReportDeactivated` entfernt zusätzlich beim letzten Report einer Gruppe alle `ReportDataDefault`-Einträge und referenzierende `AccountPrintOption`/`VertragsArt.C2ReportI3D`-Verknüpfungen (`RemoveReportReferences`).
Aussage: Das System soll beim Aktivieren/Deaktivieren eines Reports innerhalb einer Reportgruppe automatisch dessen Standard-Zuordnungen (Druck/Mail/Fax) sowie abhängige Kunden-/Vertragsart-Verknüpfungen konsistent nachführen, insbesondere wenn es sich um den letzten aktiven Report einer Gruppe handelt.
Ergebnis: Widerspruchsfreie Standardreport-Konfiguration ohne verwaiste Referenzen.
Belege:
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:303-326 - Begründung: SetActivity(ReportData, bool) mit automatischer Default-Zuweisung.
- [PRIMÄR] src/backend/Centron.BL/ReportEngine/ReportDataBL.cs:507-583 - Begründung: RemoveReportReferences/SetReportDeactivated inkl. Bereinigung AccountPrintOption und VertragsArt.C2ReportI3D.
Prüfidee: Letzten aktiven Report einer Gruppe deaktivieren, prüfen ob zugehörige AccountPrintOption-Einträge sowie ReportDataDefault-Einträge entfernt werden.
Tracelinks: keine direkte StRS-Verknüpfung (Lücke - im Kandidatenset wurde kein StRS-Geschäftsziel zu Reporting erhoben)
Konsolidierung: nein
Status: belegt

Some files were not shown because too many files have changed in this diff Show More