Files
Services.DDDocumentOperator/DocumentOperator.API/ROADMAP.md
OlgunR 758d32d8e0 Update ROADMAP.md with detailed project roadmap
- Added "Last Updated" timestamp, current status, and phase.
- Introduced a "TABLE OF CONTENTS" for easier navigation.
- Expanded "PROJECT OVERVIEW" with vision, purpose, and workflow.
- Detailed "ARCHITECTURE & DESIGN DECISIONS" with key patterns.
- Listed frameworks, libraries, and components in "TECH STACK."
- Provided a breakdown of the solution's folder structure.
- Outlined development phases in "DEVELOPMENT ROADMAP."
- Documented progress in "CURRENT STATUS" and added "UPDATE LOG."
- Included "LEARNING NOTES" and references to best practices.
- Improved formatting for clarity and readability.
2026-06-17 15:12:44 +02:00

1641 lines
44 KiB
Markdown

# 📘 DocumentOperator - Project Roadmap
> **Last Updated:** 16.06.2026 | **Status:** In Development | **Phase:** 2 (Domain Layer)
---
## 📋 TABLE OF CONTENTS
1. [Project Overview](#project-overview)
2. [Architecture & Design Decisions](#architecture--design-decisions)
3. [Technology Stack](#technology-stack)
4. [Project Structure](#project-structure)
5. [Development Roadmap](#development-roadmap)
6. [Current Status](#current-status)
---
## 🎯 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)
- Wartbar an einer Stelle
---
### Core Features
Der Service bietet folgende PDF-Operationen:
#### 1. **PDF Validierung**
- Prüfung auf gültiges PDF-Format
- Korruptions-Erkennung
- Metadaten-Extraktion (Seitenzahl, Größe, Version)
#### 2. **Attachment-Extraktion**
- Erkennung von eingebetteten Anhängen
- Extraktion in temporären Ordner
- Rückgabe als Base64 oder Download-Link
#### 3. **PDF-Konkatenation**
- Zusammenführen mehrerer PDFs
- Reihenfolge konfigurierbar
- Seitenzahl-Optimierung
#### 4. **Stempel/Wasserzeichen**
- Aufbringen von Stamps (Logo, Text)
- Positions-Konfiguration
- Mandanten-spezifische Logos
#### 5. **Zertifikat-Einbettung**
- PFX-Zertifikate als Attachment einbetten
- Digitale Signatur-Vorbereitung
- Workflow-Integration (Ergebnisbericht → Zertifikat → Siegel)
---
### Business Workflow
```
Client Application
[HTTP Request] - JSON mit Base64-PDF
DocumentOperator API
[Validierung] → [Operation(en)] → [Ergebnis]
[HTTP Response] - JSON mit verarbeitetem PDF (Base64)
```
**Typischer Ablauf:**
1. Client sendet PDF als Base64 in JSON
2. API validiert Input (FluentValidation)
3. PDF wird in Byte-Array konvertiert
4. Operationen werden durchgeführt (DevExpress)
5. Temporäre Dateien werden erstellt/bereinigt
6. Ergebnis wird als Base64 zurückgegeben
---
## 🏛️ ARCHITECTURE & DESIGN DECISIONS
### Clean Architecture
Wir verwenden **Clean Architecture** mit 4 Layers:
```
┌─────────────────────────────────────┐
│ API Layer (Endpoints) │ ← HTTP Entry Point
├─────────────────────────────────────┤
│ Application Layer (Use Cases) │ ← Business Logic Orchestration
├─────────────────────────────────────┤
│ Infrastructure Layer (Tech Stack) │ ← DevExpress, File I/O, Redis
├─────────────────────────────────────┤
│ Domain Layer (Core Logic) │ ← Business Rules, Models
└─────────────────────────────────────┘
```
#### Dependency Rule (Kritisch!)
**Abhängigkeiten zeigen immer nach innen:**
```
API → Application → Domain
API → Infrastructure → Domain
Infrastructure → Application
Domain → NICHTS! (No External Dependencies)
Application → NUR Domain
```
**Warum?**
- Domain = reine Geschäftslogik, technologie-unabhängig
- Application = Use Cases, kennt nur Interfaces
- Infrastructure = technische Details, austauschbar
- API = dünne Schicht, nur Routing
---
### CQRS with MediatR
**Pattern:** Command Query Responsibility Segregation
**Warum MediatR?**
- ✅ Klare Trennung: 1 Command/Query = 1 Handler
- ✅ Single Responsibility Principle
- ✅ Pipeline Behaviors (Validation, Logging, etc.)
- ✅ Bessere Testbarkeit
- ✅ Keine aufgeblähten Service-Klassen
**Statt:**
```csharp
public class DocumentService {
public void Process() { }
public void Validate() { }
public void Extract() { }
// ... 20 Methoden
}
```
**Nutzen wir:**
```csharp
// Feature: ProcessDocument
public class ProcessDocumentCommand : IRequest<PdfDocument> { }
public class ProcessDocumentHandler : IRequestHandler<ProcessDocumentCommand, PdfDocument> { }
public class ProcessDocumentValidator : AbstractValidator<ProcessDocumentCommand> { }
```
---
### Vertical Slice Architecture
**Statt Horizontal Layers** (Commands/, Handlers/, Validators/):
**Nutzen wir Vertical Slices** (pro Feature alles zusammen):
```
Features/
├── ProcessDocument/
│ ├── ProcessDocumentCommand.cs
│ ├── ProcessDocumentHandler.cs
│ └── ProcessDocumentValidator.cs
├── ExtractAttachments/
│ ├── ExtractAttachmentsCommand.cs
│ ├── ExtractAttachmentsHandler.cs
│ └── ExtractAttachmentsValidator.cs
```
**Vorteile:**
- ✅ Zusammengehöriger Code ist zusammen
- ✅ Einfacher zu finden und zu ändern
- ✅ Feature-basierte Organisation (nicht technische Schichten)
- ✅ Besser für Teams (weniger Merge-Konflikte)
---
### Exception-based Error Handling (Zentral!)
**Entscheidung:** Keine Result Pattern Library (Ardalis.Result entfernt)
**Stattdessen:**
1. **Domain Exceptions** für fachliche Fehler
2. **FluentValidation** für Input-Validierung
3. **Zentrale Exception Handling Middleware** im API Layer
**Warum Exception-basiert?**
- ✅ Einfacherer Code (kein `if (result.IsSuccess)` überall)
- ✅ Weniger Boilerplate
- ✅ Ein Package weniger (keine Extra-Lib)
-**Zentrales Error Handling** = bessere Wartbarkeit
- ✅ Standard .NET Exception-Flow
**Flow:**
```
Request → Validation (FluentValidation Behavior)
Handler (wirft Exception bei Fehler)
Middleware (fängt Exception, mappt zu HTTP Code)
Response (Problem Details RFC 7807)
```
---
### Minimal APIs (statt Controllers)
**Warum Minimal APIs?**
- ✅ .NET 8 Best Practice
- ✅ Weniger Boilerplate (keine Controller-Klassen)
- ✅ Direkte Endpoint-Definition
- ✅ Swagger funktioniert 1:1
- ✅ Bessere Performance
- ✅ Moderner, funktionaler Stil
**Beispiel:**
```csharp
app.MapPost("/api/v1/documents/process", async (
ProcessDocumentRequest request,
IMediator mediator) =>
{
var command = new ProcessDocumentCommand(request);
var result = await mediator.Send(command);
return Results.Ok(result);
})
.WithName("ProcessDocument")
.WithOpenApi();
```
---
### Multi-Tenancy via API-Keys
**Konzept:**
- Jeder Mandant (Customer A, B, C...) hat eigenen API-Key
- API-Key wird in HTTP Header gesendet: `X-API-Key: customer-a-key-12345`
- Middleware resolved API-Key → Tenant-Context
- Tenant-spezifische Einstellungen (Logo für Stamps, Zertifikat, etc.)
**Warum API-Keys?**
- ✅ Einfach für Service-to-Service Communication
- ✅ Security + Tenant-Identification kombiniert
- ✅ Swagger-kompatibel (für BB-Tests)
- ✅ Einfaches Rate-Limiting pro Tenant
**Flow:**
```
Request mit Header "X-API-Key: abc123"
TenantResolutionMiddleware
API-Key → Tenant-Konfiguration
ITenantContext (Scoped DI)
Handler nutzt Tenant-Settings
```
---
## 🛠️ TECHNOLOGY STACK
### Core Framework
| Technology | Version | Purpose |
|------------|---------|---------|
| **.NET** | 8.0 | Runtime & Framework |
| **ASP.NET Core** | 8.0 | Web API |
| **C#** | 12 | Language (mit Primary Constructors, Record Types) |
---
### Key Libraries & 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.Enrichers.Environment** | 3.0.1 | Log-Enrichment (MachineName, etc.) |
| **Asp.Versioning.Http** | 8.1.1 | API Versioning (/api/v1/, /api/v2/) |
| **Microsoft.Extensions.Caching.StackExchangeRedis** | 8.0.28 | Redis Distributed Cache |
#### Application Layer
| Package | Version | Purpose |
|---------|---------|---------|
| **MediatR** | 14.1.0 | CQRS Pattern Implementation |
| **FluentValidation** | 12.1.1 | Input Validation |
| **FluentValidation.DependencyInjectionExtensions** | 12.1.1 | DI Integration |
| ~~Ardalis.Result~~ | ~~10.1.0~~ | ❌ **ENTFERNT** (Exception-basiert stattdessen) |
#### Infrastructure Layer
| Package | Version | Purpose |
|---------|---------|---------|
| **DevExpress.Pdf.Core** | 25.2.8 | PDF-Operationen (Merge, Extract, Sign, etc.) |
| **Microsoft.Extensions.Options.ConfigurationExtensions** | 8.0.0 | Options Pattern |
#### Domain Layer
| Package | Version | Purpose |
|---------|---------|---------|
| - | - | **Keine Dependencies!** (Clean Architecture) |
---
### Infrastructure Components
| Component | Technology | Purpose |
|-----------|------------|---------|
| **Hosting** | IIS | Production Deployment |
| **Cache** | Redis | Distributed Cache (API-Keys, Tenant-Settings) |
| **Message Queue** | (Future) RabbitMQ/Azure Service Bus | Async Processing für große PDFs |
| **Logging** | Serilog → File/Console | Strukturiertes Logging |
| **Temp Storage** | Local File System | Temporäre PDF-Dateien (später: Blob Storage) |
---
## 📁 PROJECT STRUCTURE
### Solution Overview
```
DocumentOperator/
├── DocumentOperator.API/ ← HTTP Entry Point
├── DocumentOperator.Application/ ← Use Cases (MediatR Handlers)
├── DocumentOperator.Infrastructure/← Technical Implementations
├── DocumentOperator.Domain/ ← Core Business Logic
└── ROADMAP.md ← This file
```
---
### 🌐 API Layer (DocumentOperator.API)
**Purpose:** HTTP Entry Point, Routing, Middleware
**References:**
- → Application
- → Infrastructure
- → Domain
**NuGet Packages:**
- Swashbuckle.AspNetCore (Swagger)
- Serilog.AspNetCore + Sinks
- Asp.Versioning.Http
- Microsoft.Extensions.Caching.StackExchangeRedis
**Folder Structure:**
```
DocumentOperator.API/
├── Endpoints/
│ └── v1/
│ └── DocumentEndpoints.cs ← Minimal API Endpoints
├── Middleware/
│ ├── ExceptionHandlingMiddleware.cs ← Zentrale Exception Handling ⭐
│ ├── TenantResolutionMiddleware.cs ← API-Key → Tenant
│ └── RequestLoggingMiddleware.cs ← Request/Response Logging
├── Configuration/
│ ├── SwaggerConfiguration.cs ← Swagger Setup (API-Key Support)
│ └── SerilogConfiguration.cs ← Serilog Helper
├── appsettings.json ← Base Configuration
├── appsettings.Development.json ← Dev Overrides
└── Program.cs ← Application Entry Point
```
**Was gehört hierher?**
- ✅ HTTP Routing (Minimal APIs)
- ✅ Middleware (Exception, Auth, Logging)
- ✅ Swagger Configuration
- ✅ Dependency Injection Setup
- ✅ appsettings.json
**Was NICHT hierher gehört?**
- ❌ Business Logic (→ Application/Domain)
- ❌ PDF-Verarbeitung (→ Infrastructure)
- ❌ Validierung (→ Application: FluentValidation)
---
### 💼 Application Layer (DocumentOperator.Application)
**Purpose:** Use Cases, Business Logic Orchestration
**References:**
- → Domain (ONLY!)
**NuGet Packages:**
- MediatR
- FluentValidation + DI Extensions
**Folder Structure:**
```
DocumentOperator.Application/
├── Features/ ← Vertical Slices
│ └── Documents/
│ ├── ProcessDocument/
│ │ ├── ProcessDocumentCommand.cs
│ │ ├── ProcessDocumentHandler.cs
│ │ └── ProcessDocumentValidator.cs
│ ├── ValidatePdf/
│ │ ├── ValidatePdfQuery.cs
│ │ ├── ValidatePdfHandler.cs
│ │ └── ValidatePdfValidator.cs
│ ├── ExtractAttachments/
│ │ ├── ExtractAttachmentsCommand.cs
│ │ ├── ExtractAttachmentsHandler.cs
│ │ └── ExtractAttachmentsValidator.cs
│ ├── ConcatenatePdfs/
│ │ ├── ConcatenatePdfsCommand.cs
│ │ ├── ConcatenatePdfsHandler.cs
│ │ └── ConcatenatePdfsValidator.cs
│ ├── ApplyStamp/
│ │ ├── ApplyStampCommand.cs
│ │ ├── ApplyStampHandler.cs
│ │ └── ApplyStampValidator.cs
│ └── EmbedCertificate/
│ ├── EmbedCertificateCommand.cs
│ ├── EmbedCertificateHandler.cs
│ └── EmbedCertificateValidator.cs
├── Common/
│ ├── Interfaces/ ← Abstractions für Infrastructure
│ │ ├── IPdfProcessor.cs
│ │ ├── IFileStorageService.cs
│ │ ├── IDocumentValidator.cs
│ │ └── ICertificateService.cs
│ ├── Behaviors/ ← MediatR Pipeline Behaviors
│ │ ├── ValidationBehavior.cs ← FluentValidation Integration ⭐
│ │ ├── LoggingBehavior.cs
│ │ └── ExceptionLoggingBehavior.cs
│ ├── DTOs/ ← Data Transfer Objects
│ │ ├── ProcessDocumentRequest.cs
│ │ ├── ProcessDocumentResponse.cs
│ │ ├── DocumentOperationDto.cs
│ │ ├── AttachmentDto.cs
│ │ └── ErrorResponse.cs ← API Error Format
│ └── Mappings/ ← Domain ↔ DTO
│ └── MappingExtensions.cs
└── DependencyInjection.cs ← Service Registration
```
**Was gehört hierher?**
- ✅ MediatR Commands & Queries
- ✅ Handlers (orchestrieren Domain + Infrastructure)
- ✅ FluentValidation Validators
- ✅ DTOs (API Contracts)
- ✅ Interfaces für Infrastructure (Dependency Inversion!)
- ✅ Pipeline Behaviors
**Was NICHT hierher gehört?**
- ❌ DevExpress-spezifischer Code (→ Infrastructure)
- ❌ File I/O (→ Infrastructure)
- ❌ HTTP-spezifisches (→ API)
- ❌ EF Core / Database (haben wir nicht)
**Warum keine Infrastructure-Referenz?**
- Clean Architecture: Application kennt nur **Interfaces** (`IPdfProcessor`)
- Infrastructure **implementiert** die Interfaces (`DevExpressPdfProcessor`)
- API injected die Implementierung via DI
- → Application bleibt technologie-unabhängig!
---
### 🔧 Infrastructure Layer (DocumentOperator.Infrastructure)
**Purpose:** Technische Implementierungen, externe Abhängigkeiten
**References:**
- → Application (für Interfaces)
- → Domain
**NuGet Packages:**
- DevExpress.Pdf.Core
- Microsoft.Extensions.Options.ConfigurationExtensions
**Folder Structure:**
```
DocumentOperator.Infrastructure/
├── Services/
│ ├── PdfProcessing/
│ │ └── DevExpressPdfProcessor.cs ← IPdfProcessor Implementation
│ ├── FileStorage/
│ │ └── LocalFileStorageService.cs ← IFileStorageService Implementation
│ └── DocumentValidation/
│ └── PdfDocumentValidator.cs ← IDocumentValidator Implementation
├── Configuration/
│ ├── DocumentOperatorSettings.cs ← Options Pattern Class
│ ├── RedisSettings.cs
│ ├── ApiKeySettings.cs
│ └── TenantInfo.cs
└── DependencyInjection.cs ← Service Registration
```
**Was gehört hierher?**
- ✅ DevExpress Integration
- ✅ File System Zugriffe (Temp-Files)
- ✅ Redis Client (später)
- ✅ Externe API Calls (falls benötigt)
- ✅ Options Pattern Classes
**Was NICHT hierher gehört?**
- ❌ Business Logic (→ Application/Domain)
- ❌ HTTP Handling (→ API)
- ❌ Validierung von Inputs (→ Application)
**Beispiel - DevExpressPdfProcessor:**
```csharp
public class DevExpressPdfProcessor : IPdfProcessor
{
public async Task<PdfDocument> MergePdfsAsync(List<PdfDocument> pdfs)
{
using var processor = new PdfDocumentProcessor(); // DevExpress!
// ... DevExpress-spezifischer Code
if (error)
throw new PdfProcessingException("Merge failed"); // Exception!
return result;
}
}
```
---
### 🏛️ Domain Layer (DocumentOperator.Domain)
**Purpose:** Kern-Geschäftslogik, Business Rules
**References:**
-**KEINE!** (wichtigste Clean Architecture Regel)
**NuGet Packages:**
- **KEINE!** (reine C# Klassen)
**Folder Structure:**
```
DocumentOperator.Domain/
├── Models/
│ ├── PdfDocument.cs ← Core Business Model
│ ├── DocumentAttachment.cs
│ ├── DocumentStamp.cs
│ └── DocumentCertificate.cs
├── Models/ValueObjects/ ← Immutable, selbst-validierend
│ ├── Base64String.cs ← Wirft DomainValidationException
│ ├── TenantId.cs
│ └── PdfMetadata.cs
├── Models/Enums/
│ ├── DocumentOperationType.cs ← Extract, Concatenate, Stamp, Sign
│ ├── ProcessingStatus.cs ← Pending, Processing, Success, Failed
│ └── PdfValidationError.cs ← InvalidFormat, TooLarge, Corrupted
├── Common/
│ └── Exceptions/ ← Domain-spezifische Exceptions
│ ├── DomainException.cs ← Basis-Exception
│ ├── DomainValidationException.cs← Value Object Validierung
│ ├── NotFoundException.cs ← Resource nicht gefunden
│ └── PdfProcessingException.cs ← PDF-spezifische Fehler
└── Constants/
├── ErrorCodes.cs ← Konstanten für Error Messages
└── ValidationMessages.cs
```
**Was gehört hierher?**
- ✅ Business Models (PdfDocument, etc.)
- ✅ Value Objects (Base64String, TenantId)
- ✅ Enums (DocumentOperationType)
- ✅ Business Rules (z.B. "Max 100 Seiten")
- ✅ Domain Exceptions
- ✅ Constants
**Was NICHT hierher gehört?**
- ❌ DevExpress (→ Infrastructure)
- ❌ MediatR (→ Application)
- ❌ DTOs (→ Application)
- ❌ Validation Logic (→ Application: FluentValidation)
- ❌ JEGLICHE externe Library!
**Warum keine Dependencies?**
- Domain = Herz der Anwendung
- Sollte **ewig** leben (auch wenn Tech-Stack wechselt)
- Keine Abhängigkeit von Frameworks = langlebig
- Pure C# Business Logic
---
## 🗺️ DEVELOPMENT ROADMAP
---
### ✅ **PHASE 1: Foundation & Clean Architecture Setup** - **COMPLETED**
**Ziel:** Saubere Architektur-Basis ohne Funktionalität
#### ✅ Step 1.1: Projekt-Dependencies korrigieren - **DONE**
- [x] Application: Infrastructure-Referenz entfernt
- [x] Infrastructure: Application-Referenz hinzugefügt
- [x] Verify: Domain hat keine Dependencies
- [x] Build: Erfolgreich
**Ergebnis:** Clean Architecture Dependency Rules eingehalten
---
#### ✅ Step 1.2: NuGet Packages installieren - **DONE**
**Application:**
- [x] MediatR (14.1.0)
- [x] FluentValidation (12.1.1)
- [x] FluentValidation.DependencyInjectionExtensions (12.1.1)
- [x] ~~Ardalis.Result (10.1.0)~~**ENTFERNT** (Exception-basiert)
**Infrastructure:**
- [x] DevExpress.Pdf.Core (25.2.8)
- [x] Microsoft.Extensions.Options.ConfigurationExtensions (8.0.0)
**API:**
- [x] Serilog.AspNetCore (10.0.0)
- [x] Serilog.Enrichers.Environment (3.0.1)
- [x] Serilog.Sinks.File (7.0.0)
- [x] Asp.Versioning.Http (8.1.1)
- [x] Microsoft.Extensions.Caching.StackExchangeRedis (8.0.28)
- [x] Swashbuckle.AspNetCore (6.6.2)
**Ergebnis:** Alle Packages installiert, neueste stable Versionen
---
#### ✅ Step 1.3: Folder-Struktur erstellen - **DONE**
**Domain:**
- [x] Models/
- [x] Models/ValueObjects/
- [x] Models/Enums/
- [x] Common/
- [x] Common/Exceptions/
- [x] Constants/
**Application:**
- [x] Features/
- [x] Features/Documents/
- [x] Features/Documents/ProcessDocument/
- [x] Features/Documents/ValidatePdf/
- [x] Features/Documents/ExtractAttachments/
- [x] Features/Documents/ConcatenatePdfs/
- [x] Features/Documents/ApplyStamp/
- [x] Features/Documents/EmbedCertificate/
- [x] Common/
- [x] Common/Interfaces/
- [x] Common/Behaviors/
- [x] Common/DTOs/
- [x] Common/Mappings/
**Infrastructure:**
- [x] Services/
- [x] Services/PdfProcessing/
- [x] Services/FileStorage/
- [x] Services/DocumentValidation/
- [x] Configuration/
**API:**
- [x] Endpoints/
- [x] Endpoints/v1/
- [x] Middleware/
- [x] Configuration/
- [x] Controllers/ → **GELÖSCHT** (Minimal APIs!)
**Ergebnis:** Komplette Ordnerstruktur nach Clean Architecture
---
#### ✅ Step 1.4: Basis-Configuration - **DONE**
**Part A: appsettings.json**
- [x] appsettings.json mit allen Settings erstellt
- Serilog Configuration
- DocumentOperatorSettings
- RedisSettings
- ApiKeySettings (Demo-Keys)
- [x] appsettings.Development.json für Dev-Overrides
- [x] .gitignore vorhanden (bereits existiert)
**Part B: Options Classes**
- [x] DocumentOperatorSettings.cs
- [x] RedisSettings.cs
- [x] ApiKeySettings.cs
- [x] TenantInfo.cs (als separate Klasse ✅ Best Practice!)
**Part C: Serilog Setup**
- [x] Program.cs erweitert mit Serilog
- [x] Options Pattern registriert
- [x] Try/Catch für Startup-Errors
- [x] Serilog Request Logging aktiviert
- [x] Serilog Enrichers installiert
**Ergebnis:** Produktionsreife Konfiguration, Logging funktioniert
---
### 🔄 **PHASE 2: Domain Layer** - **IN PROGRESS**
**Ziel:** Business Models ohne technische Dependencies erstellen
---
#### ✅ Step 2.1: Domain Exceptions erstellen - **COMPLETED**
**Aufgabe:** Custom Exception-Klassen für fachliche Fehler
**Erstellt:**
1. [x] `DomainException.cs` (Basis-Exception)
2. [x] `DomainValidationException.cs` (Value Object Validierung)
3. [x] `NotFoundException.cs` (Resource nicht gefunden)
4. [x] `PdfProcessingException.cs` (PDF-spezifische Fehler)
**Wo:** `Domain/Common/Exceptions/`
**Warum Exceptions?**
- Zentrale Exception Handling Middleware (API Layer)
- Einfacher Code (keine Result<T> Checks)
- Standard .NET Exception-Flow
- Wartbar an einer Stelle
**Verwendung:**
```csharp
// In Value Objects:
if (invalid)
throw new DomainValidationException("Base64 cannot be empty");
// In Handlers:
if (notFound)
throw new NotFoundException("Document", id);
// Middleware fängt ab und mapped zu HTTP 400/404/500
```
---
#### 🔄 Step 2.2: Value Objects erstellen - **NEXT**
**Aufgabe:** Typsichere, selbst-validierende Wert-Objekte
**Zu erstellen:**
1. [ ] `Base64String.cs`
- Factory Method: `Create(string value)`
- Validierung: Gültiges Base64-Format
- Konvertierung: `ToByteArray()`, `FromByteArray()`
- Wirft `DomainValidationException` bei Fehler
2. [ ] `TenantId.cs`
- Factory Method: `Create(string value)`
- Validierung: Nicht leer, Max 100 Zeichen
- Normalisierung: `.ToLowerInvariant()`
- Wirft `DomainValidationException` bei Fehler
3. [ ] `PdfMetadata.cs`
- Properties: PageCount, FileSizeBytes, PdfVersion, HasAttachments
- Computed Property: `FileSizeMB`
- Keine Validierung (nur Daten-Container)
**Wo:** `Domain/Models/ValueObjects/`
**Warum Value Objects?**
- ✅ Typsicherheit: `Base64String` statt `string`
- ✅ Validierung an **einer** Stelle (Constructor)
- ✅ Immutable (keine Änderungen nach Erstellung)
- ✅ Domain-Driven Design Best Practice
---
#### ⏳ Step 2.3: Enums erstellen
**Aufgabe:** Aufzählungen für Business-Konzepte
**Zu erstellen:**
1. [ ] `DocumentOperationType.cs`
```csharp
public enum DocumentOperationType
{
Validate,
ExtractAttachments,
Concatenate,
ApplyStamp,
EmbedCertificate
}
```
2. [ ] `ProcessingStatus.cs`
```csharp
public enum ProcessingStatus
{
Pending,
Processing,
Success,
Failed
}
```
3. [ ] `PdfValidationError.cs`
```csharp
public enum PdfValidationError
{
InvalidFormat,
FileTooLarge,
Corrupted,
UnsupportedVersion,
NoPages
}
```
**Wo:** `Domain/Models/Enums/`
---
#### ⏳ Step 2.4: Domain Models erstellen
**Aufgabe:** Kern-Business-Objekte
**Zu erstellen:**
1. [ ] `PdfDocument.cs` (Core Model)
- Properties: Id, Base64Content, Metadata, Attachments, Status
- Methods: AddAttachment(), ApplyStamp(), etc.
2. [ ] `DocumentAttachment.cs`
- Properties: FileName, Content (Base64), FileSize, MimeType
3. [ ] `DocumentStamp.cs`
- Properties: Text, Position, Logo (Base64), TenantId
4. [ ] `DocumentCertificate.cs`
- Properties: PfxContent (Base64), Password, Issuer
**Wo:** `Domain/Models/`
**Warum Domain Models?**
- Repräsentieren Business-Konzepte
- Enthalten Business Rules
- Keine Datenbank-Annotations (wir haben kein EF Core!)
- Pure C# Klassen
---
#### ⏳ Step 2.5: Constants erstellen
**Aufgabe:** Konstanten für Error Messages, Limits, etc.
**Zu erstellen:**
1. [ ] `ErrorCodes.cs`
```csharp
public static class ErrorCodes
{
public const string InvalidBase64 = "ERR_INVALID_BASE64";
public const string PdfTooLarge = "ERR_PDF_TOO_LARGE";
public const string InvalidTenant = "ERR_INVALID_TENANT";
}
```
2. [ ] `ValidationMessages.cs`
```csharp
public static class ValidationMessages
{
public const string Base64Empty = "Base64 string cannot be empty";
public const string TenantIdEmpty = "TenantId is required";
}
```
**Wo:** `Domain/Constants/`
**Warum Constants?**
- Keine Magic Strings im Code
- Wiederverwendbar
- Leicht änderbar (an einer Stelle)
---
### ⏳ **PHASE 3: Application Layer**
**Ziel:** Use Cases mit MediatR implementieren
---
#### ⏳ Step 3.1: MediatR Setup & Behaviors
**Aufgabe:** MediatR konfigurieren + Pipeline Behaviors
**Zu erstellen:**
1. [ ] `DependencyInjection.cs` (Application Layer)
- MediatR registrieren
- FluentValidation registrieren
- Behaviors registrieren
2. [ ] `ValidationBehavior.cs` ⭐
- Vor jedem Handler: FluentValidation ausführen
- Bei Fehler: `ValidationException` werfen
- Middleware fängt ab → HTTP 400
3. [ ] `LoggingBehavior.cs`
- Request/Response loggen
- Execution Time messen
4. [ ] `ExceptionLoggingBehavior.cs`
- Exceptions loggen bevor sie propagieren
**Wo:** `Application/Common/Behaviors/`
**Warum Behaviors?**
- Cross-Cutting Concerns (Validation, Logging)
- DRY: Nicht in jedem Handler wiederholen
- Pipeline Pattern
---
#### ⏳ Step 3.2: Interfaces für Infrastructure
**Aufgabe:** Abstractions definieren (Dependency Inversion!)
**Zu erstellen:**
1. [ ] `IPdfProcessor.cs`
```csharp
public interface IPdfProcessor
{
Task<PdfDocument> MergePdfsAsync(List<PdfDocument> pdfs);
Task<List<DocumentAttachment>> ExtractAttachmentsAsync(PdfDocument pdf);
Task<PdfDocument> ApplyStampAsync(PdfDocument pdf, DocumentStamp stamp);
Task<PdfDocument> EmbedCertificateAsync(PdfDocument pdf, DocumentCertificate cert);
}
```
2. [ ] `IFileStorageService.cs`
```csharp
public interface IFileStorageService
{
Task<string> SaveTempFileAsync(byte[] content, string extension);
Task<byte[]> LoadTempFileAsync(string path);
Task DeleteTempFileAsync(string path);
Task CleanupOldFilesAsync(TimeSpan maxAge);
}
```
3. [ ] `IDocumentValidator.cs`
```csharp
public interface IDocumentValidator
{
Task<PdfMetadata> ValidateAsync(PdfDocument pdf);
bool IsValidFormat(byte[] content);
}
```
4. [ ] `ICertificateService.cs`
```csharp
public interface ICertificateService
{
Task<bool> ValidateCertificateAsync(DocumentCertificate cert);
}
```
**Wo:** `Application/Common/Interfaces/`
**Warum Interfaces?**
- Application kennt nur Verträge (nicht Implementierung)
- Infrastructure implementiert
- Testbar (Mocking)
- Clean Architecture Dependency Rule
---
#### ⏳ Step 3.3: DTOs erstellen
**Aufgabe:** Data Transfer Objects für API
**Zu erstellen:**
1. [ ] `ProcessDocumentRequest.cs` (Record Type)
```csharp
public record ProcessDocumentRequest(
string Base64Pdf,
string TenantId,
List<DocumentOperationDto> Operations
);
```
2. [ ] `ProcessDocumentResponse.cs`
```csharp
public record ProcessDocumentResponse(
string Base64Pdf,
PdfMetadata Metadata,
List<string> PerformedOperations,
bool Success
);
```
3. [ ] `DocumentOperationDto.cs`
```csharp
public record DocumentOperationDto(
DocumentOperationType Type,
Dictionary<string, object>? Parameters
);
```
4. [ ] `AttachmentDto.cs`
5. [ ] `ErrorResponse.cs` (für Exception Middleware)
**Wo:** `Application/Common/DTOs/`
**Warum DTOs?**
- API Contracts (können sich ändern ohne Domain zu ändern)
- Validation (FluentValidation)
- Serialization-friendly
---
#### ⏳ Step 3.4: Erste Feature - ValidatePdf
**Aufgabe:** Erste komplette Feature-Implementierung
**Zu erstellen:**
1. [ ] `ValidatePdfQuery.cs`
```csharp
public record ValidatePdfQuery(string Base64Pdf, string TenantId)
: IRequest<PdfMetadata>;
```
2. [ ] `ValidatePdfHandler.cs`
```csharp
public class ValidatePdfHandler : IRequestHandler<ValidatePdfQuery, PdfMetadata>
{
public async Task<PdfMetadata> Handle(...)
{
var base64 = Base64String.Create(query.Base64Pdf); // Wirft Exception
var pdf = new PdfDocument(base64);
var metadata = await _validator.ValidateAsync(pdf);
return metadata;
}
}
```
3. [ ] `ValidatePdfValidator.cs` (FluentValidation)
```csharp
public class ValidatePdfValidator : AbstractValidator<ValidatePdfQuery>
{
public ValidatePdfValidator()
{
RuleFor(x => x.Base64Pdf).NotEmpty();
RuleFor(x => x.TenantId).NotEmpty();
}
}
```
**Wo:** `Application/Features/Documents/ValidatePdf/`
**Flow:**
```
API → ValidatePdfQuery
→ ValidationBehavior (FluentValidation)
→ ValidatePdfHandler
→ IDocumentValidator (Infrastructure)
→ PdfMetadata zurück
```
---
#### ⏳ Step 3.5: Weitere Features
Nach ValidatePdf (als Beispiel):
- [ ] ProcessDocument (orchestriert andere Commands)
- [ ] ExtractAttachments
- [ ] ConcatenatePdfs
- [ ] ApplyStamp
- [ ] EmbedCertificate
Jeweils: Command/Query + Handler + Validator
---
### ⏳ **PHASE 4: Infrastructure Layer**
**Ziel:** Interfaces implementieren mit echten Technologien
---
#### ⏳ Step 4.1: DevExpress PDF Service
**Aufgabe:** `IPdfProcessor` implementieren
**Zu erstellen:**
1. [ ] `DevExpressPdfProcessor.cs : IPdfProcessor`
```csharp
public class DevExpressPdfProcessor : IPdfProcessor
{
public async Task<PdfDocument> MergePdfsAsync(List<PdfDocument> pdfs)
{
try
{
using var processor = new PdfDocumentProcessor(); // DevExpress!
foreach (var pdf in pdfs)
{
processor.AppendDocument(pdf.ToStream());
}
var result = processor.SaveDocument();
return new PdfDocument(result);
}
catch (Exception ex)
{
throw new PdfProcessingException("PDF merge failed", ex);
}
}
// ExtractAttachments(), ApplyStamp(), EmbedCertificate() ...
}
```
**Wo:** `Infrastructure/Services/PdfProcessing/`
**Wichtig:**
- Wirft `PdfProcessingException` bei Fehlern
- Nutzt DevExpress API
- Async wo möglich
---
#### ⏳ Step 4.2: File Storage Service
**Aufgabe:** `IFileStorageService` implementieren
**Zu erstellen:**
1. [ ] `LocalFileStorageService.cs : IFileStorageService`
```csharp
public class LocalFileStorageService : IFileStorageService
{
private readonly DocumentOperatorSettings _settings;
public async Task<string> SaveTempFileAsync(byte[] content, string extension)
{
var fileName = $"{Guid.NewGuid()}{extension}";
var path = Path.Combine(_settings.TempFolderPath, fileName);
Directory.CreateDirectory(_settings.TempFolderPath);
await File.WriteAllBytesAsync(path, content);
return path;
}
// LoadTempFileAsync(), DeleteTempFileAsync(), CleanupOldFilesAsync()
}
```
**Wo:** `Infrastructure/Services/FileStorage/`
**Features:**
- Nutzt `DocumentOperatorSettings.TempFolderPath`
- Cleanup für alte Dateien (Background Service später)
- Exception Handling
---
#### ⏳ Step 4.3: Document Validator
**Aufgabe:** `IDocumentValidator` implementieren
**Zu erstellen:**
1. [ ] `PdfDocumentValidator.cs : IDocumentValidator`
```csharp
public class PdfDocumentValidator : IDocumentValidator
{
public async Task<PdfMetadata> ValidateAsync(PdfDocument pdf)
{
using var processor = new PdfDocumentProcessor();
processor.LoadDocument(pdf.ToStream());
if (processor.Document.Pages.Count == 0)
throw new PdfProcessingException("PDF has no pages");
return new PdfMetadata(
pageCount: processor.Document.Pages.Count,
fileSizeBytes: pdf.Content.Length,
pdfVersion: processor.Document.Version.ToString(),
hasAttachments: processor.Document.Attachments.Count > 0,
attachmentCount: processor.Document.Attachments.Count
);
}
}
```
**Wo:** `Infrastructure/Services/DocumentValidation/`
---
#### ⏳ Step 4.4: DI Registration
**Aufgabe:** Services registrieren
**Zu erstellen:**
1. [ ] `DependencyInjection.cs` (Infrastructure Layer)
```csharp
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(
this IServiceCollection services)
{
services.AddScoped<IPdfProcessor, DevExpressPdfProcessor>();
services.AddScoped<IFileStorageService, LocalFileStorageService>();
services.AddScoped<IDocumentValidator, PdfDocumentValidator>();
return services;
}
}
```
**In Program.cs aufrufen:**
```csharp
builder.Services.AddInfrastructure();
```
---
### ⏳ **PHASE 5: API Layer - Minimal APIs & Middleware**
**Ziel:** HTTP Endpoints + Exception Handling
---
#### ⏳ Step 5.1: Exception Handling Middleware ⭐
**Aufgabe:** Zentrale Exception → HTTP Response Mapping
**Zu erstellen:**
1. [ ] `ExceptionHandlingMiddleware.cs`
```csharp
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionHandlingMiddleware> _logger;
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (DomainValidationException ex)
{
_logger.LogWarning(ex, "Validation error");
await HandleValidationExceptionAsync(context, ex);
}
catch (NotFoundException ex)
{
_logger.LogWarning(ex, "Resource not found");
await HandleNotFoundExceptionAsync(context, ex);
}
catch (PdfProcessingException ex)
{
_logger.LogError(ex, "PDF processing failed");
await HandlePdfProcessingExceptionAsync(context, ex);
}
catch (ValidationException ex) // FluentValidation
{
_logger.LogWarning(ex, "Input validation failed");
await HandleFluentValidationExceptionAsync(context, ex);
}
catch (Exception ex)
{
_logger.LogCritical(ex, "Unhandled exception");
await HandleUnexpectedExceptionAsync(context, ex);
}
}
private static Task HandleValidationExceptionAsync(HttpContext context, DomainValidationException ex)
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
var problemDetails = new ProblemDetails
{
Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1",
Title = "Validation Error",
Status = StatusCodes.Status400BadRequest,
Detail = ex.Message,
Instance = context.Request.Path
};
return context.Response.WriteAsJsonAsync(problemDetails);
}
// HandleNotFoundException(), HandlePdfProcessingException(), etc.
}
```
**Wo:** `API/Middleware/`
**Registrieren in Program.cs:**
```csharp
app.UseMiddleware<ExceptionHandlingMiddleware>();
```
**Warum zentral?**
- ✅ Alle Fehler an **einer** Stelle
- ✅ Konsistente Error-Responses
- ✅ Logging zentral
- ✅ HTTP Status Code Mapping
- ✅ Wartbar!
---
#### ⏳ Step 5.2: Minimal API Endpoints
**Aufgabe:** HTTP Endpoints definieren
**Zu erstellen:**
1. [ ] `DocumentEndpoints.cs`
```csharp
public static class DocumentEndpoints
{
public static IEndpointRouteBuilder MapDocumentEndpoints(
this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/v1/documents")
.WithTags("Documents")
.WithOpenApi();
group.MapPost("/validate", ValidatePdf)
.WithName("ValidatePdf")
.Produces<PdfMetadata>(StatusCodes.Status200OK)
.Produces<ProblemDetails>(StatusCodes.Status400BadRequest);
group.MapPost("/process", ProcessDocument)
.WithName("ProcessDocument");
group.MapPost("/extract-attachments", ExtractAttachments);
group.MapPost("/concatenate", ConcatenatePdfs);
group.MapPost("/stamp", ApplyStamp);
group.MapPost("/sign", EmbedCertificate);
return app;
}
private static async Task<IResult> ValidatePdf(
ValidatePdfRequest request,
IMediator mediator,
CancellationToken ct)
{
var query = new ValidatePdfQuery(request.Base64Pdf, request.TenantId);
var result = await mediator.Send(query, ct);
return Results.Ok(result);
}
// ProcessDocument(), ExtractAttachments(), etc.
}
```
**Wo:** `API/Endpoints/v1/`
**In Program.cs registrieren:**
```csharp
app.MapDocumentEndpoints();
```
**Features:**
- Minimal APIs (keine Controller-Klassen!)
- OpenAPI/Swagger Integration
- MediatR aufrufen
- Middleware fängt Exceptions ab
---
#### ⏳ Step 5.3: Swagger Configuration
**Aufgabe:** Swagger mit API-Key Support
**Zu erstellen:**
1. [ ] `SwaggerConfiguration.cs`
```csharp
public static class SwaggerConfiguration
{
public static IServiceCollection AddSwaggerConfiguration(
this IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "DocumentOperator API",
Version = "v1",
Description = "Zentralisierter PDF-Operationen Service"
});
// API-Key Support
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
{
Description = "API Key (Header: X-API-Key)",
Name = "X-API-Key",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "ApiKeyScheme"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "ApiKey"
}
},
Array.Empty<string>()
}
});
});
return services;
}
}
```
**Wo:** `API/Configuration/`
**Ergebnis:**
- Swagger UI zeigt "Authorize" Button
- Dev-Leiter kann API-Key eingeben für Tests
- Alle Requests enthalten X-API-Key Header
---
#### ⏳ Step 5.4: Tenant Resolution Middleware
**Aufgabe:** API-Key → Tenant Context
**Zu erstellen:**
1. [ ] `TenantResolutionMiddleware.cs`
```csharp
public class TenantResolutionMiddleware
{
public async Task InvokeAsync(HttpContext context)
{
var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
if (string.IsNullOrEmpty(apiKey))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsJsonAsync(new ProblemDetails
{
Title = "API Key Missing",
Status = 401
});
return;
}
// API-Key → Tenant auflösen (aus ApiKeySettings)
var tenantInfo = _apiKeySettings.Keys.GetValueOrDefault(apiKey);
if (tenantInfo == null || !tenantInfo.IsActive)
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
// Tenant-Context in DI (Scoped)
var tenantContext = context.RequestServices.GetRequiredService<ITenantContext>();
tenantContext.SetTenant(tenantInfo.TenantId, tenantInfo.TenantName);
await _next(context);
}
}
```
**Wo:** `API/Middleware/`
**Flow:**
```
Request mit X-API-Key → Middleware
→ API-Key validieren
→ Tenant auflösen
→ TenantContext setzen
→ Handler nutzt TenantContext
```
---
### ⏳ **PHASE 6: Multi-Tenancy & Security**
**Ziel:** Mandantenfähigkeit implementieren
#### ⏳ Steps:
- [ ] `ITenantContext` Interface (Application)
- [ ] `TenantContext` Implementation (Infrastructure)
- [ ] Rate Limiting pro Tenant
- [ ] Tenant-spezifische Settings (Logo, Zertifikat)
---
### ⏳ **PHASE 7: Distributed Cache (Redis)**
**Ziel:** Performance-Optimierung
#### ⏳ Steps:
- [ ] Redis Connection Setup
- [ ] Cache für API-Key Validation
- [ ] Cache für Tenant-Settings
- [ ] Cache Invalidation Strategy
---
### ⏳ **PHASE 8: Testing**
**Ziel:** Qualitätssicherung
#### ⏳ Steps:
- [ ] Unit Tests (Application Handlers)
- [ ] Integration Tests (API Endpoints)
- [ ] Test-PDFs erstellen
- [ ] Coverage >80%
---
### ⏳ **PHASE 9: Deployment (IIS)**
**Ziel:** Production-Ready
#### ⏳ Steps:
- [ ] appsettings.Production.json
- [ ] IIS Application Pool (.NET 8)
- [ ] HTTPS Binding
- [ ] Environment Variables
- [ ] Health Checks
---
## 📊 CURRENT STATUS
### ✅ Completed
- **Phase 1:** Foundation & Clean Architecture Setup
- Dependencies ✅
- Packages ✅
- Folder Structure ✅
- Configuration ✅
- Serilog ✅
### 🔄 In Progress
- **Phase 2:** Domain Layer
- ✅ Step 2.1 - Domain Exceptions
- **NEXT:** Step 2.2 - Value Objects
### ⏳ Pending
- Phase 3-9
---
## 🎓 LEARNING NOTES
### Clean Architecture Principles Learned
1. **Dependency Rule:** Immer nach innen (Domain kennt nichts, Application nur Domain, etc.)
2. **Separation of Concerns:** Jede Schicht hat klare Verantwortung
3. **Value Objects:** Typsicherheit + Validierung in einem
4. **CQRS:** Klare Trennung Commands/Queries
5. **Vertical Slices:** Feature-basiert statt Layer-basiert
### Exception-based Error Handling
**Vorteile erkannt:**
- Einfacherer Code (kein Result<T> Boilerplate)
- Zentrales Handling (Middleware)
- Wartbarer (Fehler-Mapping an einer Stelle)
- Standard .NET Flow
**Wichtig:**
- FluentValidation für Input (erste Verteidigung)
- Domain Exceptions für Business-Fehler
- Middleware mapped zu HTTP Status Codes
- Serilog loggt alles
---
## 📚 REFERENCES & RESOURCES
### Documentation
- [Clean Architecture (Uncle Bob)](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
- [MediatR Documentation](https://github.com/jbogard/MediatR)
- [FluentValidation Docs](https://docs.fluentvalidation.net/)
- [DevExpress PDF API](https://docs.devexpress.com/OfficeFileAPI/114877/pdf-document-api)
- [ASP.NET Core Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis)
- [RFC 7807 Problem Details](https://datatracker.ietf.org/doc/html/rfc7807)
### Best Practices Applied
- ✅ Vertical Slice Architecture
- ✅ Options Pattern für Configuration
- ✅ Dependency Injection
- ✅ Async/Await überall
- ✅ Nullable Reference Types
- ✅ Record Types für DTOs (C# 12)
- ✅ Primary Constructors (.NET 8)
- ✅ Structured Logging (Serilog)
---
## 🔄 UPDATE LOG
| Date | Phase | Changes |
|------|-------|---------|
| 2024-XX-XX | Phase 1 | Project setup, dependencies, folder structure |
| 2024-XX-XX | Phase 1 | Configuration, Serilog, Options Pattern |
| 2024-XX-XX | Phase 1 | **Decision:** Exception-based statt Ardalis.Result |
| 2024-XX-XX | Phase 1 | ✅ Phase 1 completed |
| 2024-XX-XX | Phase 2 | ✅ Step 2.1 completed - Domain Exceptions created |
| 2024-XX-XX | Phase 2 | 🔄 Starting Step 2.2 - Value Objects |
---
**END OF ROADMAP**
*This document is a living document and will be updated as development progresses.*