4.1 KiB
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
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/<module>/:
<module>/
├── 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
ErrorCodeenum (incommon/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
DomainExceptionand get mapped to HTTP status in the API layer, not thrown as raw HTTP errors from domain/application code.