|
|
@@ -0,0 +1,35 @@
|
|
|
+# AGENTS.md
|
|
|
+
|
|
|
+Spring Boot 3.5 / Java 17 OJ backend template. Root project is `serve` (see `settings.gradle.kts`), Java package `space.anyi.serve`. Stack and API docs are in `README.md`; this file only covers non-obvious gotchas.
|
|
|
+
|
|
|
+## Commands
|
|
|
+
|
|
|
+- Run: `./gradlew bootRun` (serves on :8080)
|
|
|
+- Test: `./gradlew test` (JUnit Platform). No lint/format/typecheck or CI config exists.
|
|
|
+
|
|
|
+## Runtime prerequisites
|
|
|
+
|
|
|
+- Startup requires env vars `databaseHost`, `databaseUsername`, `databasePassword` — missing any makes the app fail on first DB access. No local dev defaults are provided.
|
|
|
+- DB is named `oj`, all tables live in the `dev` schema. Initialize via `psql -U <user> -f sql/postgersql.sql` (note the misspelled filename `postgersql.sql`).
|
|
|
+- The `contextLoads` test spins up the full context and needs a live PostgreSQL; it fails without one.
|
|
|
+
|
|
|
+## Architecture & conventions
|
|
|
+
|
|
|
+- Every controller returns the `Response<T>` wrapper (`Response.ok` / `Response.error`). Validation failures map to HTTP 400; other uncaught exceptions return HTTP 200 with an `error` body (see `GlobalExceptionHandler`).
|
|
|
+- Auth is stateless JWT in `Authorization: Bearer <token>`. Roles are stored as plain `user`/`coach`/`admin` in the DB, but method-level auth requires the `ROLE_` prefix — `JwtAuthenticationFilter` adds it, so write `@PreAuthorize("hasRole('ROLE_admin')")`. Only `/auth/login`, `/auth/register`, and swagger paths are public.
|
|
|
+- No Lombok. Entities/DTOs use hand-written getters/setters; controllers use `@Resource` injection, services use constructor injection.
|
|
|
+- **Status/enum values are defined as `public static final` constants in the entity class they belong to** (e.g. `User.ROLE_ADMIN`, `Contest.STATUS_RUNNING`, `Submission.STATUS_AC`, `Problem.DIFFICULTY_EASY`). Use those constants instead of hardcoded string/number literals everywhere in Java code. Exception: SpEL annotation strings (`@PreAuthorize("hasRole('ROLE_admin')")`), the `"ROLE_" + role` authority-prefix concatenation, Swagger `@Schema`/`@Parameter` description text, and MyBatis XML (which cannot reference Java constants, e.g. `status = 'AC'` in `SubmissionMapper.xml`) keep literals — when adding a literal to a mapper XML, mirror the matching entity constant and keep the value in sync.
|
|
|
+- MyBatis-Plus has a global logic-delete field (`deleteFlag`), so deletes are logical. Entities target schema-qualified tables via `@TableName("dev.user")`. Mapper XML lives in `src/main/resources/mapper/`.
|
|
|
+- JWT secret is a hardcoded base64 key in `JwtTokenProvider`, 24h expiry, using the jjwt 0.12 API (`verifyWith`/`parseSignedClaims`).
|
|
|
+- Swagger UI: `/swagger-ui/index.html`.
|
|
|
+
|
|
|
+## Coding style
|
|
|
+
|
|
|
+- Controller methods take concrete DTOs for request bodies/params (e.g. `UserDto`, `LoginDto`) and return concrete VOs for responses (e.g. `UserVo`), never raw `User` entities or generic maps.
|
|
|
+- OpenAPI annotations are mandatory on APIs and models: `@Tag`/`@Operation` on controllers and methods, and `@Schema` on both request DTOs and response VOs (class-level and per-field). Follow the existing DTO/VO examples.
|
|
|
+- Depend on abstractions, not implementations: controllers inject the service interface (`UserService`), implementations live in `service/impl/` (`UserServiceImpl`). Don't let controllers reference impl classes directly.
|
|
|
+
|
|
|
+## Workflow
|
|
|
+
|
|
|
+- Active branch is `oj`. Commit messages use the `# feat: ...` / `# sql: ...` prefix style from `git log`.
|
|
|
+- Commit after every completed feature point (each feature is a separate version-control checkpoint).
|