- This guide is for
jwt-demo-reactive(Spring Boot 4, Java 25, reactive stack). - Existing AI/dev instructions discovered via glob:
README.md(no project-localAGENT.md/AGENTS.md/.cursorrulesetc. were found in this module).
- Entry points are reactive REST controllers in
src/main/java/lt/satsyuk/controllerreturningMono<...>and wrapping payloads intoAppResponse(AuthController,ClientController,RequestController). - Business logic lives in services under
src/main/java/lt/satsyuk/service; controllers should stay thin and delegate orchestration. - Persistence is R2DBC-first via Spring Data repositories (
ClientRepository,AccountRepository,RequestRepository) and SQL migrations insrc/main/resources/db/migration. - Async client creation is a two-step flow:
POST /api/clients-> enqueue request (RequestService.submitClientCreateRequest) -> scheduled worker claims/processes rows (RequestService.processPendingRequests). - Security boundary is WebFlux resource server with opaque token introspection + custom role conversion (
SecurityConfig,KeycloakReactiveOpaqueTokenIntrospector,KeycloakOpaqueRoleConverter).
- Standard response envelope is
AppResponse<T>(code=0for success; domain error codes otherwise) insrc/main/java/lt/satsyuk/dto/AppResponse.java. - Request worker state machine is persisted in DB:
PENDING -> PROCESSING -> COMPLETED|FAILED(RequestStatus,RequestRepository,RequestService). - Multi-instance safety relies on SQL claiming with
FOR UPDATE SKIP LOCKEDinRequestRepository.claimPendingClientCreateBatch. - Stale
PROCESSINGreclaim is explicit (RequestRepository.reclaimStaleClientCreateRequests) and indexed byV2__add_request_reclaim_index.sql.
- Public endpoints are limited to
/api/auth/**, Swagger, and/actuator/prometheus; everything else requires auth (SecurityConfig.securityWebFilterChain). - DPoP is enforced by
DpopAuthenticationWebFilterwhen DPoP scheme/proof or token binding (cnf.jkt) is present. - Rate limiting is rule-driven from
app.rate-limit.rules[*]and executed in rule order (RateLimitingWebFilter.sortedRules+RateLimitProperties.Rule.order). - Client identity for rate-limit keys comes from token attributes
azp/client_idviaSecurityService.
- Build quickly:
mvn clean compile -DskipTests(documented inREADME.md). - Unit tests:
mvn test(maven-surefire-pluginincludes*Test*, excludes*IT*inpom.xml). - Integration tests:
mvn verify(maven-failsafe-pluginruns*IT*; Testcontainers-based infra inAbstractIntegrationTest). - Coverage is split and merged (
jacoco-ut.exec,jacoco-it.exec, merged report intarget/site/jacoco-merged) configured inpom.xml.
- Integration base class
AbstractIntegrationTeststarts PostgreSQL Testcontainer and applies Flyway before each test setup. - Keycloak-backed ITs extend
KeycloakIntegrationTest(real Keycloak container + dynamic properties). - Negative/upstream auth scenarios extend
WireMockIntegrationTest(stubbed token/introspection/logout endpoints). - Async behavior assertions use Awaitility polling (
RequestIntegrationIT,RequestWorkerMultiInstanceIT).
- Keep APIs reactive end-to-end (
Mono/Flux), avoid blocking in production paths; tests may use.block()for setup/assertions. - Use localized messages through
MessageService+messages*.properties; avoid hardcoding user-facing error text in handlers. - For validation/error shaping, prefer
GlobalExceptionHandler+ typed domain exceptions (*NotFoundException,PhoneAlreadyExistsException, etc.). - For new async request types, update all three layers together: DB constraints/migration (
request.typecheck), worker claim/process logic, and integration tests.
- Base branch: create work branches from
mainunless task explicitly says otherwise. - Branch naming: use
feature/,bugfix/,hotfix/,chore/,docs/,test/(for example:docs/update-reactive-api-docs). - Commit format: use Conventional Commits,
<type>(<scope>): <short description>. - Commit style: prefer small atomic commits grouped by one logical change; avoid mixing refactor + feature + docs in one commit.
- Staging discipline: stage only relevant files (
git add <files>), do not use broad staging without checkinggit status. - Safety: never commit
.env, secrets, tokens, or generated runtime artifacts fromtarget/. - Validation before commit:
- docs-only change: at minimum recheck modified files +
git status - code change: run
mvn test - security/infra/async-worker critical changes: run
mvn verify
- docs-only change: at minimum recheck modified files +
- Sync before push: prefer
git pull --rebaseon current branch, resolve conflicts locally, then push. - History policy: do not force-push and do not rewrite shared history unless explicitly requested.
- If user asks to "commit" without extra details, apply these defaults and proceed with a single well-scoped commit.