1. Project Background and Technology Selection
The survey service is the core service of a medical survey platform that deals with Patient-Reported Outcomes (PRO) reported directly by patients, managing the entire life cycle of surveys from defining the survey format to sending, collecting responses, and closing. Scoring, statistics, and report processing are handled by a separate metrics service, while the actual sending of notifications, chat, SMS/email is managed by a separate communication service, clearly delineating responsibilities so that this service can focus on the single responsibility of 'defining and collecting survey data'.
In an environment integrated with multiple internal microservices and external legacy medical information systems (EMR), we strategically selected the following technology stack to ensure data consistency and scalability.
• Java 21 & Spring Boot 3.5.13 : Reliability of the service is ensured based on the latest LTS runtime and stable Spring ecosystem.
• Spring Cloud 2025.0.0 (OpenFeign) : Inter-service synchronous communication is handled in a declarative manner, enhancing readability and maintainability.
• PostgreSQL & JPA/Hibernate & QueryDSL 5.0 : Complex survey domain models are managed in an object-oriented way, implementing type-safe dynamic queries. JSON columns are handled with hypersistence utils to flexibly store variable survey attributes.
• Apache Kafka : Asynchronous event communication between services reduces coupling and guarantees eventual consistency.
• OAuth2 & Keycloak : The industry-standard OAuth2 protocol has been applied for unified authentication (SSO) and authorization in a distributed environment.
• Redis · ShedLock · MapStruct · Jasypt : Supporting technologies such as caching, distributed schedule locking, object mapping, and configuration encryption have been applied to ensure operational stability.
2. Core Technology Application and Architecture Design
2.1 Domain-Centric Multi-Module and Hexagonal Architecture
To protect business logic from technical dependencies, a domain-centric multi-module structure has been adopted. This reflects the concept of hexagonal (port-adapter) architecture, where core domain logic is concentrated in the domain module, and database persistence (store-jpa) and external service integration (proxy) are separated as interchangeable adapters.
The service consists of 9 modules based on responsibilities: domain (domain model, port), store-jpa (persistence adapter), proxy (external integration, event publishing adapter), feature (use cases), facade (REST, event receiving), client/event (contract, event artifacts consumed by other services), scheduler (batch), boot (assembly, entry point). The use case layer only depends on the domain interface, and the actual implementation is injected (DIP) by the boot module, which keeps the core logic unchanged regardless of changes in integration targets.
2.2 CQRS-Based Command/Query Responsibility Segregation
The CQRS pattern has been applied to suit the unique characteristics of survey domains where the requirements for writing and reading differ. Data changes are performed in the normalized command model (cm_* tables), while queries are handled in the denormalized query model (qm_* views) optimized for screens. The two models are synchronized through events to maintain eventual consistency.
This ensures that complex list and search queries do not burden command transactions, and the query model can be freely denormalized to meet screen requirements. The selection of targets for commands is always based on the command model, which guarantees the most up-to-date values to ensure consistency.
2.3 Data Isolation and Protection Through Multi-Tenancy and Soft Deletion
To accommodate an environment where multiple healthcare institutions and clinical units share a single platform, common base entities have been designed to automatically inject tenant identifiers (institution/clinical department/level) into all data. This allows for tenant-level data isolation without intervention from the application code.
Additionally, all entities apply soft deletion using a validity flag instead of physical deletion, enabling audit tracking of deleted data and meeting the requirement for medical data history retention.
3. Key function implementation and problem-solving experience
3.1 Secure version management of the survey form (Master/Snapshot pattern)
The survey form can be modified frequently during operation, but there was a stringent requirement to maintain the integrity of the form at the time of dispatch for surveys that have already been sent and answered by patients. This was resolved using the 'Master/Snapshot' pattern.
• Editing (Master): The author can freely edit the Master form. The Master holds a pointer that indicates the currently active snapshot.
• Publishing: At the time of publication, an immutable snapshot is created by duplicating the contents of the Master. Subsequent surveys are fixed to this snapshot.
• Ensuring response integrity: Patient responses always reference the snapshot from the time of dispatch, so even if the form is changed later, the meaning of past responses is not compromised.
We also implemented a preview publication for pre-validation, a flow for merging edits into the Master, achieving uninterrupted form revision and data integrity during operation.
3.2 Survey sending, assignment, and response collection lifecycle
The survey operation has been modeled in the stages of 'Assignment → Task → Status'. The assignment (who sends what to whom on what schedule) generates individual execution units called tasks, and the progress status of the tasks (Not Started/Saved Temporarily/Submitted/Completed, etc.) is managed in a separate status container.
Responses are normalized to be stored differently according to the question type: subjective questions are stored as values, and objective questions as a set of selectable options, ensuring consistent processing for subsequent scoring and statistics. Also, the handling of survey completion/forced completion/expiration is clearly separated as use cases, reducing operational burden by having the scheduler automatically perform deadlines, expirations, and communication terminations.
3.3 Integration with External Legacy Medical Information Systems
Integration with existing healthcare institutions' legacy EMRs follows the principle of not using physical foreign keys (FK) between microservices but only logical references based on IDs. External system integration is routed through a separate adapter service using REST (Feign), forming a corruption prevention layer (ACL) to prevent changes in external systems from directly penetrating the core domain.
By mapping the identification numbers generated by the legacy system at the moment of response storage, we connected data between both systems in a consistent manner and abstracted the integration implementation into a Strategy pattern to allow for future expansion by adding other institutions/systems without modifying the core logic.
4. Infrastructure and Operational Efficiency
4.1 Resolving Service Coupling Through Apache Kafka
When meaningful events occur within the domain (form announcements, survey dispatches, response completions, case completions, etc.), they are published as domain events. The scoring/statistics service and notification/chat service subscribe to only the necessary events, performing their respective responsibilities, thereby eliminating direct call dependencies between services and preventing a failure on one side from propagating to the other.
Conversely, changes to user/organization information events are subscribed to by the service itself, updating the query model to maintain effective consistency with the master data. Events for converting to standard medical information exchange formats (FHIR) are also published to secure external linkage scalability.
4.2 Operational Stability Infrastructure (Redis · ShedLock · Outbox)
• Redis Caching: Common data that is frequently accessed is cached (with TTL applied) to improve query performance and reduce database load.
• ShedLock : In a multi-instance environment, we ensured the uniqueness of tasks using distributed locks to prevent the scheduler from running duplicate executions for tasks such as closing and sending.
• Outbox pattern: Using the outbox pattern of the common library, we implemented reliable publishing without event loss by bundling data changes and event publishing within the same transaction.
4.3 Security and Authentication
External entry points are protected by an OAuth2 Resource Server, allowing only validated tokens (JWT), and separating roles for patients, medical staff, operators, and administrators through role-based access control. Internal calls between services use client_credentials type service tokens that are automatically injected by the Feign interceptor, designed to separate business logic from authentication codes. Sensitive values in configurations, such as database connection information, are stored encrypted (Jasypt), and credentials and internal endpoints are managed by injecting only into environment variables in the production environment to avoid exposure in the source.
4.4 Contract-based Module Deployment Strategy
The communication contract (Feign interface) for other services to call this service and the schema for events to subscribe to are separated into client/event modules and deployed to the internal artifact repository. The consuming service brings this artifact in as a dependency, making API changes evident at compile time and increasing integration stability.
5. Conclusion and Achievements
The survey service is a case that has secured both scalability and stability by encapsulating the entire lifecycle from the definition of the survey to the collection with a single responsibility, while separating subsequent processing such as scoring and notification as events.
• Data Integrity: Even with changes in format, we preserved the consistency of past responses using the Master/Snapshot pattern.
• Decoupling: Achieved lower coupling between services and fault isolation with Kafka event-driven asynchronous communication.
• Secured scalability: With a hexagonal multi-module and multi-tenancy design, we have established a foundation that can flexibly respond to an increase in new integration targets or adopting institutions without modifying core logic.
The domain-driven design, CQRS, and event-driven architecture experience gained from this project will be a key asset for future system design and construction dealing with complex domains.
conley