소스 검색

# feat: 状态常量添加注释并在AGENTS.md补充常量使用约定

yangyi 2 달 전
부모
커밋
196392ba5f

+ 35 - 0
AGENTS.md

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

+ 6 - 0
src/main/java/space/anyi/serve/entity/contest/Contest.java

@@ -10,11 +10,17 @@ import java.time.LocalDateTime;
 @TableName("dev.contest")
 public class Contest {
 
+    /** 比赛类型:公开 */
     public static final String TYPE_PUBLIC = "public";
+    /** 比赛类型:私有 */
     public static final String TYPE_PRIVATE = "private";
+    /** 比赛类型:密码访问 */
     public static final String TYPE_PASSWORD = "password";
+    /** 比赛状态:未开始 */
     public static final String STATUS_PENDING = "pending";
+    /** 比赛状态:进行中 */
     public static final String STATUS_RUNNING = "running";
+    /** 比赛状态:已结束 */
     public static final String STATUS_ENDED = "ended";
 
     @TableId(type = IdType.AUTO)

+ 8 - 0
src/main/java/space/anyi/serve/entity/contest/Submission.java

@@ -10,13 +10,21 @@ import java.time.LocalDateTime;
 @TableName("dev.submission")
 public class Submission {
 
+    /** 判题状态:提交成功 */
     public static final String STATUS_SUBMITTED = "SUBMITTED";
+    /** 判题状态:判题中 */
     public static final String STATUS_JUDGING = "JUDGING";
+    /** 判题状态:全部测试用例通过 */
     public static final String STATUS_AC = "AC";
+    /** 判题状态:输出与预期不符 */
     public static final String STATUS_WA = "WA";
+    /** 判题状态:运行时间超限 */
     public static final String STATUS_TLE = "TLE";
+    /** 判题状态:内存使用超限 */
     public static final String STATUS_MLE = "MLE";
+    /** 判题状态:运行时错误 */
     public static final String STATUS_RE = "RE";
+    /** 判题状态:编译失败 */
     public static final String STATUS_CE = "CE";
 
     @TableId(type = IdType.AUTO)

+ 5 - 0
src/main/java/space/anyi/serve/entity/problem/Problem.java

@@ -10,10 +10,15 @@ import java.time.LocalDateTime;
 @TableName("dev.problem")
 public class Problem {
 
+    /** 是否公开:公开 */
     public static final Integer IS_PUBLIC_YES = 1;
+    /** 是否公开:未公开 */
     public static final Integer IS_PUBLIC_NO = 0;
+    /** 难度:简单 */
     public static final String DIFFICULTY_EASY = "easy";
+    /** 难度:中等 */
     public static final String DIFFICULTY_MEDIUM = "medium";
+    /** 难度:困难 */
     public static final String DIFFICULTY_HARD = "hard";
 
     @TableId(type = IdType.AUTO)

+ 5 - 0
src/main/java/space/anyi/serve/entity/user/User.java

@@ -18,10 +18,15 @@ import java.time.LocalDateTime;
 //指定表名
 @TableName("dev.user")
 public class User {
+    /** 角色:普通用户 */
     public static final String ROLE_USER = "user";
+    /** 角色:教练 */
     public static final String ROLE_COACH = "coach";
+    /** 角色:管理员 */
     public static final String ROLE_ADMIN = "admin";
+    /** 启用状态:启用 */
     public static final Integer ENABLE_ON = 1;
+    /** 启用状态:禁用 */
     public static final Integer ENABLE_OFF = 0;
 
     //声明主键