# Design der Umfrageverwaltung (Survey Management)

## Überblick

Die Funktion **Umfrageverwaltung** stellt eine RESTful API zum Erstellen, Konfigurieren und Verwalten von Online-Umfragen bereit. Das System folgt einer zustandslosen Microservice-Architektur auf Basis von Spring Boot, sodass Umfrage-Administrator:innen den vollständigen Lebenszyklus einer Umfrage abbilden können – inklusive Erstellung, Fragenverwaltung, Abruf und Löschung.

Das Design betont Datenintegrität, Validierung und Skalierbarkeit durch zustandslose Operationen. Alle Umfragedaten werden mittels JPA/Hibernate persistiert.

## Architektur

### Grobarchitektur

Das System folgt dem Microservice-Architekturpattern:

```
┌─────────────────────────────────────────────┐
│         Client Applications                 │
│    (Web, Mobile, Third-party services)      │
└────────────────┬────────────────────────────┘
                 │ HTTP/REST
                 ▼
┌─────────────────────────────────────────────┐
│      Online Survey Backend (Spring Boot)    │
│                                             │
│  ┌──────────────────────────────────────┐   │
│  │    REST API Layer (Controllers)      │   │
│  └──────────────┬───────────────────────┘   │
│                 │                           │
│  ┌──────────────▼───────────────────────┐   │
│  │    Business Logic Layer (Services)   │   │
│  └──────────────┬───────────────────────┘   │
│                 │                           │
│  ┌──────────────▼───────────────────────┐   │
│  │   Data Access Layer (Repositories)   │   │
│  └──────────────┬───────────────────────┘   │
│                 │                           │
│  ┌──────────────▼───────────────────────┐   │
│  │         Domain Model (Entities)      │   │
│  └──────────────────────────────────────┘   │
└────────────────┬────────────────────────────┘
                 │ JDBC
                 ▼
┌─────────────────────────────────────────────┐
│          Database (H2/PostgreSQL)           │
└─────────────────────────────────────────────┘
```

### Technologie-Stack

- **Framework**: Spring Boot 3.x
- **Persistenz**: Spring Data JPA mit Hibernate
- **Datenbank**: H2 (Entwicklung), PostgreSQL (produktionstauglich)
- **Validierung**: Bean Validation (JSR-303)
- **Testing**: JUnit 5, Spring Boot Test, jqwik (Property-Based Testing)

### Designentscheidungen

1. **Separation of Concerns**: Jede Schicht hat klar getrennte Verantwortlichkeiten; entkoppelte Modelle und Mapper übersetzen zwischen den Schichten.
2. **Zustandslose Kommunikation**: Jede Anfrage enthält alle notwendigen Informationen und ermöglicht horizontale Skalierung.
3. **UUID-Identifikatoren**: Alle Entitäten nutzen UUIDv4 für global eindeutige, nicht-sequentielle Identifikatoren.
4. **Cascade-Operationen**: Das Löschen einer Umfrage kaskadiert zu Fragen und Antwortoptionen, um Datenkonsistenz sicherzustellen.
5. **Validation-First-Ansatz**: Umfassende Validierung auf Entitäts- und Service-Ebene nach etablierten Patterns.
6. **RESTful API Design**: Ressourcenbasierte URLs mit korrekten HTTP-Methoden und Statuscodes.

## Komponenten und Schnittstellen

### REST-Controller

**SurveyController**

- `POST /api/surveys` – Neue Umfrage erstellen
- `GET /api/surveys/{surveyId}` – Umfragedetails abrufen
- `DELETE /api/surveys/{surveyId}` – Umfrage löschen
- `POST /api/surveys/{surveyId}/questions` – Frage zur Umfrage hinzufügen
- `DELETE /api/surveys/{surveyId}/questions/{questionId}` – Frage löschen

### Service-Schicht

**SurveyService**

- Management des Umfrage-Lebenszyklus
- Validierung von Business-Regeln
- Transaktionskoordination

**QuestionService**

- Fragenverwaltung innerhalb von Umfragen
- Handling von Antwortoptionen
- Validierung der Reihenfolge

### Repository-Schicht

**SurveyRepository** (erweitert `JpaRepository`)

- Basis-CRUD-Operationen für Umfragen
- Custom Queries zum Abruf von Umfragen inklusive Fragen

**QuestionRepository** (erweitert `JpaRepository`)

- CRUD-Operationen für Fragen
- Queries zur Validierung von Ordnungsnummern

**AnswerOptionRepository** (erweitert `JpaRepository`)

- Verwaltung von Antwortoptionen
- Validierung der Eindeutigkeit interner Werte

## Datenmodelle

Die Datenmodelle entsprechen dem semantischen Datenmodell und implementieren die Entitäten Survey, Question und AnswerOption für die Umfrageverwaltungsfunktion.

### Survey-Entität

```java
@Entity
@Table(name = "survey")
public class Survey {
		@Id
		@Column(name = "survey_id")
		private UUID surveyId;

		@NotBlank
		@Size(max = 200)
		@Column(name = "title", nullable = false)
		private String title;

		@Size(max = 2000)
		@Column(name = "description")
		private String description;

		@NotBlank
		@Size(max = 100)
		@Column(name = "created_by", nullable = false)
		private String createdBy;

		@Column(name = "start_date")
		private LocalDate startDate;

		@Column(name = "end_date")
		private LocalDate endDate;

		@CreationTimestamp
		@Column(name = "created_at", nullable = false)
		private Instant createdAt;

		@OneToMany(mappedBy = "survey", cascade = CascadeType.ALL, orphanRemoval = true)
		@OrderBy("orderNumber ASC")
		private List<Question> questions = new ArrayList<>();
}
```

### Question-Entität

```java
@Entity
@Table(name = "question")
public class Question {
		@Id
		@Column(name = "question_id")
		private UUID questionId;

		@ManyToOne(fetch = FetchType.LAZY)
		@JoinColumn(name = "survey_id", nullable = false)
		private Survey survey;

		@NotNull
		@Min(1)
		@Column(name = "order_number", nullable = false)
		private Integer orderNumber;

		@NotBlank
		@Size(max = 1000)
		@Column(name = "question_text", nullable = false)
		private String questionText;

		@Enumerated(EnumType.STRING)
		@NotNull
		@Column(name = "question_type", nullable = false)
		private QuestionType questionType;

		@NotNull
		@Column(name = "is_mandatory", nullable = false)
		private Boolean isMandatory;

		@OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
		private List<AnswerOption> answerOptions = new ArrayList<>();
}
```

### AnswerOption-Entität

```java
@Entity
@Table(name = "answer_option")
public class AnswerOption {
		@Id
		@Column(name = "option_id")
		private UUID optionId;

		@ManyToOne(fetch = FetchType.LAZY)
		@JoinColumn(name = "question_id", nullable = false)
		private Question question;

		@NotBlank
		@Size(max = 200)
		@Column(name = "option_text", nullable = false)
		private String optionText;

		@NotBlank
		@Pattern(regexp = "^[A-Za-z0-9_-]+$")
		@Size(max = 100)
		@Column(name = "value", nullable = false)
		private String value;

		@Column(name = "is_other_option")
		private Boolean isOtherOption = false;
}
```

### QuestionType-Enum

```java
public enum QuestionType {
		RATING("Rating"),
		SINGLE_CHOICE("SingleChoice"),
		MULTIPLE_CHOICE("MultipleChoice"),
		OPEN("Open");

		private final String value;

		QuestionType(String value) {
				this.value = value;
		}

		public String getValue() {
				return value;
		}
}
```

### Entitätsbeziehungen

- Survey → Questions (One-to-Many, CASCADE ALL)
- Question → AnswerOptions (One-to-Many, CASCADE ALL)
- Bidirektionale Beziehungen mit passenden Foreign-Key-Constraints
- Spaltennamen und Constraints entsprechen den Spezifikationen des semantischen Datenmodells

## Korrektheits-Properties

_Eine Property ist eine Eigenschaft oder ein Verhalten, das über alle gültigen Ausführungen eines Systems hinweg gelten soll – im Kern eine formale Aussage darüber, was das System tun muss. Properties bilden die Brücke zwischen menschenlesbaren Spezifikationen und maschinell überprüfbaren Korrektheitsgarantien._

Nach der Analyse der Akzeptanzkriterien lassen sich mehrere Properties konsolidieren, um Redundanzen zu reduzieren und gleichzeitig eine umfassende Validierungsabdeckung sicherzustellen:

**Property 1: Umfrageerstellung mit gültigen Daten ist erfolgreich**
_Für beliebige_ gültige Umfragedaten (nicht-leerer Titel, gültiger Ersteller, korrekte Datumsreihenfolge) muss das Erstellen einer Umfrage erfolgreich sein und eine eindeutige UUID zurückgeben.
**Validiert: Anforderungen 1.1, 1.2, 1.5**

**Property 2: Ungültige Umfragedaten werden mit aussagekräftigen Fehlern abgelehnt**
_Für beliebige_ ungültige Umfragedaten (leerer/Whitespace-Titel, Enddatum vor Startdatum, fehlende Pflichtfelder) muss die Erstellung abgelehnt werden und spezifische Fehlermeldungen liefern, die die Validierungsursache erklären.
**Validiert: Anforderungen 1.3, 1.4, 6.1, 6.2**

**Property 3: Erstellung einer Frage erhält alle angegebenen Attribute**
_Für beliebige_ gültige Fragendaten, die einer existierenden Umfrage hinzugefügt werden, muss die gespeicherte Frage exakt die angegebene Ordnungsnummer, den Text, den Typ, das Pflicht-Flag sowie alle gelieferten Antwortoptionen mit Anzeigetext und internem Wert enthalten.
**Validiert: Anforderungen 2.1, 2.2**

**Property 4: Fragenvalidierung erzwingt Business-Regeln**
_Für beliebige_ Versuche, Fragen zu erstellen, die Business-Regeln verletzen (doppelte Ordnungsnummern, zu wenige Antwortoptionen für Choice-/Rating-Fragen, doppelte interne Werte), muss das System die Erstellung ablehnen und spezifische Fehlermeldungen zurückgeben.
**Validiert: Anforderungen 2.3, 2.4, 2.5, 6.3**

**Property 5: Umfrageabruf liefert vollständige und geordnete Daten**
_Für beliebige_ existierende Umfragen muss der Abruf alle Umfragemetadaten, Fragen in aufsteigender Reihenfolge nach Ordnungsnummer, alle Antwortoptionen (Anzeigetext und interner Wert), den Erstellungszeitpunkt sowie alle notwendigen Identifikatoren für Folgeoperationen enthalten.
**Validiert: Anforderungen 3.1, 3.3, 3.4, 3.5, 7.4**

**Property 6: Anfragen auf nicht existierende Ressourcen liefern passende Fehler**
_Für beliebige_ Anfragen mit ungültigen Identifikatoren (nicht existierende Survey-ID, Question-ID) muss das System Not-Found-Fehler zurückgeben, die klar benennen, welche Ressource nicht gefunden wurde.
**Validiert: Anforderungen 3.2, 4.3, 5.2, 6.4**

**Property 7: Löschen einer Frage entfernt die Frage und kaskadiert zu Antwortoptionen**
_Für beliebige_ gültige Löschanfragen für Fragen müssen die Frage und alle zugehörigen Antwortoptionen dauerhaft entfernt werden; eine Bestätigung wird zurückgegeben, aber keine gelöschten Daten.
**Validiert: Anforderungen 4.1, 4.4, 4.5**

**Property 8: Cross-Survey-Operationen auf Fragen werden abgelehnt**
_Für beliebige_ Versuche, eine Frage zu löschen, wobei die Question-ID zu einer anderen Umfrage gehört als in der URL angegeben, muss das System die Operation mit einem Validierungsfehler ablehnen.
**Validiert: Anforderungen 4.2**

**Property 9: Umfragelöschung kaskadiert vollständig**
_Für beliebige_ gültige Löschanfragen für Umfragen müssen die Umfrage, alle Fragen, alle Antwortoptionen sowie alle zugehörigen Responses dauerhaft entfernt werden; eine Bestätigung wird zurückgegeben, aber keine gelöschten Daten.
**Validiert: Anforderungen 5.1, 5.3, 5.4, 5.5**

**Property 10: Mehrere Validierungsfehler werden aggregiert**
_Für beliebige_ Anfragen mit mehreren Validierungsproblemen müssen alle Validierungsfehler in einer einzigen Response zurückgegeben werden.
**Validiert: Anforderungen 6.5**

**Property 11: Operationen erfordern korrekte Identifikatoren**
_Für beliebige_ mehrstufige Operationssequenzen muss jede Anfrage die passenden Identifikatoren (Survey-ID, Question-ID) explizit enthalten.
**Validiert: Anforderungen 7.2**

**Property 12: Fehlerantworten sind in sich geschlossen**
_Für beliebige_ Fehlerbedingungen muss die Fehlerantwort vollständige Informationen enthalten, ohne sich auf Kontext aus vorherigen Requests zu stützen.
**Validiert: Anforderungen 7.5**

**Property 13: Textdaten werden konsistent normalisiert**
_Für beliebige_ Texteingaben mit führenden oder nachgestellten Leerzeichen muss der gespeicherte Wert getrimmt werden.
**Validiert: Anforderungen 8.1**

**Property 14: Validierung und Standardisierung von Datumsformaten**
_Für beliebige_ Datumseingaben muss das System das Format validieren und Daten im ISO-8601-Format (YYYY-MM-DD) speichern.
**Validiert: Anforderungen 8.2**

**Property 15: Validierung des Formats interner Werte**
_Für beliebige_ interne Werte von Antwortoptionen darf das System ausschließlich alphanumerische Zeichen, Bindestriche und Unterstriche akzeptieren.
**Validiert: Anforderungen 8.3**

**Property 16: Konsistenz von Identifikator- und Timestamp-Formaten**
_Für beliebige_ Entitätserstellungen müssen generierte Identifikatoren dem UUID-Format entsprechen und Erstellungs-Timestamps im ISO-8601-UTC-Format vorliegen.
**Validiert: Anforderungen 8.4, 8.5**

## Fehlerbehandlung

### Strategie für HTTP-Statuscodes

Gemäß den Architekturleitlinien:

- **400 Bad Request**: Ungültige Eingaben, Validierungsfehler, Verletzung von Business-Regeln
- **404 Not Found**: Angeforderte Ressource existiert nicht
- **409 Conflict**: Operation kollidiert mit dem aktuellen Zustand (z. B. doppelte Ordnungsnummern)
- **422 Unprocessable Entity**: Request ist syntaktisch gültig, kann aber wegen Business-Regeln nicht verarbeitet werden
- **500 Internal Server Error**: Unerwartete Systemfehler

### Format der Validierungsfehlerantwort

```json
{
  "timestamp": "2024-01-15T10:30:00Z",
  "status": 400,
  "error": "Bad Request",
  "message": "Validation failed",
  "path": "/api/surveys",
  "correlationId": "abc123-def456-ghi789",
  "validationErrors": [
    {
      "field": "title",
      "rejectedValue": "",
      "message": "Title cannot be empty or contain only whitespace"
    },
    {
      "field": "endDate",
      "rejectedValue": "2024-01-01",
      "message": "End date must be after start date"
    }
  ]
}
```

### Strategie für Exception-Handling

- Eigene Exception-Klassen für unterschiedliche Fehlertypen
- Globaler Exception-Handler via `@ControllerAdvice`
- Konsistentes Error-Response-Format über alle Endpoints
- Correlation IDs für Troubleshooting
- Detailliertes Logging mit Correlation IDs, ohne sensible Daten offenzulegen
- Keine Preisgabe interner Systemdetails, Datenbankstrukturen oder sensibler Informationen

## Teststrategie

### Dualer Testansatz

Die Teststrategie kombiniert Unit-Tests und Property-Based Tests für umfassende Abdeckung:

- **Unit-Tests** verifizieren konkrete Beispiele, Edge Cases und Integrationspunkte zwischen Komponenten.
- **Property-Based Tests** verifizieren universelle Properties, die über alle Inputs hinweg gelten sollen, mithilfe der jqwik-Bibliothek.
- Zusammen liefern sie eine hohe Abdeckung: Unit-Tests finden konkrete Bugs, Property-Tests verifizieren allgemeine Korrektheit.

### Anforderungen an Unit-Tests

Unit-Tests decken ab:

- Konkrete Beispiele, die das korrekte Verhalten je Endpoint demonstrieren
- Integration zwischen Controller-, Service- und Repository-Schicht
- Fehlerbehandlungsszenarien mit bekannten Inputs
- Validierung von Datenbank-Constraints
- JSON-Serialisierung/Deserialisierung

### Anforderungen an Property-Based Tests

Property-Based Testing nutzt die Bibliothek **jqwik** für Java und wird so konfiguriert, dass mindestens 100 Iterationen pro Property-Test ausgeführt werden. Jeder Property-Test wird mit einem Kommentar getaggt, der explizit auf die Korrektheits-Property aus diesem Dokument referenziert, im Format: `**Feature: survey-management, Property {number}: {property_text}**`

Jede oben aufgeführte Korrektheits-Property wird durch genau einen Property-Based Test implementiert, der zufällige gültige und ungültige Inputs generiert, um das spezifizierte Verhalten universell zu verifizieren.

### Strategie zur Testdatengenerierung

- **Smart Generators**: Generatoren, die Inputs intelligent auf gültige Wertebereiche einschränken
- **Edge-Case-Abdeckung**: Grenzwerte, leere Collections und Limit-Fälle
- **Generierung ungültiger Inputs**: Verschiedene Klassen ungültiger Daten zur Validierung der Fehlermeldungen
- **Realistische Daten**: Sinnvolle Umfragetitel, Fragen und Antwortoptionen für bessere Lesbarkeit der Tests

### Konfiguration des Test-Frameworks

```
- **JUnit 5** für Unit-Tests mit Spring-Boot-Test-Integration
- **jqwik** für Property-Based Testing mit Custom Generators
- **TestContainers** für Integrationstests mit einer echten Datenbank
- **MockMvc** für REST-API-Tests
- **AssertJ** für Fluent Assertions
```

Der Testansatz stellt sicher, dass sowohl konkrete Szenarien als auch das allgemeine Systemverhalten gründlich validiert werden – und schafft damit Vertrauen in Korrektheit und Robustheit des Umfrageverwaltungssystems.
