116 lines
11 KiB
Markdown
116 lines
11 KiB
Markdown
# 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/<ORG_ID>.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 `<script setup>` SFCs, Pinia for state, **antdv-next** components (auto-imported via `@antdv-next/auto-import-resolver` in `vite.config.js` — do not manually import antdv-next components). There is **no vue-i18n**; i18n is custom and DB-driven from the `b_i18n` table.
|
|
|
|
### API service layer
|
|
`src/services/api.js` (on the axios wrapper `src/services/http.js`, baseURL `/api`) exposes `loginApi`, `loadDataApi`, `pageDataApi`, `saveObjectApi`, `nextIdApi`, `nextCodeApi`, `describeApi`, `loadDataBySqlApi`. Feature code should call these (or wrap them), never introduce new backend URLs from the frontend.
|
|
|
|
### Routing & permissions
|
|
- `src/router/pageComponents.js` is the explicit hand-written page component whitelist; `routes.js` registers only keys from that registry.
|
|
- `AppSidebar` reads `v_s_function_node`. The router guard authorizes the matching FunctionNode route.
|
|
- `stores/permissions.js` reads the effective FunctionNode, PageNode and Action permission views. Roles provide primary grants; direct user grants are additive. Super access comes from `b_role.b_is_super`, never from an account-name bypass.
|
|
- Permission enforcement is currently frontend-only; backend data-scope and write interception remain reserved.
|
|
- Other stores: `stores/auth.js` (token/user, persisted), `stores/app.js` (locale default `zh-CN`, sidebar collapse, visited tabs).
|
|
|
|
### Shared components & utils
|
|
- `components/fms-table/FmsTable.vue` — the project table; **all tables must use it** (not a hand-rolled table). Cell renderers live in `components/fms-table/utils/`.
|
|
- `components/fms-module-list/` — generic data-module list page (`FmsModuleListPage`, `FmsModuleTable`, `FmsQueryControl`, `FmsQueryToolbar`) built from module config.
|
|
- `components/FmsTree.vue`, `FmsSelect.vue`, `FmsAutoComplete.vue`, `FmsMemoInput.vue`, `FmsLoadingOverlay.vue`.
|
|
- `utils/dataChanges.js` — clone/diff/merge helpers for `saveobjt` (e.g. `diffRows`, `allocateTemporaryIds`, `remapForeignKeys`, `tableChange`, `hasChanges`); `utils/tempId.js`, `utils/tree.js`, `utils/i18n.js`.
|
|
|
|
### Module-management feature
|
|
`src/views/module-management/index.vue` only coordinates three maintenance areas: FunctionNode structure, PageNode composition, and Module resources. State and persistence live in the three `composables/`; independent panels own editing UI. Resource configuration is saved through one `/data/saveobjt` transaction.
|
|
|
|
## Database & migrations
|
|
|
|
- SQL Server; the migration scripts are under `fms-api/config/migrations/`. Module cutover uses `033_create_module_structure.sql`, then `034_module_runtime_views.sql`, then the read-only `verify_module_architecture.sql`. The cutover is one-time and intentionally removes the old metadata model.
|
|
- `config/migrations/tools/` has Java helpers to generate/run/verify business-schema migrations; `数据库迁移计划.md` documents the plan and 2026-07-29 execution results.
|
|
- Core architecture is `s_module` plus type tables, `s_function_node`, `s_page_node`, `s_module_profile`, capability tables, and explicit role/user grant tables. IDs and technical codes are immutable. Follow `新数据库结构.md` exactly.
|
|
|
|
## Conventions (from `开发规范.md`)
|
|
|
|
- **Write like the existing code**: mirror the style of the closest existing example (API calls, error handling, state). Prefer `if/else` over ternary/`?.` chains and `for` over `reduce`; avoid gratuitous syntax sugar and pointless abstraction. Readability beats brevity.
|
|
- **Performance is the top constraint**, above code convenience and component consistency:
|
|
- Table rows render only lightweight native elements (`h("button")`, `<input>`); heavy components (`Dropdown`, `Select`, `Input`, `Modal`) mount **on demand** for the current row and unmount on interaction end — at most one instance at a time. See the on-demand `MoreActions` pattern in `module-management/components/ModulePowersPanel.vue`; the table "⋯" more-actions button must follow it.
|
|
- Batch writes go through a single `/data/saveobjt`; no N+1 queries, no remote calls / repeated IO in loops; paginate large data; no `SELECT *`; don't wrap indexed columns in functions or implicitly convert types.
|
|
- **No `placeholder` on form inputs**; `label` holds only the field name. Use `FmsTree` without `root-title` (the component owns root titles).
|
|
- CSS in `<style scoped lang="scss">`; no `@media`/responsive breakpoints (desktop only). Prefer antdv-next component props/design tokens over custom styles; don't override default component styles unless required and then keep it minimal.
|
|
- **Scope**: change only what the current task needs — no unrelated refactors or formatting. Confirm impact before touching generic endpoints, shared components, or global styles. Preserve existing functionality and uncommitted user work.
|
|
- Boolean columns are `int` `0/1`; `b_xh` is display order (smaller = first). Table/column names must be backend-validated identifiers — never concatenated into SQL.
|