Modular monolith
The engineering handbook prefers a modular monolith first: Gradle modules, schema isolation, and extractability, without a network hop for every call. The repository now runs those modules as separate processes behind Kong because the boundaries (auth, social, feed, media, messaging, expense, notification, communication, relay) are deployed and observed on their own.
Rules that still hold
- A module owns its schema and its Flyway history.
- Domain code does not import another module's JPA entities.
- Cross-context reads use an HTTP client or a local projection filled from events.
- Shared code lives in
splick-backend/shared/*as libraries, not as a hidden runtime.
Shared modules
| Module | Role |
|---|---|
shared-database | Datasource, Hikari, JPA baseline (DataSourceFactory, PostgresConfig) |
shared-redis | Stream consumer helpers |
shared-events | Envelopes, routes, stream names, event type constants |
shared-outbox | OutboxWriter, JdbcOutboxWriter, OutboxRelayEngine |
shared-inbox | Inbox repository and InboxMessageWorker |
shared-idempotency | HTTP IdempotencyFilter |
shared-communication-ports | EmailSenderPort, SmsSenderPort, OtpSenderPort |
shared-logging | Correlation, access log, use-case metrics, application-shared.yml |
shared-security | JwtAuthenticationFilter and JSON 401/403 bodies |
shared-web | GlobalExceptionHandler |
shared-feign | Shared DTO contracts for internal HTTP (clients in services are mostly Spring HTTP interfaces, not Feign calls) |
shared-i18n | Locale parsing and message keys |
Details: Shared modules.