# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project APLP Backend — backend for **aplp-web** (Adaptive Personal Learning Platform, learner-facing app). Java 21, Spring Boot 3.5 (parent pin: `spring-boot-starter-parent` 4.1.0), Maven, modular monolith with Clean Architecture layers, DDD-oriented, vertical-slice per business module. ## Commands ```bash docker compose up -d db # start Postgres (see docker-compose.yml for port) ./mvnw spring-boot:run # run app, dev profile, port 8080 ./mvnw test # run tests (H2, Postgres-compatible mode) ./mvnw test -Dtest=AuthFlowIntegrationTest # run a single test class ./mvnw package # build jar curl http://localhost:8080/actuator/health # liveness/readiness check ``` No lint/format command is configured in `pom.xml`. ## Architecture Request flow: `Controller → Application/Service (use case) → Domain → Persistence → DB`. Dependencies point inward only (API → Application → Domain); persistence implements repository interfaces defined in domain. Each business module is a vertical slice under `src/main/java/aplp/backend/web//`: ``` / ├── api/controller/ # REST controllers ├── application/ │ ├── dtos/ # request/response DTOs │ ├── mappers/ # manual DTO <-> domain mapping (no MapStruct despite it being on the classpath) │ └── services/ # use case orchestration, @Transactional ├── domain/ │ ├── entities/ # domain model — in practice these ARE the JPA entities (@Entity, jakarta.persistence.* live here directly, not layered out into a separate persistence model) │ ├── exceptions/ # DomainException-style, mapped to HTTP in GlobalExceptionHandler │ └── repositories/ # repository interfaces (impl lives in infrastructure/persistence) └── infrastructure/persistence/ # Spring Data JPA repos + Repository interface implementations ``` Note: `docs/ARCHITECTURE.md`, `docs/CONVENTIONS.md`, `docs/MODULES.md` describe the intended design (package `com.aplp.backend`, a `persistence` layer with entities split from domain model). The actual code uses base package `aplp.backend.web` and puts JPA entities directly in `domain/entities`, with only repository *implementations* in `infrastructure/persistence`. Follow the existing code pattern (`identity`, `learner` modules), not the docs, when in doubt — the docs are aspirational/Phase 0 drafts and known to be stale on this point. Modules present today: `common` (shared infra — no business logic), `identity` (auth: register/login/refresh/logout, JWT), `learner` (learner profile). Planned modules (`content`, `learning`, `assessment`, `progress`, `adaptive`, `recommendation`, `assistance`, `subscription`, `notification`) are documented in `docs/MODULES.md` but not yet implemented. Modules must only talk to each other through public interfaces — no reaching into another module's internals. `common/` holds: `GlobalExceptionHandler` (exception → HTTP mapping), JWT (`JwtTokenProvider`, `JwtAuthenticationFilter`, `SecurityConfig`), `RequestIdFilter` (`X-Request-Id`), CORS config. Depends on an external artifact `aplp.backend:core` (separate Maven module, not in this repo tree). ## Database PostgreSQL in dev/prod (docker-compose), H2 in Postgres-compatible mode for tests (`src/test/resources/application-test.yml`). Flyway migrations in `src/main/resources/db/migration` (`ddl-auto=validate` — entities must match migrations exactly, migrations are the source of truth). Write migrations portable across Postgres and H2. ## Conventions worth knowing - Error responses go through a global `ErrorCode` enum (in `common/api`) + `GlobalExceptionHandler`; add new codes there for new failure cases. - DTO mapping is manual (static mapper methods), not MapStruct, despite mapstruct being a dependency. - Domain exceptions extend the project's `DomainException` and get mapped to HTTP status in the API layer, not thrown as raw HTTP errors from domain/application code.