Updated `DocumentEndpoints` to include detailed requirements, return values, and use case for the `ExtractSwissQrCode` endpoint. Marked Feature 2 (`ExtractSwissQrCode`) as completed in `PHASENPLAN.md` and `ROADMAP.md`, summarizing achievements and outlining next steps for Feature 3 (`ExtractAttachments`). Enhanced `ExtractSwissQrCodeRequest` and `ExtractSwissQrCodeResponse` DTOs with example JSON payloads for clarity. Expanded `SwissQrCodeDataDto` and `AddressDataDto` with detailed field-level documentation to improve usability and adherence to Swiss QR Bill Standard 2.0.
33 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 | ? Abgeschlossen | ? |
| 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 3: ExtractAttachments
?? FEATURE 2: ExtractSwissQrCode (Synchron) - ABGESCHLOSSEN
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
- ? Tests grün (19/19)
? Feature 2 ABGESCHLOSSEN!
Was haben wir erreicht?
- ? ExtractSwissQrCode Feature komplett implementiert (Domain ? Infrastructure ? Application ? API ? Tests ? Swagger)
- ? Endpoint ist im Swagger UI testbar:
POST /api/v1/documents/extract-swiss-qr-code - ? Unit Tests + Integration Tests grün (19/19)
- ? 3 Libraries integriert: DevExpress PDF, ZXing.Net, Codecrete.SwissQRBill.Generator
- ? Vollständige Swiss QR Bill Standard 2.0 Unterstützung
- ? Clean Architecture eingehalten
- ? Swagger-Dokumentation vollständig
Nächstes Feature: ? Feature 3: ExtractAttachments
?? 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 - Step 2.1 | ? ABGESCHLOSSEN - Domain Layer (SwissQrCodeData, AddressData Value Objects, SwissQrCodeNotFoundException) |
| 17.01.2025 | Feature 2 - Step 2.2 | ? ABGESCHLOSSEN - Infrastructure Layer (ISwissQrCodeProcessor, DevExpressSwissQrCodeProcessor, Libraries: Codecrete.SwissQRBill.Generator, ZXing.Net, System.Drawing.Common) |
| 17.01.2025 | Feature 2 - Step 2.3 | ? ABGESCHLOSSEN - Application Layer (Query, Handler, Validator, DTOs, Unit Tests - 2/2 grün) |
| 17.01.2025 | Feature 2 - Step 2.4 | ? ABGESCHLOSSEN - API Layer (Endpoint /extract-swiss-qr-code, Exception Handling, Integration Tests - 4/4 grün) |
| 17.01.2025 | Feature 2 - Step 2.5 | ? ABGESCHLOSSEN - Swagger Dokumentation (XML Comments, Request/Response Beispiele, Endpoint-Beschreibung) |
| 17.01.2025 | Feature 2 | ? KOMPLETT ABGESCHLOSSEN - ExtractSwissQrCode Feature testbar im Swagger UI! (19/19 Tests grün) |
END OF ROADMAP
This document is a living document and will be updated after each completed step.