# 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 -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` 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 `. 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`. ### 本地代码沙箱(`space.anyi.codesandbox`) - 沙箱在独立包 `space.anyi.codesandbox`(与 `space.anyi.serve` 平级,不在 serve 包内)。实现未接入 Spring Bean,直接 `new JVMNativeCodeSandBox()` 调用;`CodeSandBox` 是接口,控制器/服务依赖抽象。 - `CodeContext.maxMemory` 单位为 **KB**(与 `Submission.memoryUsedKb` 一致),拼接为 `-Xmxk` 传给子 JVM;`maxTime` 单位为毫秒。不要传字节值(会把 256MB 变成 256GB)。 - 输出判定不是严格 equals:按行归一化,忽略行尾空白(空格/`\t`/`\r`)与末尾空行(`outputMatches`)。 - 并发上限 `MAX_CONCURRENT`(默认 10),超限 `tryAcquire(5s)` 失败返回 `SE`「系统繁忙」。超时/异常路径由 `destroyForcibly()` 杀子进程,临时目录 `code/` 在 `finally` 中删除,不得在早退路径遗漏。 - 运行时 `javac`/`java` 取 `JAVA_HOME`(回退 `java.home`),需指向含 javac/java 的 **JDK**;环境为 JDK 17 时测试可运行(Gradle toolchain 为 17)。 - `JVMNativeCodeSandBoxTest` 需真实 JDK/JVM 子进程,不依赖数据库。 ## 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).