# Copilot Instructions ## Build, test, and lint commands ### Backend (`backend`) - Install/build: `mvn clean package` - Run tests: `mvn test` - Run one test class: `mvn -Dtest=ApprovalApplicationServiceTest test` - Run one test method: `mvn -Dtest=ApprovalApplicationServiceTest#handleActionApprovePublishesApprovedEventWhenFlowCompletes test` - Run locally: `mvn spring-boot:run` - Run with local profile: `mvn spring-boot:run -Dspring-boot.run.profiles=local` ### Admin frontend (`frontend-admin`) - Install: `npm install` - Dev server: `npm run dev` - Production build: `npm run build` - Preview build: `npm run preview` ### H5 frontend (`frontend-h5`) - Install: `npm install` - Dev server: `npm run dev` - Production build: `npm run build` - Preview build: `npm run preview` ### Uni-app mini program (`yuyueMiniProgram`) - Install: `pnpm install` - WeChat mini-program dev: `pnpm dev:mp-weixin` - H5 dev: `pnpm dev:h5` - WeChat mini-program build: `pnpm build:mp-weixin` - H5 build: `pnpm build:h5` - Type-check: `pnpm type-check` - Lint: `pnpm lint` - Auto-fix lint: `pnpm lint:fix` - Regenerate Alova API definitions: `pnpm alova-gen` ## High-level architecture - This repository is a multi-app workspace: - `backend`: Spring Boot 3 modular monolith for admin APIs and mini-program APIs - `frontend-admin`: Vue 3 + Vite admin console - `frontend-h5`: separate Vite/Vue H5 client - `yuyueMiniProgram`: separate uni-app/Wot UI client with its own toolchain and conventions - The backend is organized around **Controller -> ApplicationService -> Mapper/Mapper XML**: - controllers are thin request/response adapters - business orchestration lives in `*ApplicationService` - complex list/query SQL lives in `src/main/resources/mapper/*.xml` - MyBatis-Plus is used for CRUD plus pagination/optimistic locking - The core backend business flow is reservation and approval orchestration: - `MiniAppointmentApplicationService` creates reservations - `ApprovalEngineService` resolves approval node chains, assignees, and task transitions - `ApprovalApplicationService` and `MiniHandlerApprovalApplicationService` process approvals - approval completion publishes events consumed by `AppointmentLifecycleEventListener` - `PostApprovalOrchestrationService` performs post-approval work such as QR-code generation and notifications - There are **two auth systems** sharing the `Authorization` header but not the same login/session logic: - admin APIs use `StpUtil` with `/api/auth/**` - mini-program APIs use `StpLogic("mini")` via `/api/mini/**` - employee/visitor mini-program identity is stored in `mp_user`, not `sys_user` - Backend responses use a uniform `Result` envelope. Admin and mini-program clients both expect that wrapper rather than raw DTOs. - Backend persistence has a few important cross-cutting behaviors: - all entities inherit `BaseEntity` with `id`, `uuid`, `version`, audit fields, and `delFlag` - `MybatisPlusConfig` auto-fills `uuid`, timestamps, default `version`, and default `delFlag` - list-heavy screens rely on hand-written XML SQL (`AppointmentOrderMapper.xml`, `ApprovalTaskMapper.xml`) instead of only wrapper queries - SQL migrations in `backend/src/main/resources/db/migration/` are applied manually in version order; the app is not set up to auto-run them - The admin frontend is permission-driven: - `src/router/index.ts` uses route `meta.permission` - `src/stores/auth.ts` persists token/display info/permissions in `localStorage` - navigation falls back to the first allowed route from `pagePermissionOrder` - `src/api/http.ts` injects the token and expects backend `Result` semantics for auth/error handling - The admin login flow is coupled across frontend and backend: - `frontend-admin/src/utils/loginCrypto.ts` AES-encrypts username/password with a timestamp - `backend/.../AdminLoginCryptoService.java` decrypts and validates the same payload - keep frontend `VITE_ADMIN_LOGIN_AES_*` and backend `security.admin-login-crypto.*` aligned - The uni-app client is a separate application, not just a skin on the admin frontend: - file-based pages/layouts under `src/pages` and `src/layouts` - Pinia stores in `src/store` - Alova API layer in `src/api` - Wot Design Uni components and UnoCSS are the default UI stack ## Key conventions - **Do not inject Mapper directly into controllers.** This repository expects business logic in `*ApplicationService`. - **Preserve the dual-auth split.** Admin and mini-program endpoints may both read `Authorization`, but they are validated by different Sa-Token logics and should not be merged casually. - **When updating existing backend entities, keep `uuid` and `version` in mind.** `BaseEntity` validation groups and optimistic locking assume updates carry the current record identity/version. - **Use the existing async executors for new async work.** The backend now has named thread pools in `AsyncConfig`: - `applicationTaskExecutor` for general async/event/logging work - `exportTaskExecutor` for export jobs - **For admin list pages, check mapper XML before rewriting queries in Java.** Pagination, approval-status filtering, and visitor keyword filtering are already encoded in XML mappers. - **If you add or rename admin pages, update both routing and permission fallbacks.** `pagePermissionOrder` and each route's `meta.permission` must stay aligned with backend permission codes. - **Keep admin HTTP calls compatible with the `Result` wrapper.** The axios layer treats `code === 401` and `success === false` specially. - **Do not bypass admin login encryption.** Changes to login requests usually require coordinated edits in both `loginCrypto.ts` and `AdminLoginCryptoService`. - **For the uni-app app, follow the local project rules rather than the admin frontend style.** - use `pnpm`, not npm - prefer Pinia + Alova patterns already used under `src/store` and `src/api` - prefer Wot Design Uni / UnoCSS - use the existing global feedback components instead of direct `uni.showToast` - **Current local ports are code-driven, not README-driven.** - backend currently listens on `8880` (`application.yml`) - `frontend-admin` proxies `/api` and `/uploads` to `http://localhost:8880`