# Survey Management Feature Design

## Overview

The Survey Management feature provides a RESTful API for creating, configuring, and managing online surveys. The system follows a stateless microservice architecture built on Spring Boot, enabling survey administrators to perform complete lifecycle operations on surveys including creation, question management, retrieval, and deletion.

The design emphasizes data integrity, validation, and scalability through stateless operations. All survey data is persisted using JPA/Hibernate.

## Architecture

### High-Level Architecture

The system follows the microservice architecture pattern:

```
┌─────────────────────────────────────────────┐
│         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)           │
└─────────────────────────────────────────────┘
```

### Technology Stack

- **Framework**: Spring Boot 3.x
- **Persistence**: Spring Data JPA with Hibernate
- **Database**: H2 (development), PostgreSQL (production ready)
- **Validation**: Bean Validation (JSR-303)
- **Testing**: JUnit 5, Spring Boot Test, jqwik (Property-Based Testing)

### Design Decisions

1. **Separation of Concerns**: Each layer has distinct responsibilities with decoupled models and mappers for translation between layers
2. **Stateless Communication**: Each request contains all necessary information, enabling horizontal scaling
3. **UUID Identifiers**: All entities use UUIDv4 for globally unique, non-sequential identifiers
4. **Cascade Operations**: Survey deletion cascades to questions and answer options for data consistency
5. **Validation-First Approach**: Comprehensive validation at both entity and service levels following established patterns
6. **RESTful API Design**: Resource-based URLs with proper HTTP methods and status codes

## Components and Interfaces

### REST Controllers

**SurveyController**

- `POST /api/surveys` - Create new survey
- `GET /api/surveys/{surveyId}` - Retrieve survey details
- `DELETE /api/surveys/{surveyId}` - Delete survey
- `POST /api/surveys/{surveyId}/questions` - Add question to survey
- `DELETE /api/surveys/{surveyId}/questions/{questionId}` - Delete question

### Service Layer

**SurveyService**

- Survey lifecycle management
- Business rule validation
- Transaction coordination

**QuestionService**

- Question management within surveys
- Answer option handling
- Order validation

### Repository Layer

**SurveyRepository** (extends JpaRepository)

- Basic CRUD operations for surveys
- Custom queries for survey retrieval with questions

**QuestionRepository** (extends JpaRepository)

- Question CRUD operations
- Order number validation queries

**AnswerOptionRepository** (extends JpaRepository)

- Answer option management
- Internal value uniqueness validation

## Data Models

The data models align with the semantic data model, implementing the Survey, Question, and AnswerOption entities for the survey management feature.

### Survey Entity

```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 Entity

```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<>();
}
```

### Answer Option Entity

```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;
}
```

### Question Type 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;
    }
}
```

### Entity Relationships

- Survey → Questions (One-to-Many, CASCADE ALL)
- Question → AnswerOptions (One-to-Many, CASCADE ALL)
- Bidirectional relationships with proper foreign key constraints
- Column names and constraints align with the semantic data model specifications

## Correctness Properties

_A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees._

After analyzing the acceptance criteria, several properties can be consolidated to eliminate redundancy while maintaining comprehensive validation coverage:

**Property 1: Survey creation with valid data succeeds**
_For any_ valid survey data (non-empty title, valid creator, proper date ordering), creating a survey should succeed and return a unique UUID identifier
**Validates: Requirements 1.1, 1.2, 1.5**

**Property 2: Invalid survey data is rejected with descriptive errors**
_For any_ invalid survey data (empty/whitespace title, end date before start date, missing required fields), creation should be rejected with specific error messages explaining the validation failure
**Validates: Requirements 1.3, 1.4, 6.1, 6.2**

**Property 3: Question creation preserves all specified attributes**
_For any_ valid question data added to an existing survey, the stored question should contain exactly the specified order number, text, type, mandatory flag, and all provided answer options with their display text and internal values
**Validates: Requirements 2.1, 2.2**

**Property 4: Question validation enforces business rules**
_For any_ question creation attempt that violates business rules (duplicate order numbers, insufficient answer options for choice/rating questions, duplicate internal values), the system should reject the creation with specific error messages
**Validates: Requirements 2.3, 2.4, 2.5, 6.3**

**Property 5: Survey retrieval returns complete and ordered data**
_For any_ existing survey, retrieval should return all survey metadata, questions in ascending order by order number, all answer options with display text and internal values, creation timestamp, and all necessary identifiers for subsequent operations
**Validates: Requirements 3.1, 3.3, 3.4, 3.5, 7.4**

**Property 6: Non-existent resource requests return appropriate errors**
_For any_ request using invalid identifiers (non-existent survey ID, question ID), the system should return not found errors indicating which specific resource could not be located
**Validates: Requirements 3.2, 4.3, 5.2, 6.4**

**Property 7: Question deletion removes question and cascades to answer options**
_For any_ valid question deletion request, the question and all associated answer options should be permanently removed, with confirmation returned but no deleted data included in the response
**Validates: Requirements 4.1, 4.4, 4.5**

**Property 8: Cross-survey question operations are rejected**
_For any_ attempt to delete a question using a question ID that belongs to a different survey than specified, the system should reject the operation with a validation error
**Validates: Requirements 4.2**

**Property 9: Survey deletion cascades completely**
_For any_ valid survey deletion request, the survey, all questions, all answer options, and all associated responses should be permanently removed, with confirmation returned but no deleted data included
**Validates: Requirements 5.1, 5.3, 5.4, 5.5**

**Property 10: Multiple validation errors are aggregated**
_For any_ request with multiple validation issues, all validation errors should be returned in a single response
**Validates: Requirements 6.5**

**Property 11: Operations require proper identifiers**
_For any_ multi-step operation sequence, each request should require the appropriate identifiers (survey ID, question ID) to be explicitly provided
**Validates: Requirements 7.2**

**Property 12: Error responses are self-contained**
_For any_ error condition, the error response should provide complete information without relying on previous request context
**Validates: Requirements 7.5**

**Property 13: Text data is normalized consistently**
_For any_ text input with leading or trailing whitespace, the stored value should have whitespace trimmed
**Validates: Requirements 8.1**

**Property 14: Date format validation and standardization**
_For any_ date input, the system should validate the format and store dates in ISO 8601 format (YYYY-MM-DD)
**Validates: Requirements 8.2**

**Property 15: Internal value format validation**
_For any_ answer option internal value, the system should accept only alphanumeric characters, dashes, and underscores
**Validates: Requirements 8.3**

**Property 16: Identifier and timestamp format consistency**
_For any_ entity creation, generated identifiers should follow UUID format and creation timestamps should use ISO 8601 UTC format
**Validates: Requirements 8.4, 8.5**

## Error Handling

The error handling strategy follows the established architecture patterns for consistent error responses across the system.

### HTTP Status Code Strategy

Following the established architecture guidelines:

- **400 Bad Request**: Invalid input, validation failures, business rule violations
- **404 Not Found**: Requested resource does not exist
- **409 Conflict**: Operation conflicts with current state (e.g., duplicate order numbers)
- **422 Unprocessable Entity**: Valid request but cannot be processed due to business rules
- **500 Internal Server Error**: Unexpected system errors

### Validation Error Response Format

```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"
    }
  ]
}
```

### Exception Handling Strategy

- Custom exception classes for different error types
- Global exception handler using `@ControllerAdvice`
- Consistent error response format across all endpoints
- Correlation IDs for troubleshooting
- Detailed logging with correlation IDs while protecting sensitive data
- No exposure of internal system details, database structure, or sensitive information

## Testing Strategy

### Dual Testing Approach

The testing strategy employs both unit testing and property-based testing to ensure comprehensive coverage:

- **Unit tests** verify specific examples, edge cases, and integration points between components
- **Property-based tests** verify universal properties that should hold across all inputs using the jqwik library
- Together they provide comprehensive coverage: unit tests catch concrete bugs, property tests verify general correctness

### Unit Testing Requirements

Unit tests will cover:

- Specific examples demonstrating correct behavior for each endpoint
- Integration between controller, service, and repository layers
- Error handling scenarios with known inputs
- Database constraint validation
- JSON serialization/deserialization

### Property-Based Testing Requirements

Property-based testing will use the **jqwik** library for Java, configured to run a minimum of 100 iterations per property test. Each property-based test will be tagged with a comment explicitly referencing the correctness property from this design document using the format: `**Feature: survey-management, Property {number}: {property_text}**`

Each correctness property listed above will be implemented by a single property-based test that generates random valid and invalid inputs to verify the specified behavior holds universally.

### Test Data Generation Strategy

- **Smart Generators**: Create generators that intelligently constrain inputs to valid domains
- **Edge Case Coverage**: Include boundary values, empty collections, and limit cases
- **Invalid Input Generation**: Generate various types of invalid data to test validation
- **Realistic Data**: Use meaningful survey titles, questions, and answer options for better test readability

### Testing Framework Configuration

- **JUnit 5** for unit tests with Spring Boot Test integration
- **jqwik** for property-based testing with custom generators
- **TestContainers** for integration testing with real database
- **MockMvc** for REST API testing
- **AssertJ** for fluent assertions

The testing approach ensures that both specific scenarios and general system behavior are thoroughly validated, providing confidence in the correctness and robustness of the survey management system.
