SmartGare
Architecture

Backend architecture

Java 25, Spring Boot 4, Spring Modulith, hexagonal modules, persistence, and executable boundaries.

SmartGare is one deployable modular monolith. Business capabilities are independent Maven modules assembled by product/apps/server.

Module shape

product/modules/<feature>/
├── core/
│   ├── model/       pure domain rules and value objects
│   ├── usecase/     commands and decisions
│   └── port/        needs stated in domain vocabulary
├── inbound/         web, messaging, scheduling, MCP
├── outbound/        persistence and external systems
├── api/             published cross-module contract
└── config/          composition

Dependencies point inward. Core code imports no adapter or framework type. A business module reaches another only through its named api interface.

Enforced invariants

  • Spring Modulith detects modules explicitly and rejects cycles.
  • ArchUnit keeps domain models framework-free and adapters pointing inward.
  • Only use cases publish integration events.
  • HTTP and MCP operations must declare authorization.
  • Every scheduled method holds a named distributed lock.
  • Modules use typed text identifiers and never handle UUID directly.
  • Persistence readers project to response objects; writers rehydrate domain models.

Web contract

Controllers receive RequestContext as their first argument. Use cases validate input for every adapter, not only HTTP. One error model maps validation, not-found, conflict, forbidden, business, and technical failures.

OpenAPI adds shared error responses centrally and hides resolver-supplied arguments. Controller integration tests assert the generated document.

Persistence

Each module owns Flyway migrations under db/migration/<domain> and one PostgreSQL schema. Conditional SQL is a concurrency guard: a losing writer gets 409, never a silent overwrite.

Reads do not round-trip through the domain model. They project the requested view directly.

Adding a module

Declare the boundary

Add the Maven module, application dependency, application-module package, and architecture-test package entry.

Own persistence

Create the domain schema and Flyway location. Never share a migration file or read another module's tables.

Publish the contract

Expose only named api packages and integration events required by other modules.

Ship proof and documentation

Add domain tests, adapter integration tests, controller tests, architecture gates, and the module's shipped.md/backlog.md changes.

On this page