Files
aplp.backend.web/CLAUDE.md
T
2026-08-22 08:29:30 +07:00

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 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.