# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Repository overview FMS — a freight-forwarding / logistics management platform (货代物流管理系统). Two-part app: - `fms-api/` — Spring Boot 4.1 (Java 21, Maven) backend. Serves on port **8088** with context-path **`/api`**. SQL Server via raw JDBC. - `fms-vue/` — Vue 3 + Vite 8 (pnpm) frontend. Dev server on port **5180** (strict port), proxies `/api` → `http://127.0.0.1:8088`. Both parts are under active development; `CODEBUDDY.md` at the repo root is the equivalent guidance file for CodeBuddy — keep it in sync when this file changes. Supporting docs at repo root (Chinese — read them before feature work): - `开发规范.md` — **binding** development rules (summarized in "Conventions" below). - `新数据库结构.md` — authoritative `s_module` metadata schema. - `旧数据库结构.md` — legacy schema, reference only; never modify the legacy DB (`G3HY2025`) unless the user says so. - `模块管理实施计划.md`, `数据库迁移计划.md`, `文件组件设计方案.md` — feature/migration/file-component plans. - `docs/refactor/模块管理功能设计.md` — module-management feature design. ## Commands ### Backend (`fms-api/`) ```bash ./mvnw clean package # build jar -> target/fms-api-0.0.1-SNAPSHOT.jar ./mvnw test # all tests (8 test classes under src/test) ./mvnw test -Dtest=ClassName # single test class ./mvnw test -Dtest=ClassName#methodName # single test method ./mvnw spring-boot:run # dev server (or start.cmd, which pins JAVA_HOME/MAVEN_HOME) ``` JWT secret comes from env `FMS_JWT_SECRET` (dev default in `application.yaml`). ### Frontend (`fms-vue/`) ```bash pnpm install pnpm dev # vite dev server on :5180 pnpm build # production build pnpm preview # preview built output pnpm fmt # format with oxfmt pnpm fmt:check # verify formatting ``` There is **no lint or test script** in the frontend. ### Build/test discipline (from `开发规范.md`) Do **not** run builds or start services after finishing a change — only when the user explicitly asks. Running tests to verify changes is allowed (backend `./mvnw test`, frontend `pnpm fmt:check`). When delivering, state whether tests were run and their results, and that no build was executed. ## Backend architecture The defining trait: **almost no business-specific endpoints.** Nearly all data access flows through a small set of generic endpoints in `DataController` (`/data`), implemented by `DataService` / `DataSaveService`. There are no entity/DAO/mapper layers — `utils/DbUtils` does raw JDBC against SQL Server. All endpoints return `utils/ApiResponse` (`{ success, code, message, data }`; `code: 0` = success). Generic endpoints (full path includes the `/api` context-path): - `POST /data/loaddata` — rows from a `view_name` with optional `search_condition` / `order_by` / `search_columns`. - `POST /data/page` — paginated load (`page_no`, `page_size`, `view_name`, `order_by`); returns `{ rows, row_count, total, page_no, page_size }`. - `POST /data/saveobjt` — batch upsert across multiple tables in one transaction (`DataSaveService.save`). Body is a JSON array of `{ table, key_field, inserts[], updates[], deletes[] }`; the whole request rolls back if any table fails. - `GET /data/nextid` — Snowflake ID(s) from `utils/snowflake/idgen/IdGenerator`; `?count=N` returns an array. - `GET /data/nextcode?moduleId=&count=` — business auto-code from a `s_module_auto_code` rule (`DataSaveService.nextCode`); generates unique codes and updates the rule's counter. - `POST /data/describe` — column metadata for a table/view. - `POST /data/loaddatabysql` — runs an arbitrary SQL string. **Avoid**; prefer the structured endpoints. Key rules: - Prefer the generic endpoints for query/paging/save/ID/code generation. Do **not** change their URL, parameters, response shape, or logic, and do **not** add new business-specific endpoints or Service classes, unless you first explain why the generic API cannot do it and get user confirmation. - `bigint` values (e.g. `b_id`) are serialized to the frontend as **strings** via `config/JacksonConfig` (Long → string). - Queries default to no `search_columns` / `searchColumns` unless restricting fields is required and the fields are confirmed to exist. ### Multi-organization database routing Connections are per-organization SQL Server Druid pools; the active org is chosen per request: - `config/dbconfigs/.properties` holds `url`/`username`/`password`/`driver` for one org (e.g. `G3HD.properties`). **These files are git-ignored and must not be committed.** The directory is set by `fms.database.config-dir` in `application.yaml` (default `./config/dbconfigs`). - `database/OrgDatabaseConfigLoader` loads a properties file by org id; `OrgDataSourceManager` caches one `DruidDataSource` per org; `database/OrgRoutingDataSource` picks it per request. - `config/JwtAuthFilter` parses the JWT and sets `database/OrgContext.orgId`, so `DbUtils` targets the right datasource. - Feature work operates on the `FMS` database; the legacy `G3HY2025` DB is read-only reference. ### Auth / JWT - `config/JwtAuthFilter` (skips `/auth/login` and `OPTIONS`) validates `Authorization: Bearer`, checks `service/ActiveSessionRegistry` (single-device enforcement), and sets `OrgContext.orgId`. - `utils/JwtUtils` (jjwt) carries `orgid` / `sessionId` claims; `config/AuthProperties` reads `fms.auth.jwt-secret` / `fms.auth.jwt-expiration`. - `POST /auth/login` (`AuthController` / `AuthService`) takes `{ orgid, userid, password }`; `service/LoginLogService` records login events to `s_login_log`. ## Frontend architecture Vue 3 `