docs(core): comprehensive development documentation and issue management system

- Complete project documentation for API gateway development
- API gateway-specific development processes and standards
- Comprehensive issue management system with script automation
- Go-specific testing guidelines for multi-service architecture

New Documentation:
- devdocs/KONZEPT.md: project philosophy, architecture, service integration patterns
- devdocs/TESTING_GUIDELINES.md: Go testing, API tests, gateway-service integration
- devdocs/development-process.md: API gateway development, multi-service coordination
- devdocs/furt-issue-management-guide.md: Furt-specific issue management workflows

Issue Management System:
- scripts/create_issue.sh: 8 preconfigured templates for API gateway development
- Furt-specific issue types: service-request, architecture, performance, security
- Script-based workflows for efficient development
- Integration with existing get_issues.sh and update_issue.sh scripts

API Gateway Development Standards:
- Service integration patterns for gateway ↔ service communication
- API-contract-first development with OpenAPI specifications
- Security-first patterns for authentication and input validation
- Multi-service testing strategies for coordinated development

This documentation enables immediate, efficient API gateway development
with clear standards, proven patterns, and automated workflows.
This commit is contained in:
michael 2025-06-03 18:45:55 +02:00
parent f4e8a40cdf
commit d6d546bd95
7 changed files with 2649 additions and 0 deletions

View file

@ -0,0 +1,590 @@
# Entwicklungsprozess für Furt API-Gateway
**Erstellt:** 03.06.2025
**Letzte Aktualisierung:** 03.06.2025
**Version:** 1.0
**Verantwortlich:** Claude / DAW-Team
**Dateipfad:** devdocs/development-process.md
## Zweck dieses Dokuments
Dieses Dokument definiert den verbindlichen Prozess für die Entwicklung und Änderung von Code im Rahmen des Furt API-Gateway-Projekts. Es ergänzt die allgemeinen Entwicklungsrichtlinien um API-Gateway-spezifische Patterns und Multi-Service-Koordination.
Es richtet sich an alle Projektbeteiligten, die am Gateway oder Services entwickeln.
## Verwandte Dokumente
Dieses Dokument steht im Zusammenhang mit folgenden anderen Dokumenten:
- **KONZEPT.md:** Zentrale Referenz und Konzeptdokumentation, devdocs/KONZEPT.md
- **TESTING_GUIDELINES.md:** API-Gateway-spezifische Test-Standards, devdocs/TESTING_GUIDELINES.md
- **ARCHITECTURE.md:** Detaillierte Systemarchitektur, devdocs/ARCHITECTURE.md
## Änderungshistorie
| Version | Datum | Änderungen | Autor |
|---------|-------|------------|-------|
| 1.0 | 03.06.2025 | Initiale Version für Furt API-Gateway | Claude / DAW-Team |
## 1. Grundprinzipien für API-Gateway-Entwicklung
### 1.1 Service-First-Entwicklung
Jede Entwicklungsaufgabe muss im Kontext des **Service-Ökosystems** betrachtet werden:
- **Gateway-Änderungen** betreffen potenziell alle Services
- **Service-Änderungen** können Gateway-Anpassungen erfordern
- **API-Contracts** zwischen Gateway und Services sind kritisch
- **Breaking Changes** erfordern koordinierte Rollouts
### 1.2 API-Contract-Driven Development
Bevor Code geschrieben wird, müssen **API-Contracts** definiert werden:
- **OpenAPI-Spezifikation** für neue Endpunkte
- **Service-Interface-Definition** für neue Services
- **Authentication/Authorization-Requirements** für alle APIs
- **Error-Response-Standards** konsistent halten
### 1.3 Security-First-Pattern
Sicherheit wird bei **jeder** Änderung mitgedacht:
- **API-Key-Berechtigungen** bei neuen Endpunkten definieren
- **Input-Validation** für alle eingehenden Requests
- **Rate-Limiting** für neue Services konfigurieren
- **IP-Restrictions** wo angemessen anwenden
## 2. Verbindlicher Entwicklungsprozess für Furt
### 2.1 Vorbereitung
1. **Requirements-Analyse mit Service-Impact**
- Welche Services sind betroffen?
- Welche Gateway-Komponenten benötigen Änderungen?
- Sind Breaking Changes erforderlich?
- Welche API-Contracts müssen definiert/aktualisiert werden?
2. **Explizite Anfrage nach relevanten Dateien**
- Gateway-Dateien: `internal/gateway/`, `configs/gateway.yaml`
- Service-Dateien: `internal/services/[service]/`, `configs/services/`
- API-Dokumentation: `docs/api/`, OpenAPI-Specs
- Integration-Tests: `tests/integration/`
3. **Analyse der Service-Integration-Pattern**
- Bestehende Service-Registry-Einträge
- Routing-Patterns und Middleware-Chain
- Authentifizierungs-Flows
- Health-Check-Mechanismen
### 2.2 Design und Planung
1. **API-First-Design dokumentieren**
- OpenAPI-Spezifikation **vor** der Implementierung schreiben
- Request/Response-Schemas definieren
- HTTP-Status-Codes und Error-Handling spezifizieren
- Authentication-Requirements dokumentieren
2. **Service-Integration-Strategy festlegen**
- Wie wird der Service im Gateway registriert?
- Welche Health-Check-URL wird verwendet?
- Welche Timeout-Werte sind angemessen?
- Braucht der Service Admin-UI-Integration?
3. **Breaking-Change-Impact analysieren**
- Betrifft die Änderung bestehende API-Contracts?
- Sind koordinierte Service-Updates erforderlich?
- Müssen Client-Integrationen (Hugo-Shortcodes) angepasst werden?
- Ist eine API-Versionierung (v1 → v2) notwendig?
4. **Configuration-Strategy bestimmen**
- Welche neuen Config-Parameter werden benötigt?
- Sind Environment-Variable für Secrets erforderlich?
- Wie wird die Config zwischen Gateway und Service koordiniert?
### 2.3 Implementierung
1. **Multi-Component-Development-Order**
**Für neue Services:**
```
1. Service-Struktur scaffolden (service-generator.sh)
2. Service-Logik implementieren (Standalone-Mode)
3. Gateway-Integration hinzufügen
4. Integration-Tests schreiben
5. Deployment-Scripts anpassen
```
**Für Gateway-Änderungen:**
```
1. Gateway-Kern-Logik implementieren
2. Middleware/Auth-Anpassungen
3. Service-Integration testen
4. Health-Check-Aggregation
5. Admin-Interface-Updates
```
**Für API-Änderungen:**
```
1. OpenAPI-Spec aktualisieren
2. Gateway-Routing anpassen
3. Service-Endpunkt implementieren
4. Input-Validation hinzufügen
5. Integration-Tests erweitern
```
2. **Koordinierte Entwicklung bei Service-Updates**
- **Gateway-kompatible Änderungen zuerst** (additive APIs)
- **Service-Tests** mit Gateway-Integration
- **Backward-Compatibility** während Übergangsphase
- **Coordinated Deployment** bei Breaking Changes
3. **Configuration-Management während Entwicklung**
- **Development-Configs** in `configs/[component].dev.yaml`
- **Environment-Variable-Mapping** dokumentieren
- **Config-Validation** bei Service-Start implementieren
- **Hot-Reload** für Development (wo möglich)
### 2.4 Testing-Integration
1. **Multi-Layer-Testing-Strategy**
- **Unit-Tests:** Für Gateway- und Service-Komponenten isoliert
- **Integration-Tests:** Gateway ↔ Service-Kommunikation
- **API-Tests:** End-to-End API-Contract-Validation
- **Load-Tests:** Gateway-Performance mit mehreren Services
2. **Test-Coordination-Pattern**
```go
// Beispiel: Service-Integration-Test
func TestGatewayServiceIntegration(t *testing.T) {
// 1. Start Test-Service
service := startTestService(t, serviceConfig)
defer service.Close()
// 2. Configure Gateway with Test-Service
gateway := startTestGateway(t, gatewayConfigWithService(service.URL))
defer gateway.Close()
// 3. Test Gateway → Service communication
testServiceAPIThroughGateway(t, gateway, service)
}
```
3. **Breaking-Change-Test-Strategy**
- **Backward-Compatibility-Tests** bei API-Änderungen
- **Version-Migration-Tests** bei Breaking Changes
- **Client-Integration-Tests** (Hugo-Shortcode-Kompatibilität)
## 3. Service-spezifische Entwicklungs-Pattern
### 3.1 Neue Service-Entwicklung
1. **Service-Scaffolding**
```bash
./scripts/service-generator.sh newsletter
# Erstellt komplette Service-Struktur
```
2. **Service-Interface-Implementation**
```go
// Jeder Service muss dieses Interface implementieren
type Service interface {
// Gateway-Integration
HandleRequest(w http.ResponseWriter, r *http.Request)
HealthCheck() HealthStatus
// Standalone-Mode
HandleWithAuth(w http.ResponseWriter, r *http.Request)
// Lifecycle
Start(ctx context.Context, config ServiceConfig) error
Stop(ctx context.Context) error
// Service-Metadata
GetServiceInfo() ServiceInfo
}
```
3. **Service-Registration im Gateway**
```yaml
# configs/gateway.yaml
services:
newsletter:
enabled: true
path_prefix: "/v1/newsletter"
upstream: "http://127.0.0.1:8083"
health_check: "/health"
timeout: 15s
auth_required: true
rate_limit:
requests_per_minute: 60
```
### 3.2 Service-API-Design-Standards
1. **Einheitliche Request-Patterns**
```go
// Standard Request-Wrapper
type APIRequest struct {
RequestID string `json:"request_id,omitempty"`
Data interface{} `json:"data"`
Meta map[string]interface{} `json:"meta,omitempty"`
}
// Standard Response-Wrapper
type APIResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Error *APIError `json:"error,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
```
2. **Konsistente Error-Handling**
```go
// Standard Error-Format
type APIError struct {
Code string `json:"code"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
// Standard Error-Codes
const (
ErrInvalidInput = "INVALID_INPUT"
ErrUnauthorized = "UNAUTHORIZED"
ErrServiceUnavailable = "SERVICE_UNAVAILABLE"
ErrRateLimitExceeded = "RATE_LIMIT_EXCEEDED"
)
```
3. **Health-Check-Standards**
```go
// Standard Health-Response
type HealthStatus struct {
Status string `json:"status"`
Version string `json:"version"`
Uptime time.Duration `json:"uptime"`
Checks map[string]string `json:"checks"`
Timestamp time.Time `json:"timestamp"`
}
// Status-Werte
const (
HealthStatusHealthy = "healthy"
HealthStatusDegraded = "degraded"
HealthStatusUnhealthy = "unhealthy"
)
```
### 3.3 Gateway-Integration-Pattern
1. **Service-Discovery-Integration**
```go
// Gateway registriert Services automatisch
func (g *Gateway) RegisterService(name string, config ServiceConfig) error {
service := &ServiceProxy{
Name: name,
PathPrefix: config.PathPrefix,
Upstream: config.Upstream,
HealthCheck: config.HealthCheck,
// ...
}
g.services[name] = service
g.updateRouting()
return nil
}
```
2. **Request-Middleware-Chain**
```go
// Standard Middleware-Order für alle Services
func (g *Gateway) buildMiddlewareChain(serviceName string) []Middleware {
return []Middleware{
LoggingMiddleware,
AuthenticationMiddleware,
RateLimitingMiddleware(serviceName),
ValidationMiddleware,
ProxyMiddleware(serviceName),
}
}
```
## 4. Configuration-Management-Pattern
### 4.1 Hierarchische Konfiguration
```go
// Config-Loading-Reihenfolge
func LoadConfig(serviceName string) (*Config, error) {
config := &Config{}
// 1. Default-Values
config.ApplyDefaults()
// 2. Base-Config-File
config.LoadFromFile("configs/" + serviceName + ".yaml")
// 3. Environment-specific
if env := os.Getenv("ENVIRONMENT"); env != "" {
config.LoadFromFile("configs/" + serviceName + "." + env + ".yaml")
}
// 4. Environment-Variables
config.LoadFromEnv()
// 5. Command-Line-Flags
config.LoadFromFlags()
return config.Validate()
}
```
### 4.2 Service-Gateway-Config-Coordination
```yaml
# Gateway-Config für Service
services:
formular2mail:
config_sync: true
config_endpoint: "/config"
config_push_on_change: true
# Service erhält Config vom Gateway
```
### 4.3 Secrets-Management
```go
// Secrets werden nie in Config-Files gespeichert
type ServiceConfig struct {
// Public config
Port string `yaml:"port"`
LogLevel string `yaml:"log_level"`
// Secrets via Environment
APIKey string `env:"SERVICE_API_KEY"`
DBPassword string `env:"DB_PASSWORD"`
}
```
## 5. Security-First-Development-Pattern
### 5.1 Authentication-Integration
```go
// Jeder Service-Endpunkt bekommt Auth-Context
type AuthContext struct {
APIKey string
Permissions []string
ClientIP string
UserAgent string
RequestID string
}
func (s *Service) HandleRequest(w http.ResponseWriter, r *http.Request) {
// Auth-Context wird vom Gateway gesetzt
authCtx := r.Context().Value("auth").(*AuthContext)
// Service-spezifische Permission-Checks
if !authCtx.HasPermission("service:" + s.name + ":write") {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// ... Service-Logik
}
```
### 5.2 Input-Validation-Standards
```go
// Standard Validation-Middleware
func ValidationMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 1. Content-Type validation
if !isValidContentType(r.Header.Get("Content-Type")) {
http.Error(w, "Invalid Content-Type", http.StatusBadRequest)
return
}
// 2. Content-Length limits
if r.ContentLength > MaxRequestSize {
http.Error(w, "Request too large", http.StatusRequestEntityTooLarge)
return
}
// 3. Request-Body validation (service-specific)
if err := validateRequestBody(r); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
next.ServeHTTP(w, r)
})
}
```
### 5.3 Rate-Limiting-Strategy
```go
// Service-spezifische Rate-Limits
type RateLimitConfig struct {
RequestsPerMinute int `yaml:"requests_per_minute"`
BurstSize int `yaml:"burst_size"`
PerAPIKey bool `yaml:"per_api_key"`
PerIP bool `yaml:"per_ip"`
Whitelist []string `yaml:"whitelist"`
}
// Gateway-Level Rate-Limiting
func (g *Gateway) GetRateLimit(serviceName, apiKey, clientIP string) *RateLimit {
config := g.getRateLimitConfig(serviceName)
key := buildRateLimitKey(config, apiKey, clientIP)
return g.rateLimiter.GetLimit(key)
}
```
## 6. Breaking-Change-Management
### 6.1 API-Versionierung-Strategy
```go
// URL-basierte Versionierung
// /v1/mail/send → formular2mail v1
// /v2/mail/send → formular2mail v2
// Gateway-Routing für mehrere Versionen
services:
formular2mail-v1:
path_prefix: "/v1/mail"
upstream: "http://127.0.0.1:8081"
formular2mail-v2:
path_prefix: "/v2/mail"
upstream: "http://127.0.0.1:8084"
```
### 6.2 Backward-Compatibility-Pattern
```go
// Service unterstützt mehrere API-Versionen
func (s *FormularService) HandleRequest(w http.ResponseWriter, r *http.Request) {
version := extractAPIVersion(r.URL.Path) // v1, v2
switch version {
case "v1":
s.handleV1Request(w, r)
case "v2":
s.handleV2Request(w, r)
default:
s.handleLatestRequest(w, r)
}
}
```
### 6.3 Migration-Pattern
```go
// Coordinated Service-Migration
type MigrationPlan struct {
FromVersion string
ToVersion string
Steps []MigrationStep
}
type MigrationStep struct {
Name string
Component string // "gateway" | "service"
Action string // "deploy" | "config" | "test"
Rollback func() error
}
```
## 7. Checkliste für API-Gateway-Entwicklung
### 7.1 Vor Implementierungsbeginn
- [ ] **Service-Impact analysiert:** Welche Services sind betroffen?
- [ ] **API-Contract definiert:** OpenAPI-Spec erstellt/aktualisiert?
- [ ] **Gateway-Integration geplant:** Routing, Auth, Rate-Limiting?
- [ ] **Config-Strategy festgelegt:** Neue Parameter dokumentiert?
- [ ] **Breaking-Change-Assessment:** Versionierung erforderlich?
- [ ] **Security-Requirements:** Auth, Validation, Rate-Limiting?
- [ ] **Test-Strategy:** Unit, Integration, API-Tests geplant?
### 7.2 Während der Implementierung
- [ ] **Service-Interface-Compliance:** Standard-Interface implementiert?
- [ ] **Error-Handling-Consistency:** Standard-Error-Format verwendet?
- [ ] **Health-Check-Integration:** Standardisierte Health-Endpoint?
- [ ] **Logging-Standards:** Strukturierte Logs mit Request-IDs?
- [ ] **Config-Validation:** Startup-Config-Checks implementiert?
- [ ] **Auth-Integration:** Gateway-Auth-Context respektiert?
- [ ] **Documentation-Update:** API-Docs und Service-Docs aktualisiert?
### 7.3 Nach Implementierungsabschluss
- [ ] **Integration-Tests:** Gateway ↔ Service-Tests bestehen?
- [ ] **API-Contract-Tests:** OpenAPI-Compliance validiert?
- [ ] **Performance-Tests:** Load-Tests mit Gateway durchgeführt?
- [ ] **Security-Tests:** Auth, Input-Validation, Rate-Limiting getestet?
- [ ] **Deployment-Scripts:** Service-Deployment automatisiert?
- [ ] **Monitoring-Integration:** Health-Checks und Metriken?
- [ ] **Documentation-Complete:** Service-Integration dokumentiert?
## 8. Troubleshooting-Pattern
### 8.1 Service-Integration-Debugging
```go
// Standard Debug-Endpoints für Services
func (s *Service) RegisterDebugEndpoints() {
http.HandleFunc("/debug/config", s.debugConfig)
http.HandleFunc("/debug/health-detail", s.debugHealthDetail)
http.HandleFunc("/debug/metrics", s.debugMetrics)
http.HandleFunc("/debug/auth", s.debugAuth)
}
// Gateway Debug-Endpoints
func (g *Gateway) RegisterDebugEndpoints() {
http.HandleFunc("/debug/services", g.debugServices)
http.HandleFunc("/debug/routing", g.debugRouting)
http.HandleFunc("/debug/auth-keys", g.debugAuthKeys)
}
```
### 8.2 Request-Tracing
```go
// Request-ID-Propagation durch alle Services
func (g *Gateway) addRequestID(r *http.Request) *http.Request {
requestID := r.Header.Get("X-Request-ID")
if requestID == "" {
requestID = generateRequestID()
}
// Für Service-Weiterleitung
r.Header.Set("X-Request-ID", requestID)
// Für Logging
ctx := context.WithValue(r.Context(), "request_id", requestID)
return r.WithContext(ctx)
}
```
## 9. Zusammenfassung: API-Gateway-Entwicklungs-Goldene-Regeln
1. **API-Contract-First:** OpenAPI-Spec vor Code-Implementation
2. **Service-Integration-Aware:** Jede Änderung auf Service-Impact prüfen
3. **Security-by-Default:** Auth, Validation, Rate-Limiting bei jedem Endpunkt
4. **Configuration-Hierarchie:** Defaults → Environment → Service-specific
5. **Multi-Layer-Testing:** Unit → Integration → API → E2E
6. **Breaking-Change-Coordination:** Versionierung und Migration planen
7. **Health-Check-Integration:** Jeder Service braucht standardisierten Health-Endpoint
8. **Request-Tracing:** Request-IDs durch gesamte Pipeline propagieren
---
**Wichtiger Hinweis:** Diese Entwicklungs-Pattern sind spezifisch für das Furt API-Gateway-System optimiert und sollten bei jeder Entwicklungsaufgabe konsultiert werden, um konsistente und gut integrierte Services zu gewährleisten.

520
devdocs/furt_konzept.md Normal file
View file

@ -0,0 +1,520 @@
# Furt: API-Gateway im Einklang mit digitaler Souveränität
**Erstellt:** 03. Juni 2025
**Letzte Aktualisierung:** 03. Juni 2025
**Version:** 1.0
**Verantwortlich:** DAW-Team
**Dateipfad:** devdocs/KONZEPT.md
## Zweck dieses Dokuments
Dieses Dokument definiert die grundlegenden Prinzipien, technischen Entscheidungen und Entwicklungsrichtlinien für das Furt API-Gateway-System. Es dient als zentrale Referenz für alle Entwickler und Mitwirkenden des Projekts.
Es richtet sich an Entwickler, Projektbeteiligte und alle, die am Code-Design und der Implementierung von Furt arbeiten.
## Verwandte Dokumente
Dieses Dokument steht im Zusammenhang mit folgenden anderen Dokumenten:
- **README.md:** Öffentliche Projektbeschreibung, ../README.md
- **ARCHITECTURE.md:** Detaillierte Architekturübersicht, devdocs/ARCHITECTURE.md
- **DECISIONS.md:** Wichtige Architekturentscheidungen, devdocs/DECISIONS.md
## 1. Projektvision und Philosophie
Furt (germanisch für "Durchgang durch Wasser") ist ein selbst-gehostetes API-Gateway-System, das vollständig im Einklang mit den Prinzipien digitaler Souveränität, technologischer Angemessenheit und ressourcenschonender Entwicklung steht. Das System soll:
- **Einfachheit über Komplexität stellen** - leicht verständlich, wartbar und erweiterbar sein
- **Ressourceneffizient arbeiten** - minimale Server-Anforderungen und optimierte Performance
- **Vollständige Kontrolle** ermöglichen - transparenter Code ohne Black-Boxes
- **Langfristig tragfähig** sein - basierend auf bewährten Technologien
- **Service-Modularität** unterstützen - eigenständige Services unter einheitlicher API
- **Mehrsprachigkeit** von Anfang an unterstützen (DE, EN, FR)
Im Gegensatz zu existierenden Enterprise-Gateway-Lösungen fokussiert sich Furt auf:
- Native Installation als Hauptdeployment-Methode (keine Container-Abhängigkeit)
- Minimale externe Abhängigkeiten
- Transparente Konfiguration und Datenverarbeitung
- Volle Kompatibilität mit Low-Tech-Webseiten und statischen Site-Generatoren (besonders Hugo)
- **Ein Gateway für alle Services** - von Kontaktformularen bis zu komplexeren Anwendungen
## 2. Technische Architektur
### 2.1 Technology-Stack
- **Backend:** Go (für Performance, einfache Deployment durch einzelne Binärdatei)
- **Gateway-Pattern:** Reverse Proxy mit Service Registry
- **Konfiguration:** YAML-basiert (human-readable, versionierbar)
- **Proxy-Integration:** Apache als SSL-terminierender Reverse Proxy
- **Services:** Eigenständige Go-Binaries mit eigenen Ports
- **Authentifizierung:** API-Keys mit granularen Berechtigungen
- **Logging:** Strukturierte JSON-Logs mit konfigurierbaren Leveln
### 2.2 Projektstruktur
```
furt/
├── cmd/
│ ├── furt-gateway/ # Gateway-Binary
│ │ └── main.go
│ └── services/ # Service-Binaries
│ ├── formular2mail/ # Kontaktformular → E-Mail
│ ├── sagjan/ # Kommentarsystem-Integration
│ └── shop/ # Zukünftig: E-Commerce
├── internal/
│ ├── gateway/ # Gateway-Kernlogik
│ │ ├── server.go # HTTP-Server
│ │ ├── router.go # Request-Routing
│ │ ├── proxy.go # Service-Proxy
│ │ ├── auth.go # Authentifizierung
│ │ └── middleware.go # Gateway-Middleware
│ ├── services/ # Service-Implementierungen
│ │ ├── formular2mail/ # Formular-Service-Logik
│ │ └── sagjan/ # Kommentar-Service-Logik
│ └── shared/ # Geteilte Komponenten
│ ├── auth/ # Authentifizierungs-Bibliothek
│ ├── config/ # Konfigurationsmanagement
│ └── logging/ # Strukturiertes Logging
├── configs/ # Konfigurationsvorlagen
│ ├── gateway.yaml.example # Gateway-Konfiguration
│ └── services/ # Service-spezifische Configs
│ ├── formular2mail.yaml.example
│ └── sagjan.yaml.example
├── docs/ # Öffentliche Dokumentation
│ ├── installation.md # Installationsanleitung
│ ├── configuration.md # Konfigurationsreferenz
│ ├── services/ # Service-spezifische Dokumentation
│ └── api/ # OpenAPI-Dokumentation
│ ├── gateway.yaml # Gateway-API-Spec
│ └── services/ # Service-API-Specs
├── devdocs/ # Entwicklerdokumentation
├── scripts/ # Build & Deployment
│ ├── build-all.sh # Alle Komponenten bauen
│ ├── deploy-gateway.sh # Gateway deployment
│ ├── deploy-service.sh # Service deployment
│ └── service-generator.sh # Neuen Service scaffolden
├── examples/ # Beispiel-Integrationen
│ ├── hugo/ # Hugo-Shortcodes
│ ├── nginx/ # Nginx-Proxy-Config
│ └── apache/ # Apache-Proxy-Config
└── tests/ # Test-Suites
├── integration/ # Service-Integration-Tests
└── e2e/ # End-to-End-Tests
```
### 2.3 Gateway-Architektur
Das Furt-Gateway implementiert ein **Service-Registry-Pattern** mit dateibasierter Konfiguration:
```go
// Beispiel Gateway-Konfiguration
type GatewayConfig struct {
Gateway GatewaySettings `yaml:"gateway"`
Security SecurityConfig `yaml:"security"`
Services map[string]ServiceConfig `yaml:"services"`
Logging LoggingConfig `yaml:"logging"`
}
type ServiceConfig struct {
Enabled bool `yaml:"enabled"`
PathPrefix string `yaml:"path_prefix"` // /v1/mail, /v1/comments
Upstream string `yaml:"upstream"` // http://127.0.0.1:8081
HealthCheck string `yaml:"health_check"` // /health
Timeout time.Duration `yaml:"timeout"`
HasAdminUI bool `yaml:"has_admin_ui"`
AdminPath string `yaml:"admin_path"`
}
```
**Request-Flow:**
1. Client → Apache (SSL-Terminierung) → Gateway
2. Gateway → Authentifizierung (API-Key + IP-Check)
3. Gateway → Service-Registry (Route Resolution)
4. Gateway → Service-Proxy (Request Forwarding)
5. Service → Response → Gateway → Client
## 3. Entwicklungsphasen gemäß natürlichem Wachstum
Die Entwicklung folgt einem natürlichen, organischen Prozess, der in vier Hauptphasen gegliedert ist:
### 3.1 Wurzelphase (Grundlagen)
- **Ziel:** Funktionierendes Gateway mit minimalen Features
- **Schlüsselfeatures:**
- HTTP-Gateway mit grundlegendem Routing
- API-Key-Authentifizierung mit IP-Beschränkungen
- Formular2Mail-Service (E-Mail-Weiterleitung)
- Basis-Hugo-Integration (Shortcodes)
- Native Installationspakete für alle Komponenten
### 3.2 Wachstumsphase (Erweiterung)
- **Ziel:** Stabile, nutzbare Version mit wichtigen Services
- **Schlüsselfeatures:**
- Sagjan-Integration (Kommentarsystem)
- Erweiterte Middleware (Rate-Limiting, Logging)
- Service-Generator für neue Services
- Admin-Dashboard für Gateway-Management
- Umfassende OpenAPI-Dokumentation
### 3.3 Blütephase (Vernetzung)
- **Ziel:** Verbesserung der Integration und Erweiterbarkeit
- **Schlüsselfeatures:**
- Shop-Service (E-Commerce-Integration)
- Webhook-Support für Service-Events
- Erweiterte Monitoring-Funktionen
- Multi-Tenant-Fähigkeiten
- Service-Discovery-Verbesserungen
### 3.4 Fruchtphase (Reifung)
- **Ziel:** Langfristige Wartbarkeit und Community-Entwicklung
- **Schlüsselfeatures:**
- Community-Service-Ecosystem
- Performance-Optimierungen
- High-Availability-Features
- Föderation mit anderen Furt-Instanzen
## 4. Service-Integration-Konzept
### 4.1 Service-Entwicklung-Pattern
Jeder Service folgt einem standardisierten Muster:
```go
// Service-Interface
type Service interface {
// Für Gateway-Integration
HandleRequest(w http.ResponseWriter, r *http.Request)
HealthCheck() error
// Für Standalone-Mode
HandleWithAuth(w http.ResponseWriter, r *http.Request) // Eigene Auth
// Service-Lifecycle
Start(ctx context.Context) error
Stop(ctx context.Context) error
}
// Service-Konfiguration
type ServiceConfig struct {
Port string `yaml:"port"`
Environment string `yaml:"environment"`
Auth ServiceAuth `yaml:"auth"`
Logging LoggingConfig `yaml:"logging"`
Custom map[string]string `yaml:"custom"` // Service-spezifisch
}
```
### 4.2 Dual-Mode-Operation
Jeder Service kann sowohl **hinter dem Gateway** als auch **standalone** betrieben werden:
**Gateway-Mode:**
- Service läuft auf localhost:PORT
- Authentifizierung erfolgt im Gateway
- Routing über Gateway-Pfade (/v1/mail, /v1/comments)
**Standalone-Mode:**
- Service läuft mit eigener Authentifizierung
- Direkte API-Endpunkte (/api/v1/mail/send)
- Eigene Dokumentation und Admin-UI
### 4.3 Service-Generator
Für schnelle Service-Entwicklung existiert ein Generator:
```bash
./scripts/service-generator.sh newsletter
# Erstellt:
# - cmd/services/newsletter/main.go
# - internal/services/newsletter/service.go
# - configs/services/newsletter.yaml
# - docs/services/newsletter.yaml
# - Deployment-Scripts
```
## 5. Implementierungsrichtlinien
### 5.1 Go-spezifische Standards
- **Formatierung:** `gofmt` für alle Go-Dateien verwenden
- **Linting:** `golangci-lint` mit angepasster Konfiguration
- **Tests:** Für jedes Package Testdateien (coverage-Ziel: mind. 80%)
- **Abhängigkeiten:** Minimale externe Abhängigkeiten, nur Go-Standard-Library + etablierte Packages
- **Fehlerbehandlung:** Explizite Fehlerprüfung, strukturierte Fehlerrückgaben
- **Logging:** Strukturiertes JSON-Logging mit verschiedenen Leveln
- **Kommentare:** Alle Funktionen und Typen auf Englisch dokumentieren
### 5.2 API-Design-Standards
- **RESTful-Design:** Standard HTTP-Methoden und Status-Codes
- **Versionierung:** `/v1/` Pfad-Prefix für alle APIs
- **JSON-Format:** Einheitliche Request/Response-Strukturen
- **Fehlerbehandlung:** Konsistente Fehler-Response-Formate
- **OpenAPI:** Jeder Endpunkt wird dokumentiert
### 5.3 Konfigurationsmanagement
- **YAML-Format:** Human-readable, versionierbar
- **Umgebungsvariablen:** Für sensitive Daten (Tokens, Passwörter)
- **Hierarchische Konfiguration:** Default → Environment → Local
- **Validierung:** Konfiguration wird beim Start validiert
## 6. Qualitätssicherung
### 6.1 Teststrategie
- **Unit-Tests:** Für alle Kernfunktionen und Services
- **Integration-Tests:** Für Gateway ↔ Service-Kommunikation
- **API-Tests:** Für alle Endpunkte mit verschiedenen Authentifizierungsszenarien
- **End-to-End-Tests:** Für vollständige User-Journeys (Hugo → Gateway → Service)
- **Performance-Tests:** Load-Testing für Gateway und Services
### 6.2 Code-Review-Prozess
- Peer-Reviews für alle Änderungen
- Prüfung auf Einhaltung der Low-Tech-Prinzipien
- Überprüfung der API-Dokumentation
- Fokus auf Sicherheit und Performance
- Beachtung der Service-Integration-Patterns
### 6.3 Sicherheits-Standards
- **API-Key-Management:** Sichere Generation und Rotation
- **Input-Validierung:** Alle User-Inputs validieren
- **Rate-Limiting:** Schutz vor Abuse
- **IP-Allowlisting:** Restriktive Service-Zugriffe
- **Secure Headers:** Standard-Security-Headers
- **Audit-Logging:** Sicherheitsrelevante Events loggen
## 7. Deployment und Installation
### 7.1 Native Installation (primär)
**Gateway-Deployment:**
```bash
# Build
./scripts/build-all.sh
# Deploy Gateway
./scripts/deploy-gateway.sh
# Deploy Services
./scripts/deploy-service.sh formular2mail
./scripts/deploy-service.sh sagjan
```
**Systemd-Integration:**
- Gateway als `furt-gateway.service`
- Services als `formular2mail-service.service`, etc.
- Automatischer Start und Restart
- Structured Logging zu journald
### 7.2 Apache-Integration
**Reverse-Proxy-Konfiguration:**
```apache
<VirtualHost *:443>
ServerName api.dragons-at-work.de
# SSL-Terminierung durch Apache
SSLEngine on
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/key.pem
# Gateway-Proxy
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
# Headers für Gateway
ProxyPassReverse / http://127.0.0.1:8080/
ProxySetHeader X-Forwarded-For %{REMOTE_ADDR}s
ProxySetHeader X-Forwarded-Proto https
</VirtualHost>
```
### 7.3 Monitoring und Logging
**Log-Struktur:**
```
/var/log/furt/
├── gateway.log # Gateway-Logs
├── formular2mail.log # Service-Logs
├── sagjan.log
└── access.log # Request-Logs
```
**Health-Checks:**
- Gateway: `/health` (Service-Status-Aggregation)
- Services: `/health` (Individual Service Health)
- Systemd: `watchdog` für automatischen Restart
## 8. Hugo-Integration
### 8.1 Shortcode-Integration
**Kontaktformular:**
```hugo
{{< furt-contact
form-id="contact-main"
api-key="hugo-frontend-key"
success-message="Vielen Dank für deine Nachricht!"
>}}
```
**Kommentarsystem:**
```hugo
{{< furt-comments
page-url="{{ .Permalink }}"
api-key="sagjan-public-key"
moderation="true"
>}}
```
### 8.2 JavaScript-Client
**Minimaler, Framework-freier JavaScript-Client:**
```javascript
// pkg/client/furt-client.js
class FurtClient {
constructor(baseURL, apiKey) {
this.baseURL = baseURL;
this.apiKey = apiKey;
}
async submitForm(formData, endpoint) {
// Progressive Enhancement
// Funktioniert mit und ohne JavaScript
}
}
```
## 9. Git-Workflow und Versionierung
### 9.1 Branch-Strategie
- `main`: Stabile Releases
- `develop`: Hauptentwicklungszweig
- `feature/*`: Feature-Branches
- `service/*`: Service-spezifische Entwicklung
- `release/*`: Release-Kandidaten
### 9.2 Commit-Message-Format
```
typ(bereich): short description of the change
Detailed explanation of the change, if necessary.
Multiple lines possible.
Resolves: #123
```
- **Typen:** feat, fix, docs, style, refactor, test, chore
- **Bereiche:** gateway, service-*, config, docs, scripts
- **Sprache:** Englisch für alle Commit-Messages
### 9.3 Versionierung
Semantic Versioning (MAJOR.MINOR.PATCH):
- **MAJOR:** Breaking Changes in Gateway-API oder Service-Interfaces
- **MINOR:** Neue Services oder Features (abwärtskompatibel)
- **PATCH:** Bugfixes und Performance-Verbesserungen
## 10. Service-Spezifikationen
### 10.1 Formular2Mail-Service
**Zweck:** Kontaktformulare zu E-Mail weiterleiten
**Port:** 8081
**API:** `/send` (POST)
**Integration:** SMTP mit bestehendem Postfix
**Hugo-Integration:** Shortcode für Kontaktformulare
### 10.2 Sagjan-Service (geplant)
**Zweck:** Kommentarsystem-Integration
**Port:** 8082
**API:** `/comments/*` (GET, POST, PUT, DELETE)
**Features:** Moderation, Threading, Spam-Schutz
**Hugo-Integration:** Shortcode für Kommentare
### 10.3 Zukünftige Services
- **Shop-Service:** E-Commerce-Funktionen
- **Newsletter-Service:** Listmonk-Integration
- **Calendar-Service:** Terminbuchungen
- **Auth-Service:** User-Management
## 11. Lizenzierung
### 11.1 Apache License 2.0
Das Projekt steht unter der Apache License 2.0, die:
- Kommerzielle Nutzung erlaubt
- Patentrechte explizit gewährt
- Modifikationen ermöglicht
- Verteilung gestattet
### 11.2 Copyright-Header
Jede Quellcode-Datei muss folgenden Header enthalten:
```go
// Copyright 2025 Furt Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
```
## 12. Nächste Schritte
### 12.1 Unmittelbare Implementierung (Wurzelphase)
1. **Gateway-Grundgerüst entwickeln**
- HTTP-Server mit grundlegenden Routen
- Konfigurationsmanagement (YAML-basiert)
- Service-Registry-Implementation
2. **Formular2Mail-Service implementieren**
- SMTP-Integration mit bestehendem Postfix
- Input-Validierung und Fehlerbehandlung
- Hugo-Shortcode für Kontaktformulare
3. **Apache-Integration konfigurieren**
- Reverse-Proxy für `api.dragons-at-work.de`
- SSL-Terminierung und Header-Forwarding
- Health-Check-Integration
### 12.2 Mittelfristige Entwicklung (Wachstumsphase)
1. **Authentifizierungs-System ausbauen**
- Granulare API-Key-Berechtigungen
- Rate-Limiting und IP-Restrictions
- Admin-Interface für Key-Management
2. **Monitoring und Logging**
- Strukturiertes JSON-Logging
- Health-Check-Aggregation
- Performance-Metriken
3. **Service-Generator implementieren**
- Scaffolding für neue Services
- Template-basierte Code-Generierung
- Deployment-Script-Integration
---
Diese Konzeptdokumentation dient als Leitfaden für die Entwicklung von Furt und soll im Laufe des Projekts entsprechend der Erkenntnisse aus der praktischen Umsetzung angepasst und erweitert werden. Sie bildet die Grundlage für alle weiteren Architektur- und Implementierungsentscheidungen im Projekt.

View file

@ -0,0 +1,783 @@
# Furt Testing-Richtlinien
**Erstellt:** 03.06.2025
**Letzte Aktualisierung:** 03.06.2025
**Version:** 1.0
**Verantwortlich:** DAW-Team
**Dateipfad:** devdocs/TESTING_GUIDELINES.md
## Zweck dieses Dokuments
Dieses Dokument definiert verbindliche Standards und Richtlinien für das Testen von Komponenten des Furt API-Gateway-Projekts. Es soll sicherstellen, dass alle implementierten Funktionalitäten ausreichend durch Tests abgedeckt sind und die Tests konsistent und wartbar bleiben.
Es richtet sich an alle Entwickler, die Code zum Projekt beisteuern.
## 1. Grundprinzipien
### 1.1 Test-First-Entwicklung
- Tests sollten parallel zur Implementierung oder idealerweise vor der eigentlichen Implementierung geschrieben werden.
- Keine Implementierung gilt als abgeschlossen, bis entsprechende Tests vorhanden sind.
- Pull Requests ohne Tests werden in der Regel nicht akzeptiert.
### 1.2 Testabdeckung
- Angestrebte Testabdeckung für Gateway-Kern: mindestens 85%
- Angestrebte Testabdeckung für Services: mindestens 80%
- Angestrebte Testabdeckung für Shared-Libraries: mindestens 90%
- Besonders kritische Komponenten (Authentifizierung, Routing, Service-Proxy) sollten eine Abdeckung nahe 100% haben.
### 1.3 Test-Typen
Folgende Test-Typen werden im Projekt verwendet:
1. **Unit Tests**: Testen einzelner Funktionen/Methoden in Isolation
2. **Integration Tests**: Testen des Zusammenspiels von Komponenten
3. **API Tests**: Testen der API-Endpunkte des Gateways und Services
4. **Service Integration Tests**: Testen der Gateway ↔ Service-Kommunikation
5. **End-to-End Tests**: Testen der gesamten Request-Pipeline (Client → Gateway → Service)
6. **Performance Tests**: Load-Testing für Gateway und Services
## 2. Test-Struktur und Dateiorganisation
### 2.1 Dateistruktur
- Test-Dateien werden neben den zu testenden Dateien platziert und erhalten den Suffix `_test.go`
- Beispiel: `gateway.go``gateway_test.go`
- Integration-Tests werden in `tests/integration/` platziert
- End-to-End-Tests werden in `tests/e2e/` platziert
### 2.2 Namenkonventionen
- Testfunktionen folgen dem Format `Test<Komponente><Funktionsname><Szenario>`
- Beispiel: `TestGatewayRoutingWithValidAPIKey`, `TestServiceProxyWhenServiceUnavailable`
- Benchmark-Tests: `Benchmark<Funktionsname>`
- Example-Tests: `Example<Funktionsname>`
### 2.3 Testpakete
- Tests sollten im selben Paket wie der zu testende Code sein (kein separates `_test`-Paket)
- Dies ermöglicht das Testen von Funktionen, die nicht exportiert werden
- Ausnahme: Integration-Tests können separate Pakete verwenden
## 3. Unit Tests
### 3.1 Grundstruktur
Jeder Unit Test sollte folgende Struktur haben:
```go
func TestFunctionName(t *testing.T) {
// Arrange: Vorbereitung der Testdaten und Abhängigkeiten
input := setupTestInput()
mockService := &MockService{}
expected := expectedResult{}
// Act: Ausführen der zu testenden Funktion
actual, err := FunctionName(input, mockService)
// Assert: Überprüfung des Ergebnisses
if err != nil {
t.Fatalf("Expected no error, but got: %v", err)
}
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected %+v, but got %+v", expected, actual)
}
}
```
### 3.2 Table-Driven Tests
Für komplexere Funktionen sollten Table-Driven Tests verwendet werden:
```go
func TestGatewayRouting(t *testing.T) {
testCases := []struct {
name string
requestPath string
expectedService string
expectedPath string
wantErr bool
}{
{
name: "formular2mail service routing",
requestPath: "/v1/mail/send",
expectedService: "formular2mail",
expectedPath: "/send",
wantErr: false,
},
{
name: "sagjan service routing",
requestPath: "/v1/comments/list",
expectedService: "sagjan",
expectedPath: "/list",
wantErr: false,
},
{
name: "unknown service",
requestPath: "/v1/unknown/test",
expectedService: "",
expectedPath: "",
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
gateway := setupTestGateway()
service, path, err := gateway.ResolveRoute(tc.requestPath)
if tc.wantErr && err == nil {
t.Error("Expected error, but got nil")
}
if !tc.wantErr && err != nil {
t.Fatalf("Expected no error, but got: %v", err)
}
if service != tc.expectedService {
t.Errorf("Expected service %s, got %s", tc.expectedService, service)
}
if path != tc.expectedPath {
t.Errorf("Expected path %s, got %s", tc.expectedPath, path)
}
})
}
}
```
### 3.3 Mocking und Test-Doubles
- Für HTTP-Clients verwende `httptest.NewServer`
- Für Services erstelle Interface-basierte Mocks
- Verwende Dependency Injection für bessere Testbarkeit
```go
// Service Interface für Testbarkeit
type MailService interface {
SendMail(request MailRequest) error
}
// Mock Implementation
type MockMailService struct {
SendMailFunc func(MailRequest) error
CallCount int
}
func (m *MockMailService) SendMail(request MailRequest) error {
m.CallCount++
if m.SendMailFunc != nil {
return m.SendMailFunc(request)
}
return nil
}
// Test mit Mock
func TestFormular2MailHandler(t *testing.T) {
mockService := &MockMailService{
SendMailFunc: func(req MailRequest) error {
if req.Email == "invalid" {
return errors.New("invalid email")
}
return nil
},
}
handler := NewFormular2MailHandler(mockService)
// Test ausführen...
}
```
## 4. Integration Tests
### 4.1 Gateway-Service Integration Tests
Diese Tests prüfen die Kommunikation zwischen Gateway und Services:
```go
// tests/integration/gateway_service_test.go
func TestGatewayServiceIntegration(t *testing.T) {
// Setup Test-Services
mailService := startTestMailService(t)
defer mailService.Close()
commentsService := startTestCommentsService(t)
defer commentsService.Close()
// Setup Gateway mit Test-Konfiguration
gateway := setupTestGateway(t, GatewayConfig{
Services: map[string]ServiceConfig{
"formular2mail": {
Enabled: true,
PathPrefix: "/v1/mail",
Upstream: mailService.URL,
},
"sagjan": {
Enabled: true,
PathPrefix: "/v1/comments",
Upstream: commentsService.URL,
},
},
})
defer gateway.Close()
// Test Gateway → Service Routing
t.Run("mail service integration", func(t *testing.T) {
resp := makeTestRequest(t, gateway.URL+"/v1/mail/send", "POST", mailRequestBody)
assertStatusCode(t, resp, http.StatusOK)
})
t.Run("comments service integration", func(t *testing.T) {
resp := makeTestRequest(t, gateway.URL+"/v1/comments", "GET", nil)
assertStatusCode(t, resp, http.StatusOK)
})
}
```
### 4.2 Database Integration Tests (für Services)
Für Services mit Datenbank-Zugriff:
```go
func TestSagjanServiceDatabaseIntegration(t *testing.T) {
// Setup Test-Database (SQLite in-memory)
db := setupTestDB(t)
defer db.Close()
service := NewSagjanService(db)
// Test Comment Creation
comment := &Comment{
PageURL: "https://example.com/test",
Author: "Test User",
Content: "Test Comment",
}
err := service.CreateComment(context.Background(), comment)
if err != nil {
t.Fatalf("Failed to create comment: %v", err)
}
// Test Comment Retrieval
comments, err := service.GetComments(context.Background(), "https://example.com/test")
if err != nil {
t.Fatalf("Failed to get comments: %v", err)
}
if len(comments) != 1 {
t.Errorf("Expected 1 comment, got %d", len(comments))
}
}
func setupTestDB(t *testing.T) *sql.DB {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatalf("Failed to open test database: %v", err)
}
// Run migrations
if err := runMigrations(db); err != nil {
t.Fatalf("Failed to run migrations: %v", err)
}
return db
}
```
## 5. API Tests
### 5.1 Gateway API Tests
Tests für die Gateway-API-Endpunkte:
```go
func TestGatewayAPIEndpoints(t *testing.T) {
gateway := setupTestGateway(t)
defer gateway.Close()
testCases := []struct {
name string
method string
path string
headers map[string]string
body string
expectedStatus int
expectedBody string
}{
{
name: "health check",
method: "GET",
path: "/health",
expectedStatus: http.StatusOK,
expectedBody: `{"status":"healthy"}`,
},
{
name: "unauthorized request",
method: "POST",
path: "/v1/mail/send",
expectedStatus: http.StatusUnauthorized,
},
{
name: "authorized mail request",
method: "POST",
path: "/v1/mail/send",
headers: map[string]string{
"X-API-Key": "test-api-key",
"Content-Type": "application/json",
},
body: `{"name":"Test","email":"test@example.com","message":"Test"}`,
expectedStatus: http.StatusOK,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
req := createTestRequest(t, tc.method, gateway.URL+tc.path, tc.body)
for key, value := range tc.headers {
req.Header.Set(key, value)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != tc.expectedStatus {
t.Errorf("Expected status %d, got %d", tc.expectedStatus, resp.StatusCode)
}
if tc.expectedBody != "" {
body, _ := io.ReadAll(resp.Body)
if string(body) != tc.expectedBody {
t.Errorf("Expected body %s, got %s", tc.expectedBody, string(body))
}
}
})
}
}
```
### 5.2 Service API Tests
Tests für individuelle Service-APIs:
```go
func TestFormular2MailAPI(t *testing.T) {
service := startTestFormular2MailService(t)
defer service.Close()
t.Run("valid mail request", func(t *testing.T) {
reqBody := `{
"name": "John Doe",
"email": "john@example.com",
"message": "Test message"
}`
resp := makeTestRequest(t, service.URL+"/send", "POST", reqBody)
assertStatusCode(t, resp, http.StatusOK)
var response MailResponse
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
t.Fatalf("Failed to decode response: %v", err)
}
if !response.Success {
t.Error("Expected success=true in response")
}
})
t.Run("invalid mail request", func(t *testing.T) {
reqBody := `{"name": "", "email": "invalid", "message": ""}`
resp := makeTestRequest(t, service.URL+"/send", "POST", reqBody)
assertStatusCode(t, resp, http.StatusBadRequest)
})
}
```
## 6. Performance Tests
### 6.1 Gateway Performance Tests
```go
func TestGatewayPerformance(t *testing.T) {
if testing.Short() {
t.Skip("Skipping performance test in short mode")
}
gateway := setupTestGateway(t)
defer gateway.Close()
// Load test
concurrency := 10
requests := 1000
var wg sync.WaitGroup
errors := make(chan error, requests)
start := time.Now()
for i := 0; i < concurrency; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < requests/concurrency; j++ {
resp, err := http.Get(gateway.URL + "/health")
if err != nil {
errors <- err
return
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errors <- fmt.Errorf("unexpected status: %d", resp.StatusCode)
return
}
}
}()
}
wg.Wait()
close(errors)
duration := time.Since(start)
// Check for errors
for err := range errors {
t.Errorf("Request error: %v", err)
}
// Performance assertions
requestsPerSecond := float64(requests) / duration.Seconds()
if requestsPerSecond < 500 { // Minimum 500 RPS
t.Errorf("Performance too low: %.2f RPS", requestsPerSecond)
}
t.Logf("Performance: %.2f RPS over %v", requestsPerSecond, duration)
}
func BenchmarkGatewayRouting(b *testing.B) {
gateway := setupBenchmarkGateway(b)
req := httptest.NewRequest("GET", "/v1/mail/send", nil)
req.Header.Set("X-API-Key", "test-key")
b.ResetTimer()
for i := 0; i < b.N; i++ {
w := httptest.NewRecorder()
gateway.ServeHTTP(w, req)
}
}
```
## 7. Test-Daten und Test-Utilities
### 7.1 Test-Daten-Management
```go
// internal/testutil/fixtures.go
package testutil
func CreateTestMailRequest() MailRequest {
return MailRequest{
Name: "Test User",
Email: "test@example.com",
Subject: "Test Subject",
Message: "Test Message",
}
}
func CreateTestComment() *Comment {
return &Comment{
ID: uuid.New().String(),
PageURL: "https://example.com/test",
Author: "Test Author",
Email: "test@example.com",
Content: "Test Comment Content",
Status: StatusPending,
}
}
func CreateTestGatewayConfig() GatewayConfig {
return GatewayConfig{
Gateway: GatewaySettings{
Port: "8080",
LogLevel: "info",
},
Security: SecurityConfig{
APIKeys: []APIKey{
{
Key: "test-api-key",
Name: "Test Key",
Permissions: []string{"mail:send"},
AllowedIPs: []string{"127.0.0.1"},
},
},
},
Services: map[string]ServiceConfig{
"formular2mail": {
Enabled: true,
PathPrefix: "/v1/mail",
Upstream: "http://127.0.0.1:8081",
HealthCheck: "/health",
Timeout: 30 * time.Second,
},
},
}
}
```
### 7.2 Test-Helper-Funktionen
```go
// internal/testutil/helpers.go
package testutil
func AssertStatusCode(t *testing.T, resp *http.Response, expected int) {
t.Helper()
if resp.StatusCode != expected {
t.Errorf("Expected status code %d, got %d", expected, resp.StatusCode)
}
}
func AssertResponseBody(t *testing.T, resp *http.Response, expected string) {
t.Helper()
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Failed to read response body: %v", err)
}
if string(body) != expected {
t.Errorf("Expected body %q, got %q", expected, string(body))
}
}
func MakeTestRequest(t *testing.T, url, method, body string) *http.Response {
t.Helper()
var reqBody io.Reader
if body != "" {
reqBody = strings.NewReader(body)
}
req, err := http.NewRequest(method, url, reqBody)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
if body != "" {
req.Header.Set("Content-Type", "application/json")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("Request failed: %v", err)
}
return resp
}
```
## 8. Test-Umgebung und CI
### 8.1 Lokale Tests
- Alle Tests sollten mit `go test ./...` ausführbar sein
- Keine Tests sollten externe Ressourcen benötigen (wie echte E-Mail-Server)
- Performance-Tests mit `-short` Flag überspringen
### 8.2 Test-Tags
```go
// +build integration
package tests
// Integration tests that require external resources
```
**Ausführung:**
```bash
# Nur Unit Tests
go test ./...
# Mit Integration Tests
go test -tags=integration ./...
# Mit Performance Tests
go test -timeout=30m ./...
# Kurze Tests für CI
go test -short ./...
```
### 8.3 Coverage-Berichte
```bash
# Coverage generieren
go test -coverprofile=coverage.out ./...
# HTML-Report
go tool cover -html=coverage.out -o coverage.html
# Coverage-Threshold prüfen
go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//'
```
## 9. Spezifische Testfälle für Furt
### 9.1 Gateway-Routing Tests
```go
func TestGatewayServiceRouting(t *testing.T) {
testCases := []struct {
name string
requestPath string
method string
expectedService string
expectedUpstream string
wantErr bool
}{
{
name: "formular2mail routing",
requestPath: "/v1/mail/send",
method: "POST",
expectedService: "formular2mail",
expectedUpstream: "http://127.0.0.1:8081",
},
{
name: "sagjan comments routing",
requestPath: "/v1/comments",
method: "GET",
expectedService: "sagjan",
expectedUpstream: "http://127.0.0.1:8082",
},
{
name: "unknown service",
requestPath: "/v1/unknown",
method: "GET",
wantErr: true,
},
}
// Implementation...
}
```
### 9.2 Authentication Tests
```go
func TestGatewayAuthentication(t *testing.T) {
testCases := []struct {
name string
apiKey string
clientIP string
requestPath string
expectedStatus int
}{
{
name: "valid API key and IP",
apiKey: "hugo-frontend-key",
clientIP: "127.0.0.1",
requestPath: "/v1/mail/send",
expectedStatus: http.StatusOK,
},
{
name: "invalid API key",
apiKey: "invalid-key",
clientIP: "127.0.0.1",
requestPath: "/v1/mail/send",
expectedStatus: http.StatusUnauthorized,
},
{
name: "blocked IP",
apiKey: "hugo-frontend-key",
clientIP: "192.168.1.100",
requestPath: "/v1/mail/send",
expectedStatus: http.StatusForbidden,
},
}
// Implementation...
}
```
### 9.3 Service Health Check Tests
```go
func TestServiceHealthChecks(t *testing.T) {
// Test Gateway health aggregation
t.Run("all services healthy", func(t *testing.T) {
// Setup healthy services
// Test /health returns 200 with all services status
})
t.Run("one service unhealthy", func(t *testing.T) {
// Setup one failing service
// Test /health returns appropriate status
})
}
```
## 10. Test-Automation und CI-Integration
### 10.1 GitHub Actions / Gitea Actions
```yaml
# .gitea/workflows/test.yml
name: Test Suite
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.21
- name: Run Unit Tests
run: go test -short -race -coverprofile=coverage.out ./...
- name: Run Integration Tests
run: go test -tags=integration ./tests/integration/
- name: Check Coverage
run: |
coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "Coverage $coverage% is below 80%"
exit 1
fi
```
## 11. Best Practices Zusammenfassung
### 11.1 Do's
- ✅ **Testbare Architektur:** Dependency Injection verwenden
- ✅ **Isolierte Tests:** Keine Abhängigkeiten zwischen Tests
- ✅ **Realistische Test-Daten:** Aber anonymisiert und minimal
- ✅ **Performance-bewusst:** Benchmarks für kritische Pfade
- ✅ **Dokumentierte Test-Fälle:** Klare Beschreibungen der Test-Szenarien
### 11.2 Don'ts
- ❌ **Externe Ressourcen:** Keine echten E-Mail-Server, externe APIs
- ❌ **Feste Zeitstempel:** `time.Now()` mocken in Tests
- ❌ **Globaler State:** Tests sollten unabhängig sein
- ❌ **Überflüssige Tests:** Triviale Getter/Setter nicht testen
- ❌ **Fragile Tests:** Tests sollen bei kleinen Änderungen nicht brechen
---
Diese Richtlinien sollen als Leitfaden dienen und können im Laufe des Projekts angepasst und erweitert werden. Bei Unklarheiten oder Fragen zu diesen Richtlinien kann das Entwicklungsteam kontaktiert werden.