# ?? 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.*
