Microservices back-end for managing projects and their tasks, built on:
- Domain-Driven Design.
- Event-Driven Architecture.
- Hexagonal Architecture.
- Choreography and the Saga pattern for distributed transactions.
- Outbox and inbox patterns for reliable messaging.
- SOLID.
The front-end is FastDo.
- Spring Boot.
- Kotlin.
- Gradle Kotlin DSL (a separate build for each service, joined as a composite build).
- PostgreSQL (a separate database for each service).
- Apache Kafka (KRaft).
- Apache Avro with Schema Registry.
- Redis (API gateway sessions).
- Garage (S3-compatible storage for files).
- JUnit.
- Testcontainers.
- Spring Security.
- Spring Data JPA.
- Spring Cloud Gateway.
- OpenAPI (Swagger).
- Identity provider: Keycloak (realm
veds) owns every page that touches a credential: sign-up, sign-in, email verification, password reset, two-factor authentication and acceptance of the terms of use. The application never sees a password. - Pattern: BFF with Spring Security's OAuth2 client. The API gateway signs users in with the authorization code flow
and PKCE and is the only component that holds tokens; the browser holds only the
VEDS_SESSIONcookie (HttpOnly,SameSite=Strict,Securein production). No token reaches JavaScript. - Session store: Redis (Spring Session,
veds:sessionnamespace), every attribute encrypted by the gateway. - JWT: on the way to a service the gateway exchanges the person's token at Keycloak (token exchange, RFC 8693) for
one whose only audience is that service, and every service is a stateless OAuth2 resource server verifying signature,
issuer, expiry and its own audience (
veds-<name>-service). A token leaked from one service opens no other. - State: every service is stateless: each request is authorized by the JWT alone. The only state is the gateway's session, and it lives in Redis, so gateway instances are interchangeable too.
- Token lifecycle: access tokens live five minutes; every refresh returns a new refresh token and invalidates the old one, and concurrent requests of one session share a single refresh, across replicas too (a lock in Redis). Signing out revokes the refresh token at Keycloak.
- Authorization: permissions are granted to roles, never to people; iam-service announces what every role grants through Kafka and each service decides from its local projection.
- Accounts: iam-service creates the account in PostgreSQL at the first sign-in.
- The application has an exception handling mechanism (RFC 9457 problem details with message codes).
- The application has a logging mechanism.
- The application has separate environments for local and prod.
- The application has a dedicated configuration file.
- The application has RBAC with permissions per role, announced to every service through Kafka.
- The application has Flyway database migration mechanism.
- The application has optimistic locking with ETag and If-Match headers.
- The application has translations (ICU MessageFormat) owned by the service that declares them.
- And many other features that can be found in the application code.
- Docker for development environment.
- Detekt for static code analysis.
- ktlint for code formatting.
- ArchUnit for executable architecture rules.
- Dokka for code documentation.
- OpenTofu for Kafka topic provisioning.
Start with Development Setup, then Architecture.
- Development Setup – running the whole system locally.
- Testing – the two test tiers and the architecture check.
- Architecture – components and design principles.
- Hexagonal Layering – the dependency rule and how it is enforced.
- Shared Modules – what each shared library is responsible for.
- Service Dependencies – what each service needs to build and to run.
- CQRS – where command/query separation is applied, and why.
- Eventual Consistency – outbox, inbox and sagas.
- Event Catalogue – every topic, its owner and its consumers.
- Concurrency Control – optimistic locking, ETags, saga and outbox concurrency.
- Keycloak Configuration – realm setup, authentication flow, role management.
- Authorization – permissions, roles and how services check them.
- Files – pre-signed uploads, a private bucket and the two sweeps.
- Translations – key ownership and ICU.
Every service and shared module has its own README with the decisions behind it, for example api-gateway, iam-service and shared-messaging-kafka.
