Skip to content

← Back to post

AI-Driven Development with Amazon Kiro

12/23/2025

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

@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

@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

@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

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

{
  "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.