Updated PHASENPLAN.md and ROADMAP.md to reflect the new feature order, making "ExtractSwissQrCode" Feature 2 and renumbering previous Features 2-5 to 3-6. Added detailed steps, endpoints, and acceptance criteria for the new feature. Implemented `ISwissQrCodeProcessor` interface with `DevExpressSwissQrCodeProcessor` for extracting and parsing Swiss QR Codes using DevExpress and Codecrete libraries. Registered the new service in DependencyInjection.cs. Introduced `SwissQrCodeData` value object and `SwissQrCodeNotFoundException` for domain modeling and error handling. Updated project dependencies to include libraries for QR code processing. Adjusted existing feature descriptions and steps to align with the new feature order.
32 KiB
?? DocumentOperator - Project Roadmap (Feature-Driven Development)
Last Updated: 17.01.2025 | Status: In Development | Current Feature: Feature 1 - ValidatePDF ? ABGESCHLOSSEN!
?? NEW APPROACH: Feature-by-Feature Development
Was hat sich geändert?
? Feature-Driven Development statt Layer-by-Layer
- Jedes Feature wird KOMPLETT umgesetzt (Domain ? Infrastructure ? Application ? API ? Tests ? Swagger)
- Feature ist erst "DONE" wenn es im Swagger testbar ist
- Dann nächstes Feature
? Kleine Schritte (1 Layer pro Step)
- Besser überschaubar
- Weniger Merge-Konflikte
- Schnelleres Feedback
? Multi-Tenancy & Cross-Cutting Concerns später
- Erst alle synchronen Features implementieren
- Dann Multi-Tenancy für ALLE Endpoints (kein Wiederholungsaufwand!)
- Dann Health Checks, Polly, Logging (einmal für alle!)
?? TABLE OF CONTENTS
- Feature Roadmap
- Project Overview
- Architecture & Design Decisions
- Technology Stack
- Project Structure
- Testing Strategy
- Current Status
- Key Learnings & Decisions
?? FEATURE ROADMAP
?? Feature Overview
| Feature | Type | Status | Swagger Testbar? |
|---|---|---|---|
| 1. ValidatePDF | Synchron | ? Abgeschlossen | ? |
| 2. ExtractSwissQrCode | Synchron | ? In Progress | ? |
| 3. ExtractAttachments | Synchron | ? Pending | ? |
| 4. ApplyStamp | Synchron | ? Pending | ? |
| 5. EmbedCertificate | Synchron | ? Pending | ? |
| 6. ConcatenatePDFs | Asynchron | ? Pending | ? |
?? Cross-Cutting Concerns (nach Features 1-4)
| Concern | Status |
|---|---|
| Multi-Tenancy (X-API-Key Header) | ? Pending |
| Health Checks (/health Endpoint) | ? Pending |
| Polly Resilience (Retry, Circuit Breaker) | ? Pending |
| Logging & Monitoring (Correlation IDs, Seq) | ? Pending |
?? FEATURE 1: ValidatePDF (Synchron) - In Progress
Was macht dieses Feature?
- Client sendet PDF als Base64 (JSON)
- API validiert PDF
- API gibt Metadaten zurück (Seitenzahl, Dateigröße, PDF-Version, Anhänge)
Endpoint:
POST /api/v1/documents/validate
Request: { "base64Pdf": "JVBERi0xLjQK..." }
Response: { "pageCount": 5, "fileSizeBytes": 1024, "pdfVersion": "1.4", "hasAttachments": false }
? Step 1.0: Foundation (ABGESCHLOSSEN)
Was wurde bereits erstellt:
- ? Domain Layer (Exceptions, Enums, Value Objects)
- ? Infrastructure Layer (
DevExpressPdfProcessor.ValidateAsync- FERTIG!) - ? Tests für Infrastructure (
DevExpressPdfProcessorTests.cs- 6 Tests)
Was wir wiederverwenden:
Base64StringValue Object (Domain)PdfMetadataValue Object (Domain)IPdfProcessorInterface (Application)DevExpressPdfProcessor.ValidateAsync(Infrastructure)
? Step 1.1: Application Layer (MediatR Setup + ValidatePDF Feature) - ABGESCHLOSSEN
Ziel: MediatR + FluentValidation + ValidatePDF Handler
Was wurde erstellt:
1.1.1: MediatR Setup
- ? Datei:
Application/DependencyInjection.cs- Registriert MediatR
- Registriert FluentValidation
- Registriert Pipeline Behaviors (Validation + Logging)
1.1.2: Pipeline Behaviors
-
? Datei:
Application/Common/Behaviors/ValidationBehavior.cs- Führt FluentValidation automatisch aus (vor jedem Handler)
- Wirft
ValidationExceptionbei Fehler
-
? Datei:
Application/Common/Behaviors/LoggingBehavior.cs- Loggt jeden Request (mit Performance-Tracking)
- Nutzt
ILogger<T>(Clean Architecture konform!)
1.1.3: ValidatePDF Feature (Vertical Slice)
-
? Ordner:
Application/Features/Documents/ValidatePdf/ -
? Datei:
ValidatePdfQuery.cspublic record ValidatePdfQuery(Base64String PdfContent) : IRequest<PdfMetadata>; -
? Datei:
ValidatePdfHandler.cspublic class ValidatePdfHandler : IRequestHandler<ValidatePdfQuery, PdfMetadata> { private readonly IPdfProcessor _processor; public async Task<PdfMetadata> Handle(ValidatePdfQuery query, CancellationToken ct) { byte[] bytes = query.PdfContent.ToByteArray(); return await _processor.ValidateAsync(bytes); } } -
? Datei:
ValidatePdfValidator.cspublic class ValidatePdfValidator : AbstractValidator<ValidatePdfQuery> { public ValidatePdfValidator() { RuleFor(x => x.PdfContent).NotNull().WithMessage("PDF content is required"); } }
1.1.4: DTOs
-
? Ordner:
Application/Common/DTOs/ -
? Datei:
ValidatePdfRequest.cspublic record ValidatePdfRequest(string Base64Pdf); -
? Datei:
ValidatePdfResponse.cspublic record ValidatePdfResponse( int PageCount, long FileSizeBytes, double FileSizeMB, string PdfVersion, bool HasAttachments, int AttachmentCount);
1.1.5: Tests
- ? Datei:
Tests/Unit/Application/Features/ValidatePdf/ValidatePdfHandlerTests.cs- ? Test:
Handle_ValidPdf_ReturnsPdfMetadata - ? Test:
Handle_PdfProcessorThrowsException_PropagatesException
- ? Test:
Akzeptanzkriterien:
- ? Build erfolgreich
- ? Tests grün (alle 2 Tests)
- ? MediatR Pipeline funktioniert (Validation + Logging)
? Step 1.2: API Layer (Endpoint + Exception Middleware) - ABGESCHLOSSEN
Ziel: HTTP Endpoint + zentrale Exception Handling
Was wurde erstellt:
1.2.1: Exception Handling Middleware
- ? Datei:
API/Middleware/ExceptionHandlingMiddleware.cs- Fängt alle Exceptions
- Mappt zu HTTP Status Codes (ValidationException ? 400, DomainValidationException ? 400, NotFoundException ? 404, PdfProcessingException ? 500)
- Gibt RFC 7807 Problem Details zurück
1.2.2: Minimal API Endpoint
- ? Datei:
API/Endpoints/v1/DocumentEndpoints.cs- POST /api/v1/documents/validate
- Nutzt MediatR (ValidatePdfQuery ? ValidatePdfHandler)
- Returns ValidatePdfResponse (200) oder ProblemDetails (400, 500)
1.2.3: Infrastructure DependencyInjection
- ? Datei:
Infrastructure/DependencyInjection.cs- Registriert IPdfProcessor ? DevExpressPdfProcessor
1.2.4: Program.cs Updates
- ? Application Layer registriert (AddApplication)
- ? Infrastructure Layer registriert (AddInfrastructure)
- ? Exception Middleware registriert (FIRST in pipeline!)
- ? Endpoints registriert (MapDocumentEndpoints)
1.2.5: Integration Tests
- ? Datei:
Tests/Integration/API/DocumentEndpointsTests.cs- ? Test:
POST_ValidatePdf_ValidPdf_Returns200 - ? Test:
POST_ValidatePdf_InvalidBase64_Returns400 - ? Test:
POST_ValidatePdf_EmptyPdf_Returns400
- ? Test:
Akzeptanzkriterien:
- ? Build erfolgreich
- ? Integration Tests grün (alle 3 Tests)
- ? Exception Middleware funktioniert
- ? Endpoint gibt korrekte HTTP Status Codes zurück
? Step 1.3: Swagger Dokumentation - ABGESCHLOSSEN
Ziel: API-Dokumentation + Swagger UI testbar
Was wurde erstellt:
1.3.1: Swagger Configuration
- ? Datei:
API/Configuration/SwaggerConfiguration.csAddSwaggerDocumentation()Extension Method- Swagger mit XML Comments konfiguriert
- API-Titel, Version, Beschreibung gesetzt
1.3.2: XML Comments aktiviert
- ? Datei:
API/DocumentOperator.API.csproj<PropertyGroup> <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup>
1.3.3: Endpoint dokumentiert
- ? Datei:
API/Endpoints/v1/DocumentEndpoints.cs- XML Comments für
ValidatePdfMethode - Swagger-Annotationen (
.WithSummary(),.WithDescription(),.Produces<>())
- XML Comments für
1.3.4: DTOs dokumentiert
-
? Datei:
Application/Common/DTOs/ValidatePdfRequest.cs- XML Comments für Request-Schema
-
? Datei:
Application/Common/DTOs/ValidatePdfResponse.cs- XML Comments für Response-Schema
FileSizeMBProperty hinzugefügt
1.3.5: Program.cs aktualisiert
- ? Datei:
API/Program.csbuilder.Services.AddSwaggerDocumentation()stattAddSwaggerGen()using DocumentOperator.API.Configuration;hinzugefügt
Akzeptanzkriterien:
- ? Build erfolgreich
- ? Alle Tests grün (11/11 Tests)
- ? XML-Dokumentation wird generiert (
DocumentOperator.API.xml) - ? Swagger UI zeigt Endpoint
/api/v1/documents/validatemit Dokumentation - ? Request/Response-Schemas sind dokumentiert
- ? Endpoint ist im Swagger UI testbar
? Feature 1 ABGESCHLOSSEN!
Was haben wir erreicht?
- ? ValidatePDF Feature komplett implementiert (Domain ? Infrastructure ? Application ? API ? Tests ? Swagger)
- ? Endpoint ist im Swagger UI testbar
- ? Unit Tests + Integration Tests grün (11/11)
- ? Clean Architecture eingehalten
- ? TDD angewendet
- ? Swagger-Dokumentation vollständig
Nächstes Feature: ? Feature 2: ExtractSwissQrCode
?? FEATURE 2: ExtractSwissQrCode (Synchron) - IN PROGRESS
Was macht dieses Feature?
- Client sendet PDF als Base64 + Referenzen (Array von Strings)
- API extrahiert Swiss QR Code von der letzten Seite des PDFs
- API gibt Referenzen + alle QR Code Felder zurück (Swiss QR Bill Standard 2.0)
Endpoint:
POST /api/v1/documents/extract-swiss-qr-code
Request:
{
"references": ["REF-001", "REF-002"],
"base64Pdf": "JVBERi0xLjQK..."
}
Response:
{
"references": ["REF-001", "REF-002"],
"qrCodeData": {
"qrType": "SPC",
"version": "0200",
"codingType": "1",
"iban": "CH4431999123000889012",
"creditor": {
"name": "Robert Schneider AG",
"addressType": "S",
"street": "Rue du Lac",
"buildingNumber": "1268",
"postalCode": "2501",
"city": "Biel",
"country": "CH"
},
"ultimateCreditor": null,
"amount": 1949.75,
"currency": "CHF",
"ultimateDebtor": {
"name": "Pia-Maria Rutschmann-Schnyder",
"addressType": "S",
"street": "Grosse Marktgasse",
"buildingNumber": "28",
"postalCode": "9400",
"city": "Rorschach",
"country": "CH"
},
"referenceType": "QRR",
"reference": "210000000003139471430009017",
"unstructuredMessage": "Rechnung vom 15.01.2025",
"billInformation": "//S1/01/...",
"alternativeProcedureParameters": ["Name AV1: UV;UltraPay005;12345", "Name AV2: XY;XYService;54321"]
}
}
Technologie:
- DevExpress PDF Document API (PDF-Zugriff, letzte Seite, QR Code Image)
- Codecrete.SwissQRBill.Generator (Swiss QR Code Parsing - Standard 2.0)
Steps:
- ?? Step 2.1: Domain Layer (SwissQrCodeData Value Object)
- ?? Step 2.2: Infrastructure Layer (IQrCodeProcessor + DevExpressSwissQrCodeProcessor)
- ?? Step 2.3: Application Layer (ExtractSwissQrCodeQuery + Handler + Validator)
- ?? Step 2.4: API Layer (Endpoint + Integration Tests)
- ?? Step 2.5: Swagger Dokumentation
Akzeptanzkriterien:
- ? QR Code wird von letzter Seite extrahiert
- ? Alle Swiss QR Bill Felder werden geparst (Standard 2.0)
- ? Referenzen werden durchgeschliffen (Echo)
- ? Fehler wenn kein QR Code gefunden
- ? Swagger-testbar
?? FEATURE 3: ExtractAttachments (Synchron) - PENDING
Was macht dieses Feature?
- Client sendet PDF als Base64 (JSON)
- API extrahiert eingebettete Anhänge
- API gibt Anhänge als Base64 zurück (oder Download-Links)
Endpoint:
POST /api/v1/documents/extract-attachments
Request: { "base64Pdf": "JVBERi0xLjQK..." }
Response: { "attachments": [{ "name": "invoice.xml", "base64Content": "..." }] }
Steps:
- ?? Step 3.1: Infrastructure Layer (DevExpressPdfProcessor.ExtractAttachmentsAsync)
- ?? Step 3.2: Application Layer (ExtractAttachmentsCommand + Handler + Validator)
- ?? Step 3.3: API Layer (Endpoint)
- ?? Step 3.4: Swagger Dokumentation
?? FEATURE 4: ApplyStamp (Synchron) - PENDING
Was macht dieses Feature?
- Client sendet PDF + Stamp-Konfiguration (Text, Position)
- API fügt Stamp hinzu (Logo, Text, Wasserzeichen)
- API gibt gestempeltes PDF zurück
Endpoint:
POST /api/v1/documents/apply-stamp
Request: { "base64Pdf": "...", "text": "CONFIDENTIAL", "position": "TopRight" }
Response: { "base64Pdf": "JVBERi0xLjQK..." }
Steps:
- ?? Step 4.1: Infrastructure Layer (DevExpressPdfProcessor.ApplyStampAsync)
- ?? Step 4.2: Application Layer (ApplyStampCommand + Handler + Validator)
- ?? Step 4.3: API Layer (Endpoint)
- ?? Step 4.4: Swagger Dokumentation
?? FEATURE 5: EmbedCertificate (Synchron) - PENDING
Was macht dieses Feature?
- Client sendet PDF + Zertifikat (PFX als Base64)
- API bettet Zertifikat als Attachment ein
- API gibt PDF mit Zertifikat zurück
Endpoint:
POST /api/v1/documents/embed-certificate
Request: { "base64Pdf": "...", "base64Certificate": "..." }
Response: { "base64Pdf": "JVBERi0xLjQK..." }
Steps:
- ?? Step 5.1: Infrastructure Layer (DevExpressPdfProcessor.EmbedCertificateAsync)
- ?? Step 5.2: Application Layer (EmbedCertificateCommand + Handler + Validator)
- ?? Step 5.3: API Layer (Endpoint)
- ?? Step 5.4: Swagger Dokumentation
?? FEATURE 6: ConcatenatePDFs (Asynchron) - PENDING
Was macht dieses Feature?
- Client sendet mehrere PDFs (Array von Base64)
- API startet asynchronen Job (gibt JobId zurück)
- Client pollt Job-Status
- Wenn fertig: Client lädt Ergebnis herunter
Endpoints:
POST /api/v1/documents/concatenate (Async)
Request: { "pdfFiles": ["JVBERi0x...", "JVBERi0y..."] }
Response: { "jobId": "abc-123", "status": "Pending" }
GET /api/v1/jobs/{jobId}
Response: { "jobId": "abc-123", "status": "Processing", "progress": 50 }
GET /api/v1/jobs/{jobId}/download
Response: PDF-Datei (Binary)
Steps:
- ?? Step 6.1: Infrastructure Layer (In-Memory Queue + Background Worker)
- ?? Step 6.2: Application Layer (SubmitConcatenateJobCommand + GetJobStatusQuery)
- ?? Step 6.3: API Layer (Async Endpoints)
- ?? Step 6.4: Swagger Dokumentation
?? CROSS-CUTTING CONCERNS
Nach Features 1-4 abgeschlossen:
?? Multi-Tenancy (X-API-Key Header)
Was wird gebaut:
- EF Core + SQLite (Tenant-Datenbank)
- Redis Cache (API-Key Lookups)
- TenantResolutionMiddleware (X-API-Key ? Tenant)
- BCrypt API-Key Hashing
- Admin API (Tenant CRUD)
Steps:
- ?? Step MT.1: EF Core Setup (Entities, DbContext, Migrations)
- ?? Step MT.2: TenantResolutionMiddleware
- ?? Step MT.3: Redis Cache Integration
- ?? Step MT.4: Admin API (Tenant Management)
- ?? Step MT.5: Alle Endpoints mit X-API-Key absichern
?? Health Checks
Was wird gebaut:
/healthEndpoint (Liveness/Readiness Probes)- DevExpressPdfHealthCheck (Smoke Test)
- Database Health Check (SQLite)
- Redis Health Check
Steps:
- ?? Step HC.1: DevExpressPdfHealthCheck
- ?? Step HC.2: Database Health Check
- ?? Step HC.3: Redis Health Check (optional)
??? Polly Resilience
Was wird gebaut:
- Retry Policy (3x mit Exponential Backoff)
- Circuit Breaker (nach 5 Fehlern 30s öffnen)
- Timeout Policy (30s max)
Steps:
- ?? Step PR.1: Polly Policies in DevExpressPdfProcessor
- ?? Step PR.2: Logging für Resilience Events
?? Logging & Monitoring
Was wird gebaut:
- Correlation IDs (X-Correlation-ID Header)
- Seq Sink (Log-Browsing UI)
- File Logging (Production)
- LoggingBehavior (MediatR Pipeline)
Steps:
- ?? Step LM.1: CorrelationIdMiddleware
- ?? Step LM.2: Seq Sink konfigurieren
- ?? Step LM.3: File Logging konfigurieren
- ?? Step LM.4: LoggingBehavior erweitern (Performance-Tracking)
?? PROJECT OVERVIEW
Vision & Purpose
DocumentOperator ist ein zentralisierter REST API Service für PDF-Dokumenten-Operationen in einer Multi-Tenant DMS-Umgebung.
Problem Statement
Aktuell:
- Verschiedene DMS-Kunden bei unterschiedlichen Mandanten
- Jede Anwendung implementiert PDF-Operationen redundant
- Keine zentrale Stelle für Dokumenten-Verarbeitung
- Wartungsaufwand multipliziert sich mit jeder Anwendung
Lösung:
- Ein zentraler Service für alle PDF-Operationen
- Wiederverwendbar über HTTP REST API
- Mandantenfähig (Multi-Tenancy - später!)
- Wartbar an einer Stelle
??? ARCHITECTURE & DESIGN DECISIONS
Clean Architecture (Pragmatisch!)
Wir verwenden Clean Architecture mit 4 Layers - ABER: pragmatisch, nicht dogmatisch!
?????????????????????????????????????
? API Layer (Endpoints) ? ? HTTP Entry Point
?????????????????????????????????????
? Application Layer (Use Cases) ? ? MediatR Handlers, DTOs
?????????????????????????????????????
? Infrastructure Layer (Tech Stack) ? ? DevExpress, File I/O
?????????????????????????????????????
? Domain Layer (MINIMAL!) ? ? Nur Enums + Value Objects
?????????????????????????????????????
Dependency Rule
Abhängigkeiten zeigen immer nach innen:
API ? Application ? Domain
API ? Infrastructure ? Domain
Infrastructure ? Application (für Interfaces)
Domain ? NICHTS! (No External Dependencies)
Application ? NUR Domain
Warum Clean Architecture?
- ? Testbarkeit (Application Layer kann Services mocken)
- ? Austauschbarkeit (DevExpress ? anderes PDF-Lib ohne Application zu ändern)
- ? Separation of Concerns (jede Schicht hat klare Verantwortung)
ABER:
- ? Kein Overengineering (nur was wir wirklich brauchen!)
- ? Keine spekulativen Abstraktionen (erst wenn 2. Use Case es braucht)
- ? Keine unnötigen Klassen (YAGNI - You Ain't Gonna Need It)
CQRS with MediatR
Pattern: Command Query Responsibility Segregation
Warum MediatR?
- ? Klare Trennung: 1 Command/Query = 1 Handler = 1 Verantwortung
- ? Testbarkeit (Handler kann isoliert getestet werden)
- ? Pipeline Behaviors (Validation, Logging zentral)
- ? Kein aufgeblähter Service mit 20 Methoden
CQRS in unserem Kontext:
- Command: Ändert Daten (ApplyStamp, EmbedCertificate, etc.)
- Query: Liest Daten (ValidatePdf ? gibt nur Metadata zurück)
Beispiel:
// Query (Read-Only)
public record ValidatePdfQuery(Base64String PdfContent) : IRequest<PdfMetadata>;
// Handler
public class ValidatePdfHandler : IRequestHandler<ValidatePdfQuery, PdfMetadata>
{
private readonly IPdfProcessor _processor;
public async Task<PdfMetadata> Handle(ValidatePdfQuery query, CancellationToken ct)
{
byte[] bytes = query.PdfContent.ToByteArray();
var metadata = await _processor.ValidateAsync(bytes);
return metadata;
}
}
Vertical Slice Architecture
Statt Horizontal Layers (Commands/, Handlers/, Validators/):
? Horizontal (Schlecht für Wartung):
Application/
??? Commands/
? ??? ValidatePdfCommand.cs
? ??? ProcessDocumentCommand.cs
??? Handlers/
? ??? ValidatePdfHandler.cs
? ??? ProcessDocumentHandler.cs
??? Validators/
??? ValidatePdfValidator.cs
??? ProcessDocumentValidator.cs
Nutzen wir Vertical Slices (pro Feature alles zusammen):
? Vertical (Gut für Wartung):
Features/
??? ValidatePdf/
? ??? ValidatePdfQuery.cs
? ??? ValidatePdfHandler.cs
? ??? ValidatePdfValidator.cs
??? ProcessDocument/
??? ProcessDocumentCommand.cs
??? ProcessDocumentHandler.cs
??? ProcessDocumentValidator.cs
Vorteile:
- ? Zusammengehöriger Code ist zusammen (Cohesion)
- ? Einfacher zu finden ("Wo ist ValidatePdf?" ? ein Ordner!)
- ? Einfacher zu ändern (alle Dateien im gleichen Ordner)
- ? Weniger Merge-Konflikte im Team
Exception-based Error Handling
Entscheidung: Keine Result Pattern Library
Stattdessen:
- FluentValidation für Input-Validierung (DTO-Ebene)
- Domain Exceptions für fachliche Fehler
- Zentrale Exception Handling Middleware im API Layer
Warum Exception-basiert?
- ? Einfacherer Code (kein
if (result.IsSuccess)überall) - ? Weniger Boilerplate (kein Result Wrapping)
- ? Standard .NET Exception-Flow (jeder kennt es)
- ? Zentrales Error Handling = wartbar an einer Stelle
Flow:
HTTP Request
?
FluentValidation (MediatR ValidationBehavior)
? Bei Fehler: ValidationException ? Middleware ? HTTP 400
?
Handler
? Bei Fehler: DomainException ? Middleware ? HTTP 400/404/500
?
Middleware (Exception Handler)
? Mappt Exception Type ? HTTP Status Code
? Loggt Exception (Serilog)
? Gibt Problem Details (RFC 7807) zurück
?
HTTP Response (JSON)
?? TECHNOLOGY STACK
Core Framework
| Technology | Version | Purpose |
|---|---|---|
| .NET | 8.0 | Runtime & Framework |
| ASP.NET Core | 8.0 | Web API |
| C# | 12 | Language (Primary Constructors, Record Types) |
NuGet Packages
API Layer
| Package | Version | Purpose |
|---|---|---|
| Swashbuckle.AspNetCore | 6.6.2 | Swagger/OpenAPI Documentation |
| Serilog.AspNetCore | 10.0.0 | Strukturiertes Logging |
| Serilog.Sinks.File | 7.0.0 | Log-Datei-Output |
| Serilog.Sinks.Seq | 8.0.0 | Log-Browsing UI (Development) |
| Serilog.Enrichers.CorrelationId | 3.0.1 | Correlation IDs für Request-Tracking |
| Asp.Versioning.Http | 8.1.1 | API Versioning (/api/v1/, /api/v2/) |
Application Layer
| Package | Version | Purpose |
|---|---|---|
| MediatR | 14.1.0 | CQRS Pattern Implementation |
| FluentValidation | 12.1.1 | Input Validation (DTOs) |
| FluentValidation.DependencyInjectionExtensions | 12.1.1 | DI Integration |
Infrastructure Layer
| Package | Version | Purpose |
|---|---|---|
| DevExpress.Pdf.Core | 25.2.8 | PDF-Operationen (Merge, Extract, Sign, etc.) |
| Polly | 8.5.0 | Resilience (Retry, Circuit Breaker, Timeout) - SPÄTER! |
| Microsoft.EntityFrameworkCore | 8.0.0 | ORM für Tenant-Datenbank - SPÄTER! |
| Microsoft.EntityFrameworkCore.Sqlite | 8.0.0 | SQLite Provider - SPÄTER! |
| BCrypt.Net-Next | 4.0.3 | API-Key Hashing - SPÄTER! |
Domain Layer
| Package | Version | Purpose |
|---|---|---|
| - | - | Keine Dependencies! (Clean Architecture) |
Tests
| Package | Version | Purpose |
|---|---|---|
| xUnit | 2.9.3 | Test Framework |
| FluentAssertions | 7.0.0 | Assertions (result.Should().Be(expected)) |
| Moq | 4.20.72 | Mocking (für Services) |
| Microsoft.NET.Test.Sdk | 17.11.1 | Test SDK |
?? PROJECT STRUCTURE
Solution Overview
DocumentOperator/
??? DocumentOperator.API/ ? HTTP Entry Point
??? DocumentOperator.Application/ ? Use Cases (MediatR Handlers)
??? DocumentOperator.Infrastructure/ ? Technical Implementations
??? DocumentOperator.Domain/ ? Business Logic (MINIMAL!)
??? DocumentOperator.Tests/ ? Unit & Integration Tests
??? ROADMAP.md ? This file
??? PHASENPLAN.md ? Project timeline
?? API Layer (DocumentOperator.API)
Purpose: HTTP Entry Point, Routing, Middleware
Folder Structure:
DocumentOperator.API/
??? Endpoints/
? ??? v1/
? ??? DocumentEndpoints.cs ? Minimal API Endpoints
??? Middleware/
? ??? ExceptionHandlingMiddleware.cs ? Zentrale Exception Handling ?
??? Configuration/
? ??? SwaggerConfiguration.cs ? Swagger Setup
??? appsettings.json ? Base Configuration
??? appsettings.Development.json ? Dev Overrides
??? Program.cs ? Application Entry Point
?? Application Layer (DocumentOperator.Application)
Purpose: Use Cases, Business Logic Orchestration
Folder Structure:
DocumentOperator.Application/
??? Features/ ? Vertical Slices ?
? ??? Documents/
? ??? ValidatePdf/
? ? ??? ValidatePdfQuery.cs
? ? ??? ValidatePdfHandler.cs
? ? ??? ValidatePdfValidator.cs
? ??? ExtractAttachments/
? ? ??? ExtractAttachmentsCommand.cs
? ? ??? ExtractAttachmentsHandler.cs
? ? ??? ExtractAttachmentsValidator.cs
? ??? ... (weitere Features iterativ)
??? Common/
? ??? Interfaces/ ? Abstractions für Infrastructure
? ? ??? IPdfProcessor.cs
? ??? Behaviors/ ? MediatR Pipeline Behaviors
? ? ??? ValidationBehavior.cs ? FluentValidation Integration
? ? ??? LoggingBehavior.cs ? Structured Logging
? ??? DTOs/ ? Data Transfer Objects
? ??? ValidatePdfRequest.cs
? ??? ValidatePdfResponse.cs
??? DependencyInjection.cs ? Service Registration
?? Infrastructure Layer (DocumentOperator.Infrastructure)
Purpose: Technische Implementierungen
Folder Structure:
DocumentOperator.Infrastructure/
??? Services/
? ??? PdfProcessing/
? ??? DevExpressPdfProcessor.cs ? IPdfProcessor Implementation ?
??? Configuration/
? ??? DocumentOperatorSettings.cs ? Options Pattern Class
??? DependencyInjection.cs ? Service Registration
?? Domain Layer (DocumentOperator.Domain) - MINIMAL!
Purpose: Business Rules (nur was wirklich gebraucht wird!)
Folder Structure:
DocumentOperator.Domain/
??? ValueObjects/ ? Immutable, selbst-validierend ?
? ??? Base64String.cs
? ??? TenantId.cs
? ??? PdfMetadata.cs
??? Enums/ ? ?
? ??? DocumentOperationType.cs
? ??? ProcessingStatus.cs
??? Exceptions/ ? Domain-spezifische Exceptions ?
??? DomainException.cs
??? DomainValidationException.cs
??? NotFoundException.cs
??? PdfProcessingException.cs
?? Tests Layer (DocumentOperator.Tests)
Purpose: Unit & Integration Tests
Folder Structure:
DocumentOperator.Tests/
??? Unit/
? ??? Application/
? ? ??? Features/
? ? ??? ValidatePdf/
? ? ??? ValidatePdfHandlerTests.cs
? ??? Infrastructure/
? ? ??? Services/
? ? ??? DevExpressPdfProcessorTests.cs ?
? ??? Domain/
? ??? ValueObjects/
? ??? Base64StringTests.cs
??? Integration/
??? API/
??? DocumentEndpointsTests.cs
?? TESTING STRATEGY
Test-Driven Development (TDD)
Flow:
- Red: Test schreiben (schlägt fehl, weil Code noch nicht existiert)
- Green: Code schreiben (Test wird grün)
- Refactor: Code verbessern (Test bleibt grün)
Warum TDD?
- ? Tests als Dokumentation (wie wird es genutzt?)
- ? Tests als Safety Net (Refactoring ohne Angst)
- ? Besseres Design (testbarer Code = guter Code)
- ? Keine "vergessenen" Tests (Test kommt ZUERST)
Test-Pyramide
/\
/ \ E2E Tests (wenige)
/ \
/------\ Integration Tests (einige)
/ \
/----------\ Unit Tests (viele)
/ \
Konkret:
-
Unit Tests (viele):
- Value Objects (Base64String.Create() wirft Exception?)
- Handlers (ValidatePdfHandler ruft IPdfProcessor auf?)
- Services (DevExpressPdfProcessor gibt Metadata zurück?)
-
Integration Tests (einige):
- Endpoints (HTTP POST ? 200 OK + JSON?)
- MediatR Pipeline (ValidationBehavior funktioniert?)
-
E2E Tests (wenige/keine):
- Haben wir nicht (API ist selbst der "Top-Level")
?? CURRENT STATUS
? Completed
-
Foundation & Domain Layer:
- ? Solution Structure (4 Projekte)
- ? Dependencies (Clean Architecture Dependency Rule)
- ? Domain Exceptions (4 Exceptions)
- ? Enums (DocumentOperationType, ProcessingStatus)
- ? Value Objects (Base64String, TenantId, PdfMetadata)
-
Infrastructure Layer:
- ? IPdfProcessor Interface
- ? DevExpressPdfProcessor.ValidateAsync (mit Tests!)
- ? DependencyInjection.cs (Infrastructure Services)
-
Application Layer:
- ? DependencyInjection.cs (MediatR + FluentValidation)
- ? ValidationBehavior.cs (FluentValidation Pipeline)
- ? LoggingBehavior.cs (ILogger Pipeline)
- ? ValidatePDF Feature (Query, Handler, Validator)
- ? DTOs (ValidatePdfRequest, ValidatePdfResponse)
- ? Tests (ValidatePdfHandlerTests - 2 Tests grün)
-
API Layer:
- ? ExceptionHandlingMiddleware.cs (RFC 7807 Problem Details)
- ? DocumentEndpoints.cs (POST /api/v1/documents/validate)
- ? Program.cs (Services + Middleware + Endpoints)
- ? Tests (DocumentEndpointsTests - 3 Tests grün)
?? In Progress
- Feature 1: ValidatePDF
- ? Step 1.3: Swagger Dokumentation - NEXT
? Pending
-
Feature 1: ValidatePDF
- ? Step 1.3: Swagger Dokumentation
-
Feature 2-5: ExtractAttachments, ApplyStamp, EmbedCertificate, ConcatenatePDFs
-
Cross-Cutting Concerns: Multi-Tenancy, Health Checks, Polly, Logging
?? KEY LEARNINGS & DECISIONS
1. Feature-Driven Development statt Layer-by-Layer
Entscheidung: Jedes Feature komplett fertig (bis Swagger testbar)
Warum:
- ? Schnellerer Value (Feature 1 nach ~1 Tag fertig!)
- ? Klares Ziel (Swagger testbar = DONE)
- ? Weniger Komplexität (nicht alle Layer parallel)
- ? Besseres Lernen (Pattern wiederholt sich)
Alternative wäre gewesen:
- Domain komplett ? Infrastructure komplett ? Application komplett ? API komplett
- Nachteile: Viel Code ohne sichtbares Ergebnis, spekulativ
2. Domain Layer minimal halten
Entscheidung: Nur Enums + Value Objects + Exceptions
Warum:
- Domain = Business-Konzepte (technologie-unabhängig)
- Service-Anwendung (nicht Domain-lastig)
- YAGNI (You Ain't Gonna Need It)
Was bedeutet das?
- Domain/ValueObjects/TenantId.cs ? Value Object (immutable, validierend)
- Infrastructure/Data/Entities/Tenant.cs ? EF Core Entity (später!)
- Domain kennt KEINE EF Core Dependencies!
3. Multi-Tenancy NACH allen Features
Entscheidung: Erst alle synchronen Features, dann Multi-Tenancy
Warum:
- ? Multi-Tenancy betrifft ALLE Endpoints
- ? Einmal für alle Features (nicht 5x wiederholen!)
- ? Einfacher zu testen (erst ohne Tenancy, dann mit)
Nachteile (akzeptiert):
- ? Refactoring später nötig (alle Endpoints müssen X-API-Key Header bekommen)
- ? Aber: Aufwand überschaubar (Middleware erledigt das meiste!)
4. TDD beibehalten
Entscheidung: Test-First Development
Warum:
- ? Besseres Design (testbarer Code)
- ? Tests als Dokumentation
- ? Safety Net für Refactoring
5. Vertical Slice Architecture
Entscheidung: Pro Feature alles zusammen
Warum:
- ? Zusammengehöriger Code ist zusammen
- ? Einfacher zu finden und zu ändern
- ? Besser für Teams (weniger Merge-Konflikte)
?? UPDATE LOG
| Date | Feature/Step | Changes |
|---|---|---|
| 2024-XX-XX | Foundation | Project setup, dependencies, folder structure |
| 2024-XX-XX | Domain Layer | Exceptions, Enums, Value Objects |
| 17.01.2025 | Infrastructure | DevExpressPdfProcessor.ValidateAsync implementiert |
| 17.01.2025 | Tests | DevExpressPdfProcessorTests.cs erstellt (6 Tests) |
| 17.01.2025 | ROADMAP | ?? Komplett umstrukturiert (Feature-Driven Development!) |
| 17.01.2025 | PHASENPLAN | ?? Komplett umstrukturiert (Feature-basiert + Datum korrigiert) |
| 17.01.2025 | Feature 1 - Step 1.1 | ? ABGESCHLOSSEN - Application Layer (MediatR, Behaviors, ValidatePDF Feature, DTOs, Tests) |
| 17.01.2025 | Feature 1 - Step 1.2 | ? ABGESCHLOSSEN - API Layer (ExceptionMiddleware, Endpoint, Program.cs, Integration Tests - 3/3 grün) |
| 17.01.2025 | Feature 1 - Step 1.3 | ? ABGESCHLOSSEN - Swagger Dokumentation (SwaggerConfiguration, XML Comments, Endpoint/DTO-Dokumentation - 11/11 Tests grün) |
| 17.01.2025 | Feature 1 | ? KOMPLETT ABGESCHLOSSEN - ValidatePDF Feature testbar im Swagger UI! |
| 17.01.2025 | Fix: Attachment Detection (Multiple Attachments) | ? KORRIGIERT - ValidatePDF erkennt jetzt auch PDFs mit mehreren Attachments korrekt (globale Suche statt 1000-Zeichen-Limit) - 13/13 Tests grün |
| 17.01.2025 | Fix: Attachment Count (6 Attachments) | ? KORRIGIERT - AttachmentCount wird jetzt korrekt gezählt (objectCount statt objectCount/2). PDFs mit 6 Attachments werden korrekt erkannt - 13/13 Tests grün |
| 17.01.2025 | ROADMAP | ?? Feature-Reihenfolge geändert - Neues Feature 2: ExtractSwissQrCode (Swiss QR Bill Standard 2.0) eingefügt. Alte Features 2-5 werden zu Features 3-6. |
| 17.01.2025 | Feature 2 - ExtractSwissQrCode | ?? GESTARTET - Swiss QR Code Extraktion von letzter PDF-Seite (DevExpress + Codecrete.SwissQRBill.Generator) |
END OF ROADMAP
This document is a living document and will be updated after each completed step.