Files
DocumentService/DocumentOperator.API/ROADMAP.md
OlgunR 1b38d5a729 Implement attachment detection in ValidatePDF
Updated PHASENPLAN.md and ROADMAP.md to reflect a complete restructuring of the development plan and added a "Bugfix: Attachment Detection" entry.

Implemented attachment detection in DevExpressPdfProcessor.cs using the new `DetectEmbeddedFiles` method, which scans raw PDF data for the `/EmbeddedFiles` keyword. Updated the `hasAttachments` property to use this method and set `attachmentCount` to `-1` when attachments are detected.

Added a new test, `ValidateAsync_PdfWithoutAttachments_ReturnsNoAttachments`, in DevExpressPdfProcessorTests.cs to verify that PDFs without attachments are correctly identified. Included a note about future testing for PDFs with attachments using ZUGFeRD files.

All related tests are passing (12/12 green).
2026-06-25 16:25:16 +02:00

29 KiB

?? DocumentOperator - Project Roadmap (Feature-Driven Development)

Last Updated: 17.01.2025 | Status: In Development | Current Feature: Feature 1 - ValidatePDF ? ABGESCHLOSSEN!


?? NEW APPROACH: Feature-by-Feature Development

Was hat sich geändert?

? Feature-Driven Development statt Layer-by-Layer

  • Jedes Feature wird KOMPLETT umgesetzt (Domain ? Infrastructure ? Application ? API ? Tests ? Swagger)
  • Feature ist erst "DONE" wenn es im Swagger testbar ist
  • Dann nächstes Feature

? Kleine Schritte (1 Layer pro Step)

  • Besser überschaubar
  • Weniger Merge-Konflikte
  • Schnelleres Feedback

? Multi-Tenancy & Cross-Cutting Concerns später

  • Erst alle synchronen Features implementieren
  • Dann Multi-Tenancy für ALLE Endpoints (kein Wiederholungsaufwand!)
  • Dann Health Checks, Polly, Logging (einmal für alle!)

?? TABLE OF CONTENTS

  1. Feature Roadmap
  2. Project Overview
  3. Architecture & Design Decisions
  4. Technology Stack
  5. Project Structure
  6. Testing Strategy
  7. Current Status
  8. Key Learnings & Decisions

?? FEATURE ROADMAP

?? Feature Overview

Feature Type Status Swagger Testbar?
1. ValidatePDF Synchron ? Abgeschlossen ?
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:

  • 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

    public record ValidatePdfQuery(Base64String PdfContent) : IRequest<PdfMetadata>;
    
  • ? Datei: ValidatePdfHandler.cs

    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

    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

    public record ValidatePdfRequest(string Base64Pdf);
    
  • ? Datei: ValidatePdfResponse.cs

    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
    <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 2: ExtractAttachments


?? FEATURE 2: ExtractAttachments (Synchron) - NEXT

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:

  • /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:

// 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 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 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 Bugfix: Attachment Detection ? IMPLEMENTIERT - ValidatePDF erkennt jetzt Attachments (ZUGFeRD-PDFs) korrekt - 12/12 Tests grün

END OF ROADMAP

This document is a living document and will be updated after each completed step.