Files
DocumentService/DocumentOperator.API/ROADMAP.md
OlgunR 84c0a54c1e Enhance ExtractSwissQrCode feature documentation
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.
2026-06-26 08:58:25 +02:00

1102 lines
33 KiB
Markdown

# ?? 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
1. [Feature Roadmap](#feature-roadmap)
2. [Project Overview](#project-overview)
3. [Architecture & Design Decisions](#architecture--design-decisions)
4. [Technology Stack](#technology-stack)
5. [Project Structure](#project-structure)
6. [Testing Strategy](#testing-strategy)
7. [Current Status](#current-status)
8. [Key Learnings & Decisions](#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:**
- `Base64String` Value Object (Domain)
- `PdfMetadata` Value Object (Domain)
- `IPdfProcessor` Interface (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 `ValidationException` bei 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.cs`
```csharp
public record ValidatePdfQuery(Base64String PdfContent) : IRequest<PdfMetadata>;
```
- ? **Datei:** `ValidatePdfHandler.cs`
```csharp
public 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.cs`
```csharp
public 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.cs`
```csharp
public record ValidatePdfRequest(string Base64Pdf);
```
- ? **Datei:** `ValidatePdfResponse.cs`
```csharp
public 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`
**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`
**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.cs`
- `AddSwaggerDocumentation()` Extension Method
- Swagger mit XML Comments konfiguriert
- API-Titel, Version, Beschreibung gesetzt
#### 1.3.2: XML Comments aktiviert
- ? **Datei:** `API/DocumentOperator.API.csproj`
```xml
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
```
#### 1.3.3: Endpoint dokumentiert
- ? **Datei:** `API/Endpoints/v1/DocumentEndpoints.cs`
- XML Comments für `ValidatePdf` Methode
- Swagger-Annotationen (`.WithSummary()`, `.WithDescription()`, `.Produces<>()`)
#### 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
- `FileSizeMB` Property hinzugefügt
#### 1.3.5: Program.cs aktualisiert
- ? **Datei:** `API/Program.cs`
- `builder.Services.AddSwaggerDocumentation()` statt `AddSwaggerGen()`
- `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/validate` mit 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:**
- `/health` Endpoint (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:**
```csharp
// 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:**
1. **FluentValidation** für Input-Validierung (DTO-Ebene)
2. **Domain Exceptions** für fachliche Fehler
3. **Zentrale Exception Handling Middleware** im API Layer
**Warum Exception-basiert?**
- ? Einfacherer Code (kein `if (result.IsSuccess)` überall)
- ? Weniger Boilerplate (kein Result<T> 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:**
1. **Red:** Test schreiben (schlägt fehl, weil Code noch nicht existiert)
2. **Green:** Code schreiben (Test wird grün)
3. **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<T> 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.*