Updated PHASENPLAN and ROADMAP to reflect progress on Feature 1 - ValidatePDF (75% complete). Marked Step 1.1 as completed, including MediatR setup, pipeline behaviors (`ValidationBehavior`, `LoggingBehavior`), ValidatePDF feature (Query, Handler, Validator), and DTOs. Added `DependencyInjection.cs` for Application Layer DI configuration. Introduced `LoggingBehavior` and `ValidationBehavior` for MediatR pipelines. Implemented `ValidatePdfHandler`, `ValidatePdfQuery`, and `ValidatePdfValidator`. Created DTOs (`ValidatePdfRequest`, `ValidatePdfResponse`) for the ValidatePDF feature. Added unit tests for `ValidatePdfHandler` to verify metadata handling and exception propagation. Removed unused folder references in `DocumentOperator.Application.csproj`.
28 KiB
?? DocumentOperator - Project Roadmap (Feature-Driven Development)
Last Updated: 17.01.2025 | Status: In Development | Current Feature: Feature 1 - ValidatePDF (Step 1.2 NEXT)
?? 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 | ?? In Progress (Step 1.2 NEXT) | ? |
| 2. ExtractAttachments | Synchron | ? Pending | ? |
| 3. ApplyStamp | Synchron | ? Pending | ? |
| 4. EmbedCertificate | Synchron | ? Pending | ? |
| 5. 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) - NEXT
Ziel: HTTP Endpoint + zentrale Exception Handling
Was wird erstellt:
1.2.1: Exception Handling Middleware
- Datei:
API/Middleware/ExceptionHandlingMiddleware.cs- Fängt alle Exceptions
- Mappt zu HTTP Status Codes (400, 404, 500)
- Gibt RFC 7807 Problem Details zurück
1.2.2: Minimal API Endpoint
- Datei:
API/Endpoints/v1/DocumentEndpoints.cspublic static class DocumentEndpoints { public static void MapDocumentEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/api/v1/documents") .WithTags("Documents") .WithOpenApi(); group.MapPost("/validate", ValidatePdf) .WithName("ValidatePdf") .WithSummary("Validates a PDF document and returns metadata"); } private static async Task<IResult> ValidatePdf( ValidatePdfRequest request, IMediator mediator, CancellationToken ct) { var query = new ValidatePdfQuery(Base64String.Create(request.Base64Pdf)); var metadata = await mediator.Send(query, ct); var response = new ValidatePdfResponse( metadata.PageCount, metadata.FileSizeBytes, metadata.FileSizeMB, metadata.PdfVersion, metadata.HasAttachments, metadata.AttachmentCount ); return Results.Ok(response); } }
1.2.3: Program.cs Updates
- Registriert Exception Middleware
- Registriert DocumentEndpoints
- Registriert Application + Infrastructure Services
1.2.4: Integration Tests
- Datei:
Tests/Integration/API/DocumentEndpointsTests.cs- Test:
POST_ValidatePdf_ValidPdf_Returns200 - Test:
POST_ValidatePdf_InvalidBase64_Returns400 - Test:
POST_ValidatePdf_CorruptedPdf_Returns500
- 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
Ziel: API-Dokumentation + Swagger UI testbar
Was wird erstellt:
1.3.1: Swagger Configuration
- Datei:
API/Configuration/SwaggerConfiguration.cs- AddSwaggerGen mit XML Comments
- Konfiguriert API-Versioning
- Fügt Beispiel-Schemas hinzu
1.3.2: XML Comments
-
Aktivieren in
API/DocumentOperator.API.csproj:<PropertyGroup> <GenerateDocumentationFile>true</GenerateDocumentationFile> <NoWarn>$(NoWarn);1591</NoWarn> </PropertyGroup> -
XML Comments für
ValidatePdfEndpoint:/// <summary> /// Validates a PDF document and returns metadata /// </summary> /// <param name="request">PDF as Base64 string</param> /// <returns>PDF metadata (page count, file size, etc.)</returns> /// <response code="200">PDF is valid, metadata returned</response> /// <response code="400">Invalid PDF or Base64 format</response> /// <response code="500">Internal server error during validation</response>
Akzeptanzkriterien:
- ? Swagger UI läuft unter
/swagger - ? Endpoint
/api/v1/documents/validateist sichtbar - ? Request/Response Schemas sind dokumentiert
- ? Endpoint ist im Swagger UI testbar (manuelle Verifikation!)
? 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
- ? Clean Architecture eingehalten
- ? TDD angewendet
Nächstes Feature: ? Feature 2: ExtractAttachments
?? FEATURE 2: 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 2.1: Infrastructure Layer (DevExpressPdfProcessor.ExtractAttachmentsAsync)
- ?? Step 2.2: Application Layer (ExtractAttachmentsCommand + Handler + Validator)
- ?? Step 2.3: API Layer (Endpoint)
- ?? Step 2.4: Swagger Dokumentation
?? FEATURE 3: 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 3.1: Infrastructure Layer (DevExpressPdfProcessor.ApplyStampAsync)
- ?? Step 3.2: Application Layer (ApplyStampCommand + Handler + Validator)
- ?? Step 3.3: API Layer (Endpoint)
- ?? Step 3.4: Swagger Dokumentation
?? FEATURE 4: 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 4.1: Infrastructure Layer (DevExpressPdfProcessor.EmbedCertificateAsync)
- ?? Step 4.2: Application Layer (EmbedCertificateCommand + Handler + Validator)
- ?? Step 4.3: API Layer (Endpoint)
- ?? Step 4.4: Swagger Dokumentation
?? FEATURE 5: 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 5.1: Infrastructure Layer (In-Memory Queue + Background Worker)
- ?? Step 5.2: Application Layer (SubmitConcatenateJobCommand + GetJobStatusQuery)
- ?? Step 5.3: API Layer (Async Endpoints)
- ?? Step 5.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!)
-
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)
?? In Progress
- Feature 1: ValidatePDF
- ? Step 1.2: API Layer (Endpoint + Exception Middleware) - NEXT
? Pending
-
Feature 1: ValidatePDF
- ? Step 1.2: API Layer (Endpoint + Exception Middleware)
- ? 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) |
END OF ROADMAP
This document is a living document and will be updated after each completed step.