# CODEBUDDY.md This file provides guidance to CodeBuddy Code when working with code in this repository. ## Repository layout This is a two-part application (FMS — 模块/数据管理平台): - `fms-api/` — Spring Boot 4.1 (Java 21, Maven) backend. Serves on port **8088** with context-path **`/api`**. - `fms-vue/` — Vue 3 + Vite 8 (pnpm) frontend. Dev server on port **5180**, proxies `/api` → `http://127.0.0.1:8088`. Supporting docs in the repo root (Chinese): - `开发规范.md` — binding development rules (read it; summarized below). - `新数据库结构.md` — the module-management table design (authoritative schema). - `旧数据库结构.md` — legacy schema, kept for reference only. - `模块管理实施计划.md` — phased plan for the module-management feature. - `fms-api/config/migrations/001_module_management.sql` — the only migration script. ## Commands ### Backend (`fms-api/`) ```bash ./mvnw clean package # build jar -> target/fms-api-0.0.1-SNAPSHOT.jar ./mvnw test # run all tests (8 test classes under src/test) ./mvnw test -Dtest=ClassName # run a single test class ./mvnw test -Dtest=ClassName#methodName # run a single test method ./mvnw spring-boot:run # run the dev server (or use start.cmd) java -jar target/fms-api-0.0.1-SNAPSHOT.jar # run built jar ``` JWT secret is read from env `FMS_JWT_SECRET` (defaults to a dev value 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 # check formatting ``` There is **no lint or test script** in the frontend. ### Build/test discipline (from `开发规范.md`) Do **not** run build/test/start yourself after finishing a change. Only build, test, or start services when the user explicitly asks. When delivering, state that build/test were not executed. ## Backend architecture The defining characteristic of this backend is that it has **almost no business-specific endpoints**. Almost all data access goes through a small set of generic endpoints in `DataController`, implemented by `DataService` / `DataSaveService`. There are no entity/DAO/mapper layers — `utils/DbUtils` does raw JDBC against SQL Server. Generic data endpoints (full path includes the `/api` context-path): - `POST /api/data/loaddata` — load rows from a `view_name` with optional search/order (`DataService.loadData`). - `POST /api/data/page` — paginated load (`page_no`, `page_size`, `view_name`, `order_by`). - `POST /api/data/saveobjt` — batch upsert across multiple tables in one transaction (`DataSaveService.save`). Request body is a JSON array of `{ table, key_field, inserts[], updates[], deletes[] }`; the whole request rolls back if any table fails. - `GET /api/data/nextid` — Snowflake ID from `utils/snowflake/IdGenerator`. - `POST /api/data/loaddatabysql` — runs an arbitrary SQL string. **Avoid this**; it exists but new feature work should prefer the structured endpoints. - `POST /api/auth/login` — `AuthController` / `AuthService`. Key rules when working on the backend: - Prefer the generic endpoints for query/paging/save/ID-generation. Do **not** modify their URL, parameters, response shape, or logic, and do **not** add new business-specific endpoints, unless you first explain why the generic API cannot do it and get user confirmation. - `b_id` values that are `bigint` snowflake IDs must be serialized to the frontend as **strings**. ### Multi-organization database routing Connections are per-organization SQL Server pools (Druid). The active org is selected at request time: - `config/dbconfigs/.properties` holds `url`/`username`/`password`/`driver` for one org (e.g. `g3hd.properties` for org `G3HD`). **These files are git-ignored** and must not be committed. The `config-dir` 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. - `config/JwtAuthFilter` parses the JWT, then `database/OrgContext` holds the current `orgId` so `DbUtils` targets the right datasource (`OrgRoutingDataSource`). - New features operate on the `g3hd.properties` database (`fms`); do not touch the legacy database. ### Auth / JWT - `config/JwtAuthFilter` (skips `/auth/login`) validates `Authorization: Bearer`, checks `ActiveSessionRegistry` (single-device enforcement), and sets `OrgContext.orgId`. - `utils/JwtUtils` (jjwt) puts `orgid` / `sessionId` claims. `config/AuthProperties` reads `fms.auth.jwt-secret` / `fms.auth.jwt-expiration`. - Login response returns `id`, `account`, `name`; the JWT session identifier stays the account. ## Frontend architecture Vue 3 `