Files
workspace/code/fms/CLAUDE.md
T
2026-08-03 22:54:03 +08:00

11 KiB

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/)

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

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.