AGENTS.md 13 KB

AGENTS.md — 杭州第一技师学院智慧校园管理系统

Monorepo Structure

Multi-project workspace. No monorepo tool — each sub-project is independent.

Directory Stack Framework Port Notes
crm/backend/ Java 17, Maven RuoYi-Vue-Plus 5.4.0, Spring Boot 3.4.6 8080 Main backend; Sa-Token auth, MyBatis-Plus ORM
crm/web/ Node 18.18+, npm Vue 3.5 + TypeScript 5.8 + Vite 6.3 + Element Plus 2.9 80 Main admin frontend; auto-imports Vue APIs
crm/py-backend/ Python FastAPI / scripts — 主工程侧 Python 服务(若使用)
crm/mobile/ Node, pnpm uni-app Vue 2.6 + uview-ui 2.0 + vue-cli-service 8081 (H5) 主工程移动端(纳入仓库时使用该路径)
bx/bx-backend/ Python 3.11+ FastAPI + SQLAlchemy 2 + Uvicorn 8011 报销(expense) sub-system backend
bx/bx-web/ Node, npm Vue 3.5 + TypeScript + Vite 6.3 + Element Plus — 报销 sub-system admin frontend
bx/bx-mobile/ Node, npm Vue 3.4 + TypeScript + Vite 5 + Vant 4 — 报销 sub-system mobile frontend
crm/ — — — 主工程(智慧校园 / RuoYi)根:crm/backend、crm/web、crm/sql、文档与原型等
bx/docs/ — — — 报销子系统规范与计划(含 UI 规范、superpowers 计划)

Non-app under crm/: crm/sql/、crm/yuanxing/、crm/graphify-out/、crm/docs/、crm/*.md 等;报销文档在 bx/docs/;另有 ui-ux-pro-max-skill-main/ 等工具目录。

Developer Commands

Backend (Java)

cd crm/backend

# Build (skips tests by default — <skipTests>true</skipTests> in pom.xml)
mvn clean package -DskipTests

# Start all services in order (monitor → job → main app)
bash start-all.sh

# Or start individually (MUST follow this order):
bash start-monitor.sh     # Monitor center → port 9090
bash start-job.sh          # SnailJob scheduler → port 8800
bash hot-start.sh          # Main app → port 8080 (interactive, supports hot-reload)

# Maven profiles: local, dev (default), prod, prod-local
# (prod-9900 is a Spring profile only, not a Maven profile)
mvn clean package -P dev

hot-start.sh compiles ruoyi-modules/ with mvn clean install first, then ruoyi-admin/. Supports flags: -p <profile>, -P <port>, -c (clean), -d (debug on port 5005), --no-hot.

Web Frontend (Vue 3)

cd crm/web
npm install --registry=https://registry.npmmirror.com
npm run dev              # Dev server on port 80, proxies /prod-api → localhost:8080
npm run build:prod       # Production build (increases heap to 8GB)
npm run lint:eslint      # Lint
npm run lint:eslint:fix  # Lint fix
npm run prettier         # Format

Vitest is installed as devDependency but no test script is defined in package.json.

Mobile (uni-app)

cd crm/mobile
pnpm install             # Has .npmrc with shamefully-hoist=true; pnpm-lock.yaml present
pnpm run dev:h5          # H5 development (vue-cli-service uni-serve)
pnpm run dev:mp-weixin   # WeChat miniprogram development
pnpm run build:h5        # H5 production build

CRM Python backend (optional)

cd crm/py-backend
bash start.sh            # Uses .venv + uvicorn per project script

BX Backend (Python/FastAPI)

cd bx/bx-backend
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
bash start.sh            # Reads .env, runs uvicorn on port 8011 (default)
# With debug reload: set DEBUG=true in .env
# Tests: pytest (httpx + pytest in dev deps)

BX Web & Mobile

cd bx/bx-web && npm install && npm run dev   # Proxies /api → localhost:8011
cd bx/bx-mobile && npm install && npm run dev

Architecture Notes

Backend Module Layout

crm/backend/
├── ruoyi-admin/              # App entry point (SpringApplication.run)
├── ruoyi-common/             # Shared library modules (20+)
│   ├── ruoyi-common-core/
│   ├── ruoyi-common-mybatis/
│   ├── ruoyi-common-redis/
│   ├── ruoyi-common-satoken/
│   ├── ruoyi-common-web/
│   ├── ruoyi-common-excel/
│   └── ...
├── ruoyi-modules/            # Business modules
│   ├── ruoyi-system/         # System management (users, roles, menus)
│   ├── ruoyi-xg/             # 学工管理 (student affairs) ⭐ main custom module
│   ├── ruoyi-crm/            # CRM module
│   ├── ruoyi-workflow/       # Workflow (warm-flow engine)
│   ├── ruoyi-job/            # Scheduled tasks
│   ├── ruoyi-generator/      # Code generator
│   └── ruoyi-demo/           # Demo/examples
└── ruoyi-extend/
    ├── ruoyi-monitor-admin/  # Spring Boot Admin → port 9090
    └── ruoyi-snailjob-server/ # SnailJob scheduler → port 8800

BX Backend Layout

bx/bx-backend/app/
├── main.py          # FastAPI entry (app.main:app)
├── config.py        # Settings via pydantic-settings
├── database.py      # SQLAlchemy engine/session
├── models/          # SQLAlchemy ORM models
├── schemas/         # Pydantic request/response schemas
├── routers/         # API route handlers
├── services/        # Business logic
└── utils/           # Helpers

Key Backend Conventions

  • Package: org.dromara.{module} — e.g. org.dromara.xg, org.dromara.system
  • Auth: Sa-Token with JWT, permission format {module}:{entity}:{action} (e.g. xg:student:list)
  • ORM: MyBatis-Plus with BaseMapperPlus<Entity, VO> — provides selectVoPage, selectVoList etc.
  • Object mapping: MapStruct-Plus 1.5.0 (@AutoMapper annotation on BO/VO classes)
  • Multi-tenant: Entities extend TenantEntity, tenant filtering is automatic
  • ID strategy: Snowflake (ASSIGN_ID) — NOT auto-increment
  • Logical delete: del_flag field with @TableLogic
  • API docs: SpringDoc auto-generated at /swagger-ui/index.html (uses javadoc comments, no annotations needed)
  • Excel: FastExcel with @ExcelProperty on VO fields for export
  • Validation groups: AddGroup / EditGroup for create vs update validation
  • Key deps: Hutool 5.8, Redisson 3.45, Warm-Flow 1.7.3, SnailJob 1.5.0

Backend Layer Pattern (ruoyi-xg as reference)

controller/  → REST endpoints, @SaCheckPermission, @Log, @RepeatSubmit
service/     → Interface (IXgXxxService)
service/impl → Implementation with LambdaQueryWrapper + MapstructUtils.convert
mapper/      → BaseMapperPlus<Xxx, XxxVo> (XML only for custom SQL)
domain/      → Entity (@TableName, extends TenantEntity)
domain/bo/   → Business Object (@AutoMapper(target=Entity), validation groups)
domain/vo/   → View Object (@AutoMapper(target=Entity), @ExcelProperty)

Frontend Conventions (crm/web/)

  • Style: <script setup lang="ts"> with Composition API
  • Auto-import: Vue APIs (ref, reactive, onMounted etc.) are auto-imported via unplugin-auto-import
  • Path alias: @ → src/
  • API layer: src/api/{module}/xxx.ts — each file defines Query, Form, VO interfaces + CRUD functions
  • Views: src/views/{module}/xxx/index.vue — standard CRUD page (query form → toolbar → table → dialog)
  • Auth directive: v-hasPermi="['xg:student:add']" for button-level permission control
  • Dict: useDict('dict_type') returns reactive dict data; <dict-tag> renders dict labels
  • Proxy: Vite dev server proxies VITE_APP_BASE_API (/prod-api) → http://localhost:8080
  • API encryption: Enabled by default (VITE_APP_ENCRYPT=true), RSA key pair in .env
  • Extra libs: vxe-table 4.13, UnoCSS 66, echarts 5.6, vue-i18n 11, TinyMCE/WangEditor rich text

Mobile Conventions

  • uni-app Vue 2 with uview-ui component library (NOT Vue 3)
  • Uses pnpm (not npm); .npmrc sets shamefully-hoist=true
  • Uses @vue/cli-service (webpack-based), NOT Vite
  • Pages configured in src/pages.json
  • API utilities in src/common/

Environment & Prerequisites

  • JDK: 17 (required; 21 also supported)
  • Maven: 3.8.8+
  • Node.js: 18.18+ (web), compatible version for mobile
  • Python: 3.11+ (bx/bx-backend 报销;若使用主工程 Python 则为 crm/py-backend/)
  • MySQL: 5.7+ or 8.0+ (can use remote instance)
  • Redis: 5.0+ (can use remote instance)
  • Database name: sx (shared across all Spring profiles)
  • Encoding: All Java/Maven processes use UTF-8 + Asia/Shanghai timezone (set by start scripts)

Gotchas

  • Backend startup order matters: monitor (9090) → job (8800) → main app (8080). Use start-all.sh for correct ordering.
  • hot-start.sh builds ruoyi-modules/ before ruoyi-admin/: If you get compile errors in admin, check that ruoyi-modules installed first.
  • Tests skipped by default: <skipTests>true</skipTests> in pom.xml
  • No .env files in git: application-local.yml, .env.*.local are gitignored. Only crm/web/.env (production defaults) is tracked.
  • Mobile is Vue 2, web is Vue 3: Completely different ecosystems. Mobile uses pnpm + webpack; web uses npm + Vite.
  • Code generator: Available at system tools menu — generates full CRUD scaffolding from DB table definitions.
  • Sensitive data: Student PII (ID numbers, phone numbers) uses data masking annotations.
  • Warm-flow workflow: Enabled by default; workflow definitions managed via built-in designer at /warm-flow-ui.
  • bx/ is independent: The 报销 (expense) sub-system has its own Python backend on port 8011, separate from the main Java backend on 8080. No shared code.
  • bx-web proxies /api → localhost:8011: Not the same proxy path as main web (/prod-api → localhost:8080).
  • Main stack paths: Java backend crm/backend/, admin UI crm/web/, optional Python crm/py-backend/ — run Maven/npm from these directories (not repo-root backend/ / web/).

Existing Instruction Files

  • .cursorrules — Comprehensive code generation rules (Chinese), full-stack conventions, layer patterns, complete code templates. High-value reference for any code generation task.
  • crm/README.md — 主工程目录约定;仓库根 scripts/crm.sh 可在不先 cd 时在 crm/backend|web|py-backend 下执行命令
  • crm/工程本地启动指导.md — Local setup and startup guide with environment installation steps
  • crm/docs/backend/README-热启动脚本.md — Hot-reload startup script documentation
  • .github/workflows/crm-backend-validate.yml — CI:在 crm/backend 下执行 mvn validate(推送/PR 触及后端时触发)

bx-web (报销子系統前端) Conventions

Applies to bx/bx-web/ — Vue 3.5 + TypeScript + Element Plus project.

Component Architecture

  • Page pattern: Each page uses useServerPaged hook + ListPageScaffold (or FilterBlock + DataTablePanel + ListToolbar) for standard CRUD layout.
  • Base components: BaseDialog.vue, BaseButton.vue, BaseInput.vue, BaseSelect.vue, BaseTable.vue, BaseTag.vue, BaseOpButton.vue, BaseClampText.vue, BaseDetailTableSection.vue, ApprovalFlowView.vue
  • Template components: ListPageScaffold.vue, FilterBlock.vue, DataTablePanel.vue, ListToolbar.vue

Dialog Rules (强约束)

  • All dialogs must be centered (horizontal + vertical) via align-center prop on el-dialog / BaseDialog. Never use top offset.
  • Dialog submit buttons must have :loading bound to a loading state variable.
  • Use loadingMap: Record<string, boolean> pattern to track loading state per action.

Search/Filter Rules (强约束)

  • Filter params must be passed to API: When search is triggered, pass filterForm values to pager.search({ ...filterForm }). Never call refresh() without filter params.
  • Use search() not refresh() for user-triggered search: search() resets page to 1 before fetching. refresh() keeps current page.
  • Reset must clear form + reload: handleReset() should clear filterForm fields then call pager.search().
  • Search/Reset buttons must show loading: Bind :loading="pager.loading" (or equivalent).

Button Loading Rules (强约束)

  • Every async button must have :loading: Including query, reset, save, submit, delete, approve, reject, export, etc.
  • Pattern: const loadingMap = reactive<Record<string, boolean>>({}), then :loading="loadingMap.xxx" on button, loadingMap.xxx = true/false around async call.

Table Action Column Rules (强约束)

  • 操作列必须固定右侧: 所有 <el-table-column label="操作"> 必须设置 fixed="right" + class-name="col-actions"。
  • 操作列宽度必须容纳所有按钮: 宽度按按钮数量和文案长度设定,不得出现按钮被截断或换行。
    • 1 个按钮:width="120" | 2 个按钮:width="200" | 3 个按钮:width="280" | 4 个按钮:width="360"
    • 含 3-4 字文案时加 40-60px。
  • 表格支持横向滚动: 使用 .table-scroll 包裹 el-table,设置 overflow-x: auto。
  • 操作列单元格禁止换行: class-name="col-actions" 配合 CSS .col-actions .cell { white-space: nowrap; }。