Generated: 2026-04-30 (initial knowledge base)
Three-tier wedding management system: Spring Boot REST API + Vue web app + uni-app mobile (H5 / WeChat Mini Program). Multi-wedding tenancy enforced at the SQL layer via a custom MyBatis interceptor.
.
├── chapel-backend/ # Spring Boot 3.2.5 + Java 21 + MyBatis Plus + ULID — see ./chapel-backend/AGENTS.md
├── chapel-frontend/ # Vue 3 + TypeScript + TDesign + Pinia — see ./chapel-frontend/AGENTS.md
├── doc/ # Personal/project notes; doc/note.md is user-maintained, do not edit unless asked
├── README.md # Human-facing structure, development, deployment, migration, maintenance guide
├── docker-compose.yml # MySQL 8 + backend + frontend
└── .env.example # Docker compose env (MYSQL_*, JWT_*, OSS_*)
| Task | Location |
|---|---|
| Add a new business module | All three: backend entity/+mapper/+service/+controller/, frontend api/+store/modules/+pages/+router/modules/chapel.ts, mobile api/+store/modules/+pages/+pages.json |
| Change wedding-data isolation | chapel-backend/.../interceptor/WeddingDataInterceptor.java |
| Auth flow | chapel-backend/.../common/Jwt*.java + chapel-frontend/src/permission.ts + chapel-frontend/src/store/modules/user.ts |
| Database schema | chapel-backend/src/main/resources/db/migration/V1__init_schema.sql (only one Flyway file so far) |
| Theme / design tokens | chapel-frontend/src/style/chapel-theme.less (Klein blue #002fa7) |
| Docker / nginx | chapel-backend/Dockerfile, chapel-frontend/Dockerfile, chapel-frontend/nginx*.conf, docker-compose.yml |
No @TableLogic. No deleted column. Hard delete throughout. This contradicts older notes that mentioned soft delete — the actual V1__init_schema.sql has no deleted column on any table.
All entities use @TableId(type = IdType.ASSIGN_UUID) + custom UlidIdentifierGenerator. Columns are CHAR(26). Never use IdType.ASSIGN_ID (will throw UnsupportedOperationException).
Backend WeddingDataInterceptor auto-injects WHERE wedding_id = ? into SELECTs against whitelisted tables (chapel_task, chapel_budget_*, chapel_guest, chapel_seating_event, chapel_hotel, chapel_collaboration). To opt out, annotate the mapper method with @ManualWeddingId. The current wedding ID lives in UserContext (ThreadLocal), populated by @RequireWedding aspect.
Database tables: chapel_user, chapel_wedding, chapel_user_wedding, chapel_guest, chapel_guest_group, chapel_seating_*, chapel_hotel*, chapel_room_assignment, chapel_budget_*, chapel_task*, chapel_collaboration. 17 entities total.
- Jackson
yyyy-MM-dd HH:mm:ss, time zoneAsia/Shanghai(set inapplication.yml). - All comments / Javadoc / log messages / user-facing error messages in Chinese.
- Frontend i18n:
zh_CN(default) +en_US.
- JWT, Bearer token. Subject is the ULID userId (String, not Long).
/auth/**routes bypass/apiprefix. Other endpoints under/api/**.- Frontend stores token in
localStoragevia Pinia persist (user.tokenonly).
cp .env.example .env
docker compose up -d # MySQL + backend + frontend (HTTP, port 80)
docker compose logs -f backend# Backend (chapel-backend/)
mvn spring-boot:run # Uses application.yml + env vars
mvn clean package -DskipTests # Build JAR
# Frontend (chapel-frontend/)
npm run dev # Vite dev, port 3002, proxies /api+/auth → :8080
npm run dev:mock # Same, with mock mode (mock/ dir is currently empty)
npm run build # Typecheck (vue-tsc) + build
npm run lint # ESLint --max-warnings 0
npm run stylelint # Stylelint for CSS/Less
# Mobile (chapel-mobile/)
npm run dev:h5 # uni-app H5 dev
npm run dev:mp-weixin # WeChat Mini Program dev
npm run typecheck # vue-tsc --noEmitAngular Conventional Commits via commitlint (frontend has the .husky hook):
feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|types|perf: <subject>
- Don't add
@TableLogicordeletedcolumns — physical delete is intentional. - Don't use
IdType.ASSIGN_IDon entities — must beIdType.ASSIGN_UUID(ULID). - Don't refactor
tabs-router.ts:56keepAlive !== falsecondition — explicit comment forbids it. Subtle keep-alive default semantics. - Don't bypass
WeddingDataInterceptorwithout@ManualWeddingId. Silent data leak ifwedding_idis missing from context. - Don't commit OSS credentials — backend config is env-var driven; keep real keys in local/server
.envonly. - Don't write English Javadoc — backend convention is Chinese.
- Root is the canonical git repo for open-source work.
chapel-backend/andchapel-frontend/are no longer nested git repos; their previous.gitdirectories are backed up under.git-backups/and ignored. chapel-mobile/,design/, andicon/are intentionally ignored for now because they are not part of the initial open-source scope.mock/directory underchapel-frontend/is configured (vite-plugin-mock) but currently empty — backend is the source of truth.- No frontend test framework. Backend uses
spring-boot-starter-test(JUnit 5 + Mockito). - Backend uses a single
application.yml; local and production differences come from env vars such asMYSQL_*,OSS_*,JWT_*, and log levels. - Production HTTPS is expected to be handled by host nginx or another edge proxy. The Compose stack only exposes HTTP from
chapel-frontendplus the backend and MySQL ports configured in.env.