# AGENTS.md — shanxia2.0 (山峡化工) Two-package monorepo: Python backend + Vue 3 admin frontend. Named "sanqiang" internally. ## Repository Layout ``` backend/ FastAPI backend (Python 3.9, venv) web-admin/ Vue 3 admin panel (pnpm, Vite 7, Element Plus, Tailwind CSS 4) docs/ UI specs, SQL schemas, requirements docs openspec/ OpenSpec: `config.yaml`; active changes under `openspec/changes/*/` .cursorrules Detailed UI conventions and constraints (Chinese) ``` ## Ecosystem (multi-system) Normative detail: `openspec/changes/zkxw-engineering-standards/specs/ecosystem-landscape/spec.md`. | System | DDL snapshot (`docs/sql/`) | Code location | |--------|---------------------------|---------------| | 山峡一体化门户(本仓库) | `shanxia2.0.sql` | `backend/`, `web-admin/`, `miniprogram/` | | 山峡 CRM | `sx.sql` | Sibling repo `shanxia/crm/backend/` (Java), `shanxia/crm/web/` (Vue 3) | | 地磅系统 | `dibang.sql` | Separate system (not this repo's backend) | Do not implement CRM or weighbridge features in `shanxia2.0/backend` unless an OpenSpec change explicitly covers integration. ## OpenSpec engineering standards Full specs: `openspec/changes/zkxw-engineering-standards/specs/*/spec.md`. Below are the key SHALL items every coding session MUST follow. ### UI Conventions (web-admin + miniprogram) - **Visual authority**: `web-admin` SHALL follow `docs/web-admin-ui-spec-fresh-mint.md` (Fresh Mint palette, `--primary #10b981`). `miniprogram` SHALL follow `docs/miniprogram-ui-spec-sanqiang.md` (三墙 palette, brand green `#0a9f6d`). - **No cross-app color mixing**: `web-admin` SHALL NOT use `#0a9f6d` as primary; `miniprogram` SHALL NOT use `#10b981` as primary. - **Tree path display**: Dropdown/tree nodes show **node name only**; input fields, table columns, exports, and view dialogs SHALL show **full ancestor path**. Separator: ` / ` (space-slash-space). See `web-admin/src/utils/tree-path.ts`. - **Dialog forms**: `label-position="top"`. No backdrop blur (`backdrop-filter: none`). Use `.dialog-form-layout` with `max-height: calc(100vh - 100px)`, only body scrolls. - **Dialog grid**: Default 2-column (`.form-grid-2`). Max 5 columns. Full-width fields use `.form-col-span-2` (`grid-column: 1 / -1`). Narrow viewport SHALL fallback to fewer columns. - **List panel heading**: `panel-top` → `h2.title-bar-heading` SHALL show primary-color vertical bar via `::before`. Ambiguous titles (e.g. "租户" containing "户") SHALL be registered in `App.vue` `panelTitleBarTextRules`. - **Miniprogram media**: Thumbnails 1:1 `aspectFill`; carousel 4:3 `aspectFill`; detail images `widthFix`. Min tap target 44×44px. - **Sidebar menu icons**: First-level menu items SHALL show icons before the name; second-level and deeper items SHALL NOT show icons (text only). Implemented via `level === 0` check in `SidebarSubmenu.vue`. - **Tab bar (WorkTab) icons**: Tab bar tabs SHALL NOT show icons — only text titles. `meta.icon` is for sidebar only. - **Form field annotations**: Field hints (e.g. "数值越小越靠前") SHALL appear as small text after the label via ``, NOT beside the input control. Style class: `.form-label-tip` (12px, `--mint-text-muted`). - **Attachment upload card layout** (`web-admin`): Upload trigger SHALL be a card (140×96px, dashed border `#a7f3d0`) inline as the first item in the same flex row as uploaded attachment cards; select file → immediate upload via `fetchUploadAttachment`; preview/download/delete on cards; hint below the row. Authority: `ProtocolFormDialog.vue` «协议附件». See `openspec/.../ui-conventions/spec.md` §「附件上传卡片化布局」. - **Miniprogram photo evidence upload** (`miniprogram`, baseline): Photo/album images only — `uni.chooseImage` + `uni.uploadFile` (`name: file`, `formData.folder`, Bearer header) → collect `data.url` → business API submits `imageUrls`. SHALL NOT use Web `el-upload`/`FormData`+`request`, Base64-in-JSON, or document pickers (`chooseMessageFile`). Upload path SHALL be in `API_ENCRYPT_EXCLUDE_PATHS`. Authority: `openspec/.../ui-conventions` §「小程序拍照凭证上传(基线)」+ `api-conventions` §「小程序拍照凭证上传接口」; reference pattern from `sqxp-wx` delivery/supplier evidence upload. - **Button icons**: All `web-admin` `el-button` with visible text labels SHALL include a leading `` from `@element-plus/icons-vue` (explicit import). See `openspec/.../ui-conventions/spec.md` §「按钮须携带图标」. - **Sort fields (sort_order/orderNum)**: web-admin 列表、新增弹窗、编辑弹窗中默认不展示排序字段。后续根据功能需要自行添加。 - **Status/conclusion/type fields as Tags**: All status, conclusion, and type fields in table columns and view dialogs SHALL render as `` with semantic colors (**dark background + white text** globally via `el-ui.scss`). Tables: use `` in column templates. SystemViewDialog: use `tagType` property on `ViewField`. Semantic colors: `success`/`primary`=`#059669`, `warning`=`#d97706`, `danger`=`#dc2626` (dark bg + white text); `info`=transparent bg + standard text `#1e293b` (avoid Element default `#909399`). SHALL NOT use plain text, custom ``, or light-fill tags for non-info types. See `openspec/.../ui-conventions/spec.md` "状态、结论与类型字段使用 Tag 标签展示". - **List primary column view link**: List pages with read-only view dialogs SHALL use `` on the primary name/no column to open the view handler; SHALL NOT duplicate a「查看」button in the operation column when the link exists. Keep `@row-dblclick`. For standard CRUD lists (edit/delete only), SHALL NOT have an operation column—place「编辑」「删除」in the list toolbar (edit requires exactly one selected row; delete supports batch) and in `SystemViewDialog` `#hero-actions`. Reference: `crm/product/index.vue`, `system/user/index.vue`. See `openspec/.../ui-conventions/spec.md` §「列表主标识列链接查看与编辑删除外置」. - **Template pages** — new pages SHALL match these exactly: - Standard list: `src/views/system/unit/index.vue` - Complex list: `src/views/system/order/index.vue` - Product list + view dialog: `src/views/system/product/index.vue` - Tree master data: `src/views/system/category/index.vue` - User CRUD: `src/views/system/user/index.vue` - **UI pattern index** — before implementing a new page, developers SHALL select a pattern code (P01–P27) per `docs/web-admin-ui-pattern-index.md` and OpenSpec `ui-conventions` §「界面模式索引与参考页选型」; PRs SHALL cite pattern code and reference page path. ### API Conventions (backend) - **Cell-storage sample cross-table key**: Matching `biz_protocol_sample` to downstream rows (sample reception, QC work orders, etc.) SHALL use `tenant_no` + `sample_code` only—not `collection_protocol_id` or `protocol_sample_id` (protocol may change; sample code does not). See `openspec/changes/zkxw-engineering-standards/specs/api-conventions/spec.md` §「细胞存储样本跨表关联键」. - **Tenant isolation**: All business data queries SHALL filter by current user's `tenant_no`. All write/update endpoints SHALL set `tenant_no` to the current user's tenant. MUST NOT trust client-submitted tenant overrides (unless multi-tenant admin API with security review). - **Data permission**: All business queries SHALL apply data scope filtering based on the union of all roles assigned to the current user (menu + data permissions both use union semantics). - **Default sort**: Lists SHALL sort by `create_time DESC` when no custom sort is specified. - **Route registration**: New route modules SHALL be registered in `app/api/__init__.py` AND `app/main.py`. SHALL NOT bypass auth/crypto/audit middleware. ### Database Conventions - **Engine**: MySQL 5.7, charset utf8mb4. - **Public fields** (every business table SHALL include these after business fields): `id` VARCHAR(64) UUID, `tenant_no`, `order_num`, `remark`, `create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag` (default `0`). - **Field order**: `id` → business fields → public fields (`tenant_no` through `del_flag`). - **Soft delete**: SHALL NOT physically delete business data. Delete = set `del_flag=1`. Queries SHALL exclude `del_flag=1` by default. - **Primary key**: `id` SHALL be `VARCHAR(64) NOT NULL`, UUID value. ### Architecture Conventions - **Monorepo structure**: Python backend (`backend/`) + Vue 3 web-admin (`web-admin/`) + uni-app miniprogram (`miniprogram/`). Shared backend and tenant model. - **File attachments**: SHALL use object storage (MinIO). Multiple attachments in one field SHALL be comma-separated URLs. - **Authoritative docs**: `工程规范` (requirements), `docs/web-admin-ui-spec-fresh-mint.md` (web UI), `docs/miniprogram-ui-spec-sanqiang.md` (miniprogram UI). ### Coding Conventions - **Minimal changes**: Commits SHALL contain only what's needed. No unrelated refactoring or formatting. - **Frontend (web-admin)**: pnpm, Prettier (single quotes, no semicolons, 2-space indent). Vue/Element Plus auto-imports — SHALL NOT manually import auto-imported APIs/components. - **Backend**: Python 3.9, FastAPI + SQLAlchemy + Pydantic v2. Routes stay thin; business logic goes in `app/services/` and `app/crud/`. Config via `pydantic-settings` + `.env` files. - **DB changes**: SHALL maintain SQL in `docs/sql/`. Schema changes SHALL align with `database-conventions` public field rules. - **Commit messages**: SHALL be complete sentences describing "what changed and why". Follow Conventional Commits (`feat|fix|docs|…`). - **Field consistency (CRUD ↔ Schema ↔ Frontend)**: When implementing CRUD for any entity, the `_row_to_dict` function is the **single source of truth** for all readable fields. The CreateBody/UpdateBody Pydantic schemas and the frontend `formData` initialization SHALL include every writable field present in `_row_to_dict` (excluding computed/read-only fields like `id`, `createTime`, `updateTime`, `stockQty`). Run `python scripts/check_field_consistency.py` after implementation to verify. See `docs/dev-field-consistency.md` for details. ### Permission Conventions - **Role-menu**: Selecting a child menu SHALL auto-include all ancestor menus (no orphan leaves). - **Data scope**: Per role — all / own dept / own dept and below / self only / custom. Custom uses `sys_role_data_scope_detail` with `scope_type` (dept/user) + `scope_value`. - **Multi-role union**: A user with multiple roles gets the **union** of menu permissions and the **union** of data scopes across all roles. - **Dual menu trees**: Web and miniprogram each have a separate top-level virtual root (`parent_id=0`). New menus SHALL be placed under the correct root. - **Tenant management**: Accessible ONLY by `super_admin`. All other system management runs within tenant context. ### Workflow Conventions (target design, not yet implemented) - **Engine**: SHALL be implemented in Python backend as an independent, configurable approval/flow subsystem. - **Node types**: Start, End, Approver, Conditional Branch (multi-branch supported). Extensible but SHALL NOT break published definitions. - **Approver strategies**: Specified users, specified roles, or SQL-based resolution. Per-node: "any one passes" or "all must pass". - **Versioning**: Each flow definition has a version. Running instances SHALL stick to their launch version; new versions only affect new launches. - **Task centers**: System SHALL provide "Pending Tasks" and "Completed Tasks" views. ## Backend (`backend/`) ### Stack FastAPI · SQLAlchemy · Pydantic v2 · MySQL (pymysql) · Redis · MinIO · JWT auth · Alembic migrations ### Commands ```bash source venv/bin/activate pip install -r requirements.txt cp .env.example .env.local # fill in DB, Redis, MinIO, etc. ./start-local.sh # uvicorn --reload on 127.0.0.1:8000 ./start-prod.sh start # production (reads .env.production, PID-managed) ./start-prod.sh status|stop|restart|logs ``` ### Entrypoint & Structure - Entrypoint: `app/main.py` → `app.main:app` - **`app/api/`** — Route files: `public.py` (no auth), `menu.py`, `admin.py`. Register new routers in `app/api/__init__.py` and `app/main.py`. - **`app/core/`** — Config (`config.py`), DB (`database.py`), auth (`auth.py`, `security.py`), middleware (`api_crypto_middleware.py`, `api_request_log_middleware.py`), RSA login crypto (`login_crypto.py`) - **`app/models/`** — SQLAlchemy models (`models.py`, `base.py`) - **`app/schemas/`** — Pydantic schemas per domain (auth, order, product, user, etc.) - **`app/crud/`** — Database CRUD operations (`base.py` has generic base) - **`app/services/`** — Business logic layer - **`app/tasks/`** — APScheduler scheduled tasks - **`scripts/`** — SQL migrations and one-off scripts ### Key Patterns - API prefix: `/api` (set via `API_V1_PREFIX` in config). Routes: `/api/public/*`, `/api/admin/*`, `/api/supplier/*`, `/api/client/*`, `/api/deliver/*` - Auth: JWT + RSA-encrypted login. Login RSA key auto-generated or set via `LOGIN_RSA_PRIVATE_KEY_PEM` env var. - API encryption middleware: symmetric crypto layer controlled by `API_ENCRYPT_*` env vars. Excluded paths listed in `API_ENCRYPT_EXCLUDE_PATHS`. - Config: pydantic-settings (`app/core/config.py`), reads from `.env` / `.env.local` / `.env.production`. - Database init / schema baseline: `docs/sql/zkxw.sql`(从当前库导出的全量 SQL)。Default admin: `admin` / `111111`, role `super_admin`. - Swagger docs at `/docs`, ReDoc at `/redoc`. - Tests: minimal, only `tests/test_api_crypto.py`. Run with `pytest`. ## Frontend (`web-admin/`) ### Stack Vue 3 · TypeScript (strict: false, noImplicitAny: false) · Vite 7 · Element Plus · Tailwind CSS 4 · Pinia · vue-router (hash mode) · SCSS · Axios · pnpm ### Commands ```bash pnpm install # if fails: pnpm install --ignore-scripts pnpm dev # Vite dev server (port from .env.development) pnpm build # production build pnpm build:typecheck # typecheck + build (vue-tsc --noEmit) pnpm lint # ESLint check pnpm fix # ESLint --fix pnpm lint:prettier # Prettier format all pnpm lint:stylelint # Stylelint fix SCSS/Vue pnpm commit # cz-git interactive commit pnpm clean:dev # strip demo data for fresh start ``` ### Entrypoint & Structure - Entrypoint: `src/main.ts` - **`src/views/system/`** — Main business pages: `category/`, `order/`, `product/`, `tenant/`, `unit/`, `user/` - **`src/api/`** — Axios API modules: `auth.ts`, `admin.ts`, `business.ts`, `system.ts`, `chinaRegion.ts` - **`src/store/modules/`** — Pinia stores: `user.ts`, `menu.ts`, `setting.ts`, `table.ts`, `worktab.ts` - **`src/router/modules/`** — Route modules: `index.ts`, `sqxp.ts`, `exception.ts` - **`src/utils/tree-path.ts`** — Tree path utilities (`buildTreePathLabelFromFlat`, etc.). Separator: ` / ` (spaced slash). ### Path Aliases (tsconfig + vite) `@/*` → `src/*`, `@views/*`, `@imgs/*`, `@icons/*`, `@utils/*`, `@stores/*`, `@plugins/*`, `@styles/*` ### Key Patterns - **Auto-imports**: `unplugin-auto-import` + `unplugin-vue-components` — Vue, vue-router, pinia, @vueuse/core APIs and Element Plus components are auto-imported. Don't manually import them. - **Element Plus**: auto-imported resolvers — use components directly, no manual imports. - **Tailwind CSS 4**: via `@tailwindcss/vite` plugin. - **SCSS**: global mixin/data injected via `vite.config.ts` `additionalData` (uses `@styles/core/el-light.scss` and `@styles/core/mixin.scss`). - **API proxy**: dev server proxies `/api` → `VITE_API_PROXY_URL` (localhost:8000). Also `/web` and `/mini` proxies configured. - **Env files**: `.env.development` (local), `.env.production` (prod). Uses `VITE_*` prefix. - **API encryption**: `VITE_API_ENCRYPT_ENABLED` toggles request/response crypto in dev. Production has it on. - **Hash routing**: URLs use `/#/` format. - **Access mode**: `VITE_ACCESS_MODE=frontend` (fixed frontend menu mode). ### Code Style - **Prettier**: single quotes, no semicolons, 2-space indent, trailing comma: none, `vueIndentScriptAndStyle: true` - **ESLint**: extends recommended + typescript + vue essential + prettier. `@typescript-eslint/no-explicit-any` is OFF. - **Stylelint**: SCSS + Vue + recess-order property sorting. - **Commit**: Conventional commits via `cz-git` + `commitlint`. Types: `feat|fix|docs|style|refactor|perf|test|build|ci|revert|chore|wip`. - **Husky + lint-staged**: pre-commit auto-runs ESLint, Prettier, Stylelint on staged files. ## UI Design Authority **The `.cursorrules` file and `docs/` are the authoritative source for all UI decisions.** - **Web admin UI spec**: `docs/web-admin-ui-spec-fresh-mint.md` + `docs/fresh-mint-green.html` - **Template pages** (match these exactly for new pages): - Standard list: `src/views/system/unit/index.vue` (`/#/demo/unit`) - Complex list: `src/views/system/order/index.vue` (`/#/demo/order`) - Product list + view dialog: `src/views/system/product/index.vue` - Tree master data: `src/views/system/category/index.vue` - User CRUD: `src/views/system/user/index.vue` - Console/dashboard: `src/views/dashboard/console/index.vue` - **Color tokens** (web-admin): Primary `#10b981`, dark `#059669`, bg `#ecfdf5`. Fresh Mint palette. **Do NOT use miniprogram colors in web-admin.** - **Tree display**: dropdown shows node name; selected/input/table shows full path (spaced slash separator). ## Knowledge Graph (代码知识图谱) 项目已生成代码知识图谱,用于理解模块间依赖关系、追踪修改影响范围。 ### 图谱位置 | 项目 | 报告 | 可视化 | 数据 | |------|------|--------|------| | 后端 | `backend/graphify-out/GRAPH_REPORT.md` | `backend/graphify-out/graph.html` | `backend/graphify-out/graph.json` | | 前端 | `web-admin/graphify-out/GRAPH_REPORT.md` | `web-admin/graphify-out/graph.html` | `web-admin/graphify-out/graph.json` | ### 使用方式 - **浏览器**:直接打开 `*/graphify-out/graph.html` 查看交互式图谱 - **AI Agent 查询**:已配置 MCP 服务(graphify),可通过工具调用查询图谱 - **手动更新**:`./scripts/update-graph.sh [backend|frontend|all]` ### Agent 更新规则 完成代码修改后(新建文件、修改函数签名、新增/删除 import、重构模块),Agent SHALL 执行 `./scripts/update-graph.sh` 增量更新图谱,确保图谱与代码保持同步。如果只修改了单个项目(backend 或 web-admin),只需更新对应项目即可。 ## Important Constraints - **Language**: User communication in Chinese (简体中文) when user writes in Chinese. - **Minimal changes**: Don't expand scope, don't refactor unrelated code. Match surrounding naming/type/import style. - **Cross-app colors**: Web admin uses Fresh Mint (`#10b981`), miniprogram uses 三墙 (`#0a9f6d`). Don't mix. - **No backdrop blur on modals**: `backdrop-filter: none`. - **Dialog forms**: `label-position="top"`. - **Table action column**: `fixed="right"`, min-width ≥ 260px. - **Table column widths**: Business data / action columns SHALL use `min-width` (not `width`) for proportional scaling. Exception: `type="selection"` and `type="index"` SHALL use fixed `width` (约 48–55 / 60–68) so they stay compact on wide screens. - **Toolbar**: "已选 N 项" first, then primary action button (only one `type="primary"` per toolbar row), no `space-between` push. - **Database changes**: always pair with schema SQL in `docs/sql/` and evaluate API/TypeScript type impact. ## graphify This project has a graphify knowledge graph at graphify-out/. Rules: - Before answering architecture or codebase questions, read graphify-out/GRAPH_REPORT.md for god nodes and community structure - If graphify-out/wiki/index.md exists, navigate it instead of reading raw files - For cross-module "how does X relate to Y" questions, prefer `graphify query ""`, `graphify path "" ""`, or `graphify explain ""` over grep — these traverse the graph's EXTRACTED + INFERRED edges instead of scanning files - After modifying code files in this session, run `graphify update .` to keep the graph current (AST-only, no API cost)