Migrate all repos into monorepo context folders

Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
This commit is contained in:
2026-06-30 20:39:52 +02:00
parent 2f2b295531
commit a5f8fb49ab
1717 changed files with 447332 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
# Clean Code & Architektur
## Architektur: Ports & Adapters (Hexagonal)
```
┌─────────────────────────────────────────┐
│ Application Core │
│ ┌─────────────────────────────────┐ │
│ │ Domain Model │ │
│ │ (Entities, Value Objects) │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ Use Cases / Services │ │
│ │ (Business Logic, Ports) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
▲ ▲
Driving Ports Driven Ports
│ │
┌────────┴───────┐ ┌────────┴───────┐
│ REST API │ │ Repository │
│ (Adapter) │ │ (Adapter) │
│ Controller │ │ JPA/JDBC │
└────────────────┘ └────────────────┘
```
- **Domain**: Reine Business-Logik, keine Framework-Abhängigkeiten
- **Ports**: Interfaces die Use Cases definieren (inbound) und externe Systeme abstrahieren (outbound)
- **Adapters**: Implementierungen (REST Controller, JPA Repository, Kafka Consumer)
## Separation of Concerns
- **Controller/Handler**: Nur Request/Response Mapping, Validierung, keine Business-Logik
- **Service**: Business-Logik, Orchestrierung, Transaktionen
- **Repository/DAO**: Datenzugriff, Queries
- **Model/Entity**: Datenstrukturen, Domain-Logik
- **DTO**: Daten-Transfer zwischen Schichten (nicht Entity direkt exponieren)
- **Mapper**: Entity ↔ DTO Konvertierung
- **Config**: Konfiguration, Beans, Dependency Injection
## Exception Handling
### Strategie
- **Domain Exceptions**: Fachliche Fehler (z.B. `AddressNotFoundException`)
- **Global Exception Handler**: `@RestControllerAdvice` für einheitliche Error-Responses
- **Keine generischen Exceptions** werfen (nicht `throw new RuntimeException`)
- **HTTP Status Codes** korrekt nutzen (400, 404, 409, 422, 500)
### Pattern
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) {
return ResponseEntity.status(404)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleValidation(ConstraintViolationException ex) {
return ResponseEntity.status(400)
.body(new ErrorResponse("VALIDATION_ERROR", ex.getMessage()));
}
}
```
## Observability (Logging, Tracing, Metrics)
### Logging
- **Structured Logging** (JSON) mit SLF4J/Logback
- Log-Level: ERROR (Fehler), WARN (unerwartetes Verhalten), INFO (Business-Events), DEBUG (Entwicklung)
- **Correlation-ID** in jedem Log-Eintrag (aus Request-Header oder generiert)
- Keine sensiblen Daten loggen (Passwörter, Tokens, PII)
### Tracing (OpenTelemetry)
- **OTEL** für Distributed Tracing (Spring Boot Actuator + Micrometer)
- Trace-ID und Span-ID in Logs propagieren
- Externe Calls (DB, HTTP, Kafka) automatisch instrumentiert
```yaml
# application.yml
management:
tracing:
sampling:
probability: 1.0
otlp:
tracing:
endpoint: http://k8s-monitoring-alloy-receiver.monitoring.svc.cluster.local:4317
# CNP Grafana Alloy - OTLP gRPC Port 4317
# Doku: https://cnp.gitpages.tech.rz.db.de/core/docs/cnp/latest/cnp-portfolio/observability/tracing.html
```
### Metrics
- Spring Boot Actuator Endpoints (`/actuator/health`, `/actuator/metrics`, `/actuator/prometheus`)
- Custom Business-Metrics wo sinnvoll (z.B. Bestellungen pro Minute)
- Prometheus-Format für Grafana-Dashboards
### Health Checks
```yaml
management:
endpoint:
health:
show-details: always
health:
db:
enabled: true
kafka:
enabled: true
```
## Clean Code Prinzipien
- **Single Responsibility**: Eine Klasse/Funktion = eine Aufgabe
- **DRY**: Keine Code-Duplikation, gemeinsame Logik extrahieren
- **KISS**: Einfachste Lösung die funktioniert
- **YAGNI**: Nichts implementieren was nicht gefordert ist
- **Dependency Injection**: Abhängigkeiten injizieren, nicht selbst erstellen
- **Interface Segregation**: Kleine, fokussierte Interfaces
- **Open/Closed**: Offen für Erweiterung, geschlossen für Änderung
## Naming
- Klassen: PascalCase, Substantive (UserService, OrderRepository)
- Methoden: camelCase, Verben (findById, createUser, validateInput)
- Variablen: camelCase, sprechend (userCount statt n, isActive statt flag)
- Konstanten: UPPER_SNAKE_CASE
- Packages: lowercase, Singular (controller, service, model)
## Methoden
- Max 20 Zeilen (Richtwert)
- Max 3 Parameter (sonst Object/DTO)
- Keine boolean-Parameter (Split in zwei Methoden)
- Early Return statt tiefe Verschachtelung
## Error Responses (API)
Einheitliches Format:
```json
{
"error": "NOT_FOUND",
"message": "Address with id 42 not found",
"timestamp": "2026-05-17T19:00:00Z",
"path": "/api/addresses/42"
}
```
## Configuration
- **application.yml** für Defaults
- **application-{profile}.yml** für Stage-spezifisch (dev, iu, prod)
- Secrets NICHT in application.yml (über Env-Variablen oder SecretProviderClass)
- **@ConfigurationProperties** statt @Value für typsichere Config
## Mapper: MapStruct
Entity ↔ DTO Mapping über **MapStruct** (compile-time, kein Reflection):
```java
@Mapper(componentModel = "spring")
public interface AddressMapper {
AddressDto toDto(Address entity);
Address toEntity(AddressDto dto);
List<AddressDto> toDtoList(List<Address> entities);
}
```
- Kein manuelles Mapping in Services
- MapStruct generiert Implementierung zur Compile-Zeit
- Bei komplexen Mappings: `@Mapping(source = "...", target = "...")`
## Lombok
Getter, Setter, Builder über **Lombok** (kein Boilerplate):
```java
@Data // Getter + Setter + toString + equals + hashCode
@Builder // Builder-Pattern
@NoArgsConstructor // JPA braucht Default-Konstruktor
@AllArgsConstructor // Für Builder
@Entity
public class Address {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String street;
private String city;
private String zip;
}
```
### Konventionen
- `@Data` für Entities und DTOs
- `@Builder` für DTOs (immutable Construction)
- `@Value` für immutable Value Objects (statt @Data)
- `@Slf4j` für Logger (statt `private static final Logger log = ...`)
- `@RequiredArgsConstructor` für Constructor-Injection (statt @Autowired)
## Validierung
### Schichten
1. **Bean Validation** (`@Valid`, `@NotNull`, `@Size`) Syntaktische Prüfung im Controller
2. **Business Rules** Fachliche Validierung im Service/Validator (eigene Schicht)
3. **Domain Invarianten** Im Entity selbst (z.B. `@PrePersist`)
### Pattern: Separater Validator
```java
@Component
@RequiredArgsConstructor
public class OrderValidator {
public void validate(OrderRequest request) {
if (request.getQuantity() > MAX_QUANTITY) {
throw new BusinessRuleViolationException("Maximale Bestellmenge überschritten");
}
// Weitere fachliche Regeln...
}
}
```
### Konventionen
- Bean Validation für einfache Feld-Prüfungen (nicht null, Format, Länge)
- Eigener Validator für fachliche Regeln (Abhängigkeiten zwischen Feldern, DB-Lookups)
- Business-Regeln NICHT im Controller
- Custom Constraint-Annotations für wiederverwendbare Validierungen