Add conventions, ADR, CI workflows, and prompts

New directories:
- .claude/rules/: Coding conventions (Flyway, Java, Vue, memory)
- .claude/skills/fix-gate/, gen-migration/: Specialized skills
- .github/workflows/: CI/CD pipelines
- docs/: Architecture documentation and ADRs
- prompts/: System prompts and evaluation templates
- scripts/ci/: CI linting scripts
- spec/phase/TEMPLATE.md: Phase Brief template

Files added:
- Flyway, Java, Vue conventions for code generation
- Memory management decisions and session tracking
- CI workflow with shell/yaml linting
- Architecture decision records (ADR-001: tech stack)
- Backend/Frontend builder system prompts
- Phase execution templates and evaluations

Total: 19 files, 1118 insertions

Co-authored-by: Qwen-Coder <[email protected]>
This commit is contained in:
2026-02-23 15:18:57 +08:00
co-authored by Qwen-Coder
parent e83d73fbae
commit 567cde064d
19 changed files with 1118 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
---
paths:
- "ljwx-platform-app/src/main/resources/db/migration/**/*.sql"
---
# Flyway 迁移规范 — LJWX Platform
## 文件命名
格式:`V{phase}_{seq}__{description}.sql`
示例:
- `V1_1__create_sys_user.sql`
- `V6_1__seed_admin_user.sql`
- `V15_2__add_notification_index.sql`
迁移文件路径:`ljwx-platform-app/src/main/resources/db/migration/`
## DDL 硬规则
1. **禁止** `IF NOT EXISTS`(Flyway 负责版本管理,不需要幂等 DDL)
2. 业务表(非 Quartz)**必须**含 7 列审计字段,均 NOT NULL + 有 DEFAULT:
```sql
CREATE TABLE sys_example (
id BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
-- 7 个审计字段,业务表必须全部包含
tenant_id BIGINT NOT NULL DEFAULT 0,
created_by BIGINT NOT NULL DEFAULT 0,
created_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by BIGINT NOT NULL DEFAULT 0,
updated_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted TINYINT NOT NULL DEFAULT 0,
version INT NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
```
3. Quartz 系统表(`QRTZ_*`)**不得**含审计字段
4. **禁止** `DROP TABLE`(除非 ADR 明确批准)
5. **禁止** `TRUNCATE`
## 已应用迁移不可修改
一旦 Flyway 迁移文件被 apply,**永远不能修改**。
追加变更需创建新的迁移文件(更高版本号)。
## 种子数据
- 管理员初始密码 `Admin@12345`,使用 BCrypt cost=10 哈希
- 写在 V006 种子 SQL 中
+61
View File
@@ -0,0 +1,61 @@
---
paths:
- "ljwx-platform-*/src/**/*.java"
- "ljwx-platform-*/src/**/*.xml"
---
# Java 编码规范 — LJWX Platform
## 模块 DAG 依赖(硬规则)
```
core ← {security, data} ← web ← app
```
- `ljwx-platform-data/` **禁止** import `com.ljwx.platform.security.*`
- `ljwx-platform-security/` **禁止** import `com.ljwx.platform.data.*`
- `ljwx-platform-core/` **禁止** import 任何其他 `com.ljwx.platform.*` 模块
- `ljwx-platform-web/` 通过 security 间接依赖,**禁止**直接 import data
## 实体 / Mapper
- 所有业务实体必须继承 `BaseEntity`(含 7 列审计字段)
- 审计字段:`tenant_id`, `created_by`, `created_time`, `updated_by`, `updated_time`, `deleted`, `version`
- 使用 MyBatis-Plus `@TableName` 注解
## Service
- `tenant_id` 由 `TenantLineInterceptor` 自动注入,**禁止** `setTenantId()`
- 写操作加 `@Transactional`
## Controller
正确写法:
```java
@GetMapping
@PreAuthorize("hasAuthority('resource:action')")
public Result<PageResult<UserVO>> list(UserQueryDTO query) { ... }
```
- 每个 `@(Get|Post|Put|Delete|Patch)Mapping` 方法上方 **必须** 有 `@PreAuthorize`
- 格式:`hasAuthority('resource:action')`,**禁止** `hasRole(...)` 或 `ROLE_` 前缀
- 例外:路径含 `/auth/login` 或 `/auth/refresh` 的端点
## DTO / Request / Response
- **禁止** 出现 `tenantId` 或 `tenant_id` 字段
- 字段用 `@NotNull`、`@NotBlank`、`@Size` 等 Bean Validation 注解
- 命名:`XxxCreateDTO`、`XxxUpdateDTO`、`XxxQueryDTO`、`XxxVO`
## POM
- **禁止** `${latest.version}` 占位符
- 所有版本号必须硬编码数字
- 版本以 CLAUDE.md "版本锁定" 表为唯一来源
## 安全规范
- 密码字段日志输出 → `***`
- 手机号中间四位 → `*`
- 身份证中间段 → `*`
- BCrypt cost=10:`new BCryptPasswordEncoder(10)`
+45
View File
@@ -0,0 +1,45 @@
# LJWX Platform — 关键决策记录
本文件记录已做出的架构决策,避免重复讨论。
## 2026-02-23: macOS 兼容性 — 使用 ERE 而非 PCRE
所有 shell 脚本使用 POSIX ERE(`grep -E`),禁止 `grep -P`(GNU/PCRE-only)。
理由:macOS 自带 BSD grep 不支持 `-P`。
具体替换规则:
- `\s` → `[[:space:]]`
- `\S` → `[^[:space:]]`
- `\|`(PCRE 交替) → `|`(ERE 交替)
- `\K`(lookbehind)→ `sed -n 's/.../\1/p'`
- `(?!...)`(负向前瞻)→ 两步 grep:先匹配,再排除
## 2026-02-23: Flyway 规范 — 禁止 IF NOT EXISTS
Flyway 通过版本号管理迁移,不需要幂等 DDL。
`CREATE TABLE IF NOT EXISTS` 是反模式,已通过 post-edit-check.sh hook 拦截。
## 2026-02-23: Vue Router v5 API
项目使用 vue-router `~5.0.2`。v5 将 unplugin-vue-router 功能内置。
所有代码必须用 Composition API(`useRoute()`/`useRouter()`),禁止 Options API 路由守卫。
`onBeforeRouteLeave` 和 `onBeforeRouteUpdate` 在 v5 中合法。
## 2026-02-23: Hook 机制
Claude Code hooks 仅支持三种事件:`PreToolUse`、`PostToolUse`、`Stop`。
`SessionStart` 不是有效事件类型。
PreToolUse → pre-edit-guard.sh(路径级阻断)
PostToolUse → post-edit-check.sh(内容级检查)
Stop → stop-gate.sh(Phase 完成校验)
## 2026-02-23: .env.example 处理
Claude Code 系统沙箱阻止写入所有 `.env.*` 文件(含 `.env.example`)。
解决方案:`stop-gate.sh` 跳过 `.env*` 文件的 scope 检查;用户手动创建该文件。
## 2026-02-23: settings.json 权限策略
使用 `"defaultMode": "dontAsk"` 配合精细化 allow/deny 列表。
`sandbox.enabled: true` 提供额外的系统级保护。
代理类型权限用 `Task(backend-builder)` 格式。
+54
View File
@@ -0,0 +1,54 @@
# LJWX Platform — 项目档案
本文件由 Claude Code 自动维护,记录不变的项目事实。
## 技术栈
| 层 | 技术 | 版本 |
|---|------|------|
| 后端语言 | Java | 21 |
| 框架 | Spring Boot | 3.5.11 |
| ORM | MyBatis-Plus | 3.0.5 |
| 数据库 | PostgreSQL | 16.12 |
| 迁移 | Flyway | 由 Spring Boot BOM 管理 |
| 前端框架 | Vue | ~3.5.28 |
| 路由 | Vue Router | ~5.0.2 |
| 状态管理 | Pinia | ~3.0.4 |
| UI 组件 | Element Plus | ~2.13.2 |
| 包管理 | pnpm | 10.30.1 |
| 构建 | Vite | ~7.3.1 |
| 类型 | TypeScript | ~5.9.3 |
## 模块结构
```
ljwx-platform/
├── ljwx-platform-core/ # 基础类,无外部依赖
├── ljwx-platform-security/ # 认证授权,依赖 core
├── ljwx-platform-data/ # 数据访问,依赖 core(不依赖 security)
├── ljwx-platform-web/ # Web 层,依赖 security + data
├── ljwx-platform-app/ # 启动模块,依赖 web
├── ljwx-platform-admin/ # Vue 3 管理后台
├── ljwx-platform-mobile/ # uni-app 移动端
└── ljwx-platform-screen/ # 数据大屏
```
## 多租户策略
- 应用层隔离:每张业务表含 `tenant_id` 列
- TenantLineInterceptor 自动注入 tenant_id(从 JWT claim 提取)
- DTO / 请求参数**禁止**传 tenantId
- SecurityContext 是 tenantId 的唯一来源
## 关键配置
- 后端编译:`mvn clean compile -f pom.xml -q`
- 前端类型检查:`pnpm run type-check`(在 ljwx-platform-admin/)
- Gate 检查:`bash scripts/gates/gate-all.sh <phase-number>`
- 预检:`bash scripts/preflight/preflight-check.sh`
## Phase 系统
- Phase 0–19(当前规划)
- 每个 Phase 的说明在 `spec/phase/phase-NN.md`
- 完成记录写入 `PHASE_MANIFEST.txt`
+44
View File
@@ -0,0 +1,44 @@
# LJWX Platform — 会话日志
本文件由 Claude Code 在每次会话结束时更新,记录已完成的工作。
## 2026-02-23: 基础设施建设(Session 1-2)
### 完成内容
- 修复所有 gate 脚本(gate-nfr.sh、gate-contract.sh)的 PCRE 兼容性问题
- 创建 Phase 0 骨架文件:pom.xml、pnpm-workspace.yaml、package.json、.npmrc、
.nvmrc、docker-compose.yml、.gitignore、.editorconfig、.mvn/wrapper/、
scripts/tools/export-openapi.sh、scripts/acceptance/smoke-test.sh
- 修复 pre-edit-guard.sh(shebang、.env.example 白名单)
- 修复 stop-gate.sh(.env* 跳过逻辑)
- 修复 preflight-check.sh(8 处 PCRE → ERE 转换、J3/K9 逻辑修正)
- 为三个 agent 文件添加 permissionMode 字段
- 在 CLAUDE.md 第 3 条添加 "(audit fields)" 英文关键词
### 当前 Phase 状态
Phase 0 骨架文件已创建,PHASE_MANIFEST.txt 已写入 PASSED。
下一步:运行 `/preflight` 确认全部通过,然后执行 `/phase-exec 1`。
### 挂起事项
- `.env.example` 需用户手动创建(沙箱限制)
- preflight Section I 的版本号警告(WARN,非 FAIL):spec/01-constraints.md 中
版本号格式与提取 pattern 不匹配,需酌情更新 spec 文件
## 2026-02-23: AI-Native GitOps 体系建设(Session 3)
### 完成内容
- 创建 .claude/rules/ 条件上下文规则文件:
- java-conventions.md(paths: *.java)
- vue-conventions.md(paths: *.vue, *.ts)
- flyway-rules.md(paths: */migration/*.sql)
- memory-profile.md(全局)
- memory-decisions.md(全局)
- memory-sessions.md(全局,即本文件)
- 更新 .claude/agents/ 文件(清理无效字段)
- 添加新技能:fix-gate、gen-migration
- 创建 docs/ 文档结构
- 创建 spec/phase/TEMPLATE.md
- 创建 scripts/ci/ 和 .github/workflows/
### 下一步
确认 preflight 全绿,执行 Phase 1。
+80
View File
@@ -0,0 +1,80 @@
---
paths:
- "ljwx-platform-admin/**/*.vue"
- "ljwx-platform-admin/**/*.ts"
- "ljwx-platform-admin/**/*.tsx"
- "ljwx-platform-screen/**/*.vue"
- "ljwx-platform-mobile/**/*.vue"
---
# Vue 3 / TypeScript 规范 — LJWX Platform
## TypeScript 硬规则
- **禁止** `: any`、`as any`、`<any>`
- `tsconfig.json` 必须 `"strict": true`
- 所有 props、emits、ref 必须有明确类型
## 组件写法
正确:
```vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { UserVO } from '@ljwx/shared'
const users = ref<UserVO[]>([])
</script>
<style scoped lang="scss">
// scoped styles
</style>
```
- 只用 `<script setup lang="ts">` 语法糖
- **禁止** Options API、`defineComponent()`
- 样式必须 `<style scoped lang="scss">`
## Vue Router v5 API(重要)
```typescript
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
// Composition API:
const route = useRoute()
const router = useRouter()
// 路由守卫(v5 合法写法):
onBeforeRouteLeave((to, from) => { ... })
onBeforeRouteUpdate((to, from) => { ... })
```
- **禁止** Options API 路由守卫(`beforeRouteLeave` / `beforeRouteUpdate` 写在组件选项里)
- **禁止** v4 专属的 `useLink`(v5 已内置)
- 所有路由视图必须懒加载:`component: () => import('...')`
- 路由文件:手动定义,不使用文件系统路由
## API 调用
```typescript
import request from '@/api/request'
// 返回类型从 @ljwx/shared 引入
```
- API 调用只通过 `src/api/*.ts` 模块,**禁止**在组件内直接 fetch / axios
- **禁止** `VITE_API_BASE_URL`、`VITE_BASE_API` 等变量,只用 `VITE_APP_BASE_API`
## Pinia Store
```typescript
export const useUserStore = defineStore('user', () => {
const token = ref<string>('')
return { token }
})
```
- 使用 setup function 语法,禁止 options 语法
- Store 文件放 `src/stores/`
## package.json 依赖版本
- 所有 `dependencies` / `devDependencies` 只用 `~`(tilde patch)
- **禁止** `^`(caret)
- 版本号以 CLAUDE.md "版本锁定" 表为唯一来源
+56
View File
@@ -0,0 +1,56 @@
---
name: fix-gate
description: Fix all gate failures for a phase. Reads gate output, fixes each violation, re-runs gate until all checks pass. Use when gate-all.sh reports FAILs.
argument-hint: "[phase-number]"
---
# 修复 Gate 失败
修复 Phase $ARGUMENTS 的所有 gate 失败项。
## 步骤
1. 运行 gate 获取失败列表:
```bash
bash scripts/gates/gate-all.sh $ARGUMENTS
```
2. 对每条 `FAIL` 输出,按以下流程处理:
**[no-preauthorize]** — Controller 缺少 @PreAuthorize:
- 读取对应的 Controller 文件
- 在每个 @*Mapping 上方添加 `@PreAuthorize("hasAuthority('resource:action')")`
- login/refresh 端点除外
**[no-caret]** — package.json 使用了 `^`:
- 将所有 `"^x.y.z"` 改为 `"~x.y.z"`
**[dto-no-tenant-id]** — DTO 含 tenantId 字段:
- 删除该字段;在 Service 层从 SecurityContext 提取
**[no-any]** — TypeScript 使用了 `any`:
- 替换为正确的类型定义;从 @ljwx/shared 导入共享类型
**[no-if-not-exists]** — Flyway SQL 含 IF NOT EXISTS:
- 删除 `IF NOT EXISTS` 关键词(Flyway 通过版本号保证幂等性)
**[wrong-env-var]** — 错误的环境变量名:
- 替换为 `VITE_APP_BASE_API`
**[dag-violation]** — 模块 DAG 违规:
- 检查 import 语句,移除跨层引用
- 如需共享,将类移至 core 模块
**[audit-columns]** — SQL 缺少审计字段:
- 添加 7 列:tenant_id, created_by, created_time, updated_by, updated_time, deleted, version
3. 每修复一类问题后,重新运行对应的编译/类型检查:
- Java 文件修改后:`mvn clean compile -f pom.xml -q`
- TS/Vue 文件修改后:`pnpm run type-check`(在 ljwx-platform-admin/)
4. 所有问题修复后,重新运行完整 gate:
```bash
bash scripts/gates/gate-all.sh $ARGUMENTS
```
5. 重复步骤 2-4,直到 gate 输出全部 `PASS`。
+54
View File
@@ -0,0 +1,54 @@
---
name: gen-migration
description: Generate a Flyway SQL migration file following LJWX project conventions. Use when adding new database tables or schema changes.
argument-hint: "[phase-number] [description]"
---
# 生成 Flyway 迁移文件
为 Phase $ARGUMENTS 生成符合项目规范的 Flyway 迁移 SQL 文件。
## 步骤
1. 查看现有迁移文件,确定版本号:
```bash
ls ljwx-platform-app/src/main/resources/db/migration/
```
2. 确定新文件名:
- 格式:`V{phase}_{seq}__{description}.sql`
- 示例:`V15_1__create_notification_table.sql`
- seq 从当前 phase 最大序号 +1 开始
3. 生成 SQL 文件,遵循以下规则:
**业务表模板(必须含 7 列审计字段)**:
```sql
CREATE TABLE t_example (
id BIGINT NOT NULL COMMENT '主键',
name VARCHAR(100) NOT NULL COMMENT '名称',
-- 7 个审计字段 — 业务表必须全部包含
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
created_by BIGINT NOT NULL DEFAULT 0 COMMENT '创建人',
created_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_by BIGINT NOT NULL DEFAULT 0 COMMENT '更新人',
updated_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除(0:正常,1:删除)',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
INDEX idx_tenant_id (tenant_id)
) COMMENT = '示例表';
```
**硬规则**:
- 禁止 `IF NOT EXISTS`
- 禁止 `DROP TABLE`(除非有 ADR 批准)
- 禁止修改已应用的迁移文件
- Quartz 系统表(`QRTZ_*`)不含审计字段
4. 验证迁移文件创建后后端仍可编译:
```bash
mvn clean compile -f pom.xml -q
```
5. 如果是 Quartz 相关表,参考 Spring Boot Quartz 官方 SQL schema,不添加审计字段。
+65
View File
@@ -0,0 +1,65 @@
name: CI
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Shell script syntax check
run: bash scripts/ci/lint-shell.sh
- name: YAML validation
run: |
pip install pyyaml --quiet
bash scripts/ci/lint-yaml.sh
backend:
name: Backend
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'maven'
- name: Backend compile
run: mvn clean compile -f pom.xml -q
- name: Backend test
run: mvn test -f pom.xml -q
frontend:
name: Frontend
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- uses: pnpm/action-setup@v4
with:
version: '10.30.1'
- name: Install dependencies
run: cd ljwx-platform-admin && pnpm install --frozen-lockfile
- name: Type check
run: cd ljwx-platform-admin && pnpm run type-check
- name: Lint
run: cd ljwx-platform-admin && pnpm run lint
+80
View File
@@ -0,0 +1,80 @@
name: Prompt Review
on:
pull_request:
paths:
- 'CLAUDE.md'
- '.claude/rules/**'
- '.claude/skills/**'
- '.claude/agents/**'
- 'prompts/**'
jobs:
validate:
name: Validate AI Assets
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Shell script syntax check
run: bash scripts/ci/lint-shell.sh
- name: YAML validation
run: |
pip install pyyaml --quiet
bash scripts/ci/lint-yaml.sh
- name: CLAUDE.md line count check
run: |
LINES=$(wc -l < CLAUDE.md)
echo "CLAUDE.md: $LINES lines"
if [ "$LINES" -gt 200 ]; then
echo "::warning file=CLAUDE.md::CLAUDE.md exceeds 200 lines ($LINES). Consider moving detail to spec/ files."
fi
- name: Rules files frontmatter check
run: |
ERRORS=0
while IFS= read -r -d '' RULE_FILE; do
REL="${RULE_FILE#"$PWD"/}"
FIRST=$(head -1 "$RULE_FILE")
if [ "$FIRST" = "---" ]; then
echo " [OK] $REL has frontmatter"
else
echo " [INFO] $REL has no frontmatter (loads globally)"
fi
done < <(find .claude/rules -type f -name "*.md" -print0 2>/dev/null)
- name: Agent files required fields check
run: |
ERRORS=0
for AGENT_FILE in .claude/agents/*.md; do
[ -f "$AGENT_FILE" ] || continue
REL="$AGENT_FILE"
if ! grep -q '^permissionMode:' "$AGENT_FILE"; then
echo " [FAIL] $REL missing permissionMode field"
ERRORS=$((ERRORS + 1))
else
echo " [OK] $REL"
fi
done
if [ "$ERRORS" -gt 0 ]; then
echo "Agent validation failed: $ERRORS file(s) missing required fields"
exit 1
fi
- name: Prompt version bump check
run: |
CHANGED=$(git diff --name-only origin/${{ github.base_ref }} -- prompts/system/ prompts/templates/ 2>/dev/null || true)
for F in $CHANGED; do
[ -f "$F" ] || continue
OLD_VER=$(git show "origin/${{ github.base_ref }}:$F" 2>/dev/null | grep -m1 '^version:' | sed 's/version:[[:space:]]*//' || echo "none")
NEW_VER=$(grep -m1 '^version:' "$F" | sed 's/version:[[:space:]]*//' || echo "none")
if [ "$OLD_VER" = "$NEW_VER" ] && [ "$OLD_VER" != "none" ]; then
echo "::warning file=$F::Version not bumped (still $OLD_VER). Update 'version:' and add a changelog entry."
else
echo " Version bump: $OLD_VER -> $NEW_VER in $F"
fi
done
+38
View File
@@ -0,0 +1,38 @@
# ADR-001: 技术栈选型
## 状态
已采纳(2026-02-23)
## 背景
构建企业级多租户 SaaS 平台,需要:
- 强类型安全
- 成熟的安全框架
- 良好的前端工程化
- 简单的数据库迁移管理
## 决策
| 层 | 技术选型 | 理由 |
|---|---------|------|
| 后端 | Spring Boot 3.5 + Java 21 | 成熟生态、强安全框架、LTS |
| ORM | MyBatis-Plus | 多租户拦截器支持好 |
| 前端 | Vue 3 + Vue Router 5 + Pinia | Composition API、TS 支持完善 |
| 数据库 | PostgreSQL 16 | 生产稳定、JSONB 支持 |
| 迁移 | Flyway | 显式版本管理,与 Phase 开发模式匹配 |
| 前端构建 | Vite 7 + pnpm | 快速 HMR、确定性依赖 |
| API 文档 | springdoc-openapi | Spring Boot 3 原生支持 |
## 后果
- Java 21 需要对应 JDK(`JAVA_HOME` 指向 21)
- pnpm 10 作为包管理器,版本由 `packageManager` 字段锁定
- Flyway 迁移文件不可修改(已 apply 的),需新建版本文件追加变更
- Vue Router 5 与 v4 API 不完全兼容,需按 v5 文档编写
## 参考
- [Spring Boot 3.x 文档](https://docs.spring.io/spring-boot/docs/3.5.x/)
- [Vue Router 5 迁移指南](https://router.vuejs.org/guide/migration/v4-to-v5)
- [MyBatis-Plus 多租户插件](https://baomidou.com/plugins/tenant/)
+92
View File
@@ -0,0 +1,92 @@
# LJWX Platform — 架构概览
## 系统定位
企业级多租户 SaaS 平台脚手架。支持管理后台(Admin)、移动端(uni-app Mobile)、数据大屏(Screen)三端接入。
## 后端架构
### 模块 DAG
```
ljwx-platform-core
↑ ↑
ljwx-platform-security ljwx-platform-data
↑ ↑
ljwx-platform-web
↑
ljwx-platform-app ← Spring Boot 启动入口
```
约束:
- `core` 不依赖任何其他模块
- `security` 和 `data` 仅依赖 `core`,互不依赖
- `web` 依赖 `security` 和 `data`
- `app` 是唯一的可运行模块
### 关键组件
| 组件 | 职责 |
|------|------|
| TenantLineInterceptor | MyBatis-Plus 拦截器,自动在所有 SQL 注入 `tenant_id` WHERE 条件 |
| SecurityConfig | Spring Security 配置,JWT 过滤链 |
| JwtTokenFilter | 解析 JWT,填充 SecurityContext(含 tenantId) |
| BaseEntity | 含 7 列审计字段的 MyBatis-Plus 基类 |
| Result<T> | 统一 REST 响应包装器 |
### 多租户策略
- **方式**:应用层过滤(每张业务表含 `tenant_id` 列)
- **注入点**:TenantLineInterceptor 自动读取 SecurityContext 中的 tenantId
- **禁止**:Service 层手动 `setTenantId()`;DTO/请求参数携带 tenantId
## 前端架构
```
src/
├── api/ # Axios 封装 + 各模块 API 函数
├── components/ # 全局公共组件
├── layouts/ # 布局(BasicLayout、BlankLayout)
├── router/ # Vue Router 5,手动路由定义
│ └── modules/ # 按模块拆分的路由文件
├── stores/ # Pinia 状态管理
├── views/ # 页面组件(按模块组织)
└── types/ # TypeScript 类型定义
```
### 关键约束
- 只用 `<script setup lang="ts">`,禁止 Options API
- Vue Router 5 Composition API(`useRoute()`、`useRouter()`)
- 所有 API 调用通过 `src/api/*.ts`,禁止组件内直接 fetch
- 环境变量只用 `VITE_APP_BASE_API`
## 数据库
- PostgreSQL 16
- Flyway 版本化迁移(文件命名:`V{phase}_{seq}__{description}.sql`)
- 每张业务表包含 7 列审计字段
## API 设计
- REST 风格,统一前缀 `/api/v1/`
- 响应体统一用 `Result<T>` 包装
- 认证:JWT Bearer Token
- 授权:Spring Security `@PreAuthorize("hasAuthority('resource:action')")`
- 分页:Spring `Pageable` 参数 + `PageResult<T>` 响应
## 开发环境
```bash
# 启动数据库
docker compose -f docker-compose.yml up -d
# 后端编译
mvn clean compile -f pom.xml -q
# 前端依赖安装
cd ljwx-platform-admin && pnpm install
# 前端类型检查
cd ljwx-platform-admin && pnpm run type-check
```
@@ -0,0 +1,56 @@
name: backend-builder-evaluation
version: "1.0.0"
target_prompt: backend-builder-system-prompt
target_prompt_version: "1.0.0"
description: "Assertions on the backend builder system prompt completeness"
assertions:
- id: E-BE-01
description: "Prompt mentions tenantId isolation"
type: contains
value: "tenantId"
- id: E-BE-02
description: "Prompt requires @PreAuthorize"
type: contains
value: "@PreAuthorize"
- id: E-BE-03
description: "Prompt forbids IF NOT EXISTS in Flyway"
type: contains
value: "IF NOT EXISTS"
- id: E-BE-04
description: "Prompt specifies compile command"
type: contains
value: "mvn clean compile"
- id: E-BE-05
description: "Prompt specifies entity generation order"
type: contains
value: "Entity"
- id: E-BE-06
description: "Prompt references TenantLineInterceptor"
type: contains
value: "TenantLineInterceptor"
- id: E-BE-07
description: "Prompt specifies BCrypt requirement"
type: contains
value: "BaseEntity"
- id: E-BE-08
description: "Prompt enforces complete output"
type: contains
value: "完整"
- id: E-BE-09
description: "Prompt covers DAG dependency"
type: contains
value: "DAG"
- id: E-BE-10
description: "Prompt covers DTO tenantId prohibition"
type: contains
value: "DTO"
+39
View File
@@ -0,0 +1,39 @@
name: backend-builder-system-prompt
version: "1.0.0"
model: claude-sonnet-4-6
author: ljwx-team
changelog:
- version: "1.0.0"
date: "2026-02-23"
description: "Initial backend builder system prompt"
system_prompt: |
你是 LJWX Platform 的高级 Java 后端工程师,负责生成高质量、符合所有硬规则的代码。
技术栈:Spring Boot 3.5 / Java 21 / MyBatis-Plus / PostgreSQL / Flyway。
## 模块 DAG(严格执行)
core ← {security, data} ← web ← app
- data 禁止 import security 的任何类
- security 禁止 import data 的任何类
- core 禁止 import 其他 ljwx 模块
## 硬规则
1. 所有业务实体继承 BaseEntity(含 7 列审计字段)
2. 每个 @*Mapping 方法必须有 @PreAuthorize("hasAuthority('resource:action')"),login/refresh 除外
3. DTO/Request/Response 禁止含 tenantId 字段
4. Service 层禁止手动 setTenantId(),由 TenantLineInterceptor 自动注入
5. Flyway 迁移禁止 IF NOT EXISTS
6. POM 版本禁止 ${latest.version},必须硬编码数字
7. 每个新文件必须输出完整内容,禁止省略
## 生成顺序
Entity → Mapper → Service → Controller → Flyway 迁移 SQL
## 编译验证
每生成 3-5 个文件后运行:mvn clean compile -f pom.xml -q
编译失败立即修复,不继续生成下一个文件。
context_requirements:
- "CLAUDE.md"
- ".claude/rules/java-conventions.md"
- ".claude/rules/flyway-rules.md"
+36
View File
@@ -0,0 +1,36 @@
name: frontend-builder-system-prompt
version: "1.0.0"
model: claude-sonnet-4-6
author: ljwx-team
changelog:
- version: "1.0.0"
date: "2026-02-23"
description: "Initial frontend builder system prompt"
system_prompt: |
你是 LJWX Platform 的高级 Vue 3 前端工程师,负责生成高质量、类型安全的前端代码。
技术栈:Vue 3.5 / Vue Router 5 / Pinia 3 / TypeScript 5.9 / Element Plus / pnpm。
## 硬规则
1. 只用 <script setup lang="ts"> 语法糖,禁止 Options API
2. 禁止 any / as any / <any>,所有类型必须明确
3. tsconfig.json 必须 "strict": true
4. 使用 Vue Router 5 Composition API:useRoute(), useRouter()
- onBeforeRouteLeave / onBeforeRouteUpdate 在 v5 合法
- 禁止 Options API 路由守卫(beforeRouteLeave 写在组件选项中)
5. API 调用只通过 src/api/*.ts,禁止组件内直接 fetch
6. 环境变量只用 VITE_APP_BASE_API
7. package.json 只用 ~(tilde),禁止 ^(caret)
8. 样式 <style scoped lang="scss">
9. 每个新文件必须输出完整内容,禁止省略
## 生成顺序
TypeScript 类型定义 → API 函数 → Pinia Store → 路由模块 → Vue 视图
## 类型检查验证
每生成 3-5 个 TS/Vue 文件后运行:pnpm run type-check(在 ljwx-platform-admin/)
类型错误立即修复,不继续生成下一个文件。
context_requirements:
- "CLAUDE.md"
- ".claude/rules/vue-conventions.md"
+31
View File
@@ -0,0 +1,31 @@
name: phase-execution-template
version: "1.0.0"
author: ljwx-team
description: "Template for executing any numbered phase"
changelog:
- version: "1.0.0"
date: "2026-02-23"
description: "Initial phase execution template"
template: |
执行 Phase {PHASE_NUM}。
## 步骤
1. 读取 spec/phase/phase-{PHASE_NUM_PADDED}.md 获取本阶段任务
2. 严格按 "读取清单" 加载指定的 spec 文件(禁止扫描整个 spec/ 目录)
3. 按 scope 顺序逐文件生成,每文件生成后立即编译/类型检查
4. 运行 gate:bash scripts/gates/gate-all.sh {PHASE_NUM}
5. 修复所有 FAIL 项,直到全部 PASS
6. 写入 PHASE_MANIFEST.txt
7. 提示用户更新 CLAUDE.md 中的 Current Phase
## 质量检查清单(输出前自查)
- [ ] 所有新文件输出完整内容(无省略标记)
- [ ] 所有 Controller 方法有 @PreAuthorize
- [ ] 所有 Flyway SQL 含 7 列审计字段且无 IF NOT EXISTS
- [ ] 所有 DTO 无 tenantId 字段
- [ ] 所有 package.json 只用 ~,无 ^
- [ ] 所有 TS/Vue 无 any 类型
- [ ] 仅修改 Phase scope 内的文件(禁止顺手重构无关文件)
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -euo pipefail
# CI: syntax-check all shell scripts in the project.
# Uses bash -n for all .sh files.
# Uses shellcheck if available (warning level, non-blocking).
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ERRORS=0
echo "=== Shell Script Lint ==="
echo ""
# Collect all .sh files
while IFS= read -r -d '' SCRIPT_FILE; do
REL="${SCRIPT_FILE#"$PROJECT_ROOT"/}"
if bash -n "$SCRIPT_FILE" 2>/dev/null; then
echo " [OK] $REL"
else
echo " [FAIL] $REL — syntax error:"
bash -n "$SCRIPT_FILE" 2>&1 | sed 's/^/ /'
ERRORS=$((ERRORS + 1))
fi
done < <(find \
"$PROJECT_ROOT/scripts" \
"$PROJECT_ROOT/.claude/hooks" \
-type f -name "*.sh" -print0 2>/dev/null)
# shellcheck if available (informational only)
if command -v shellcheck >/dev/null 2>&1; then
echo ""
echo "--- shellcheck (warnings only, non-blocking) ---"
while IFS= read -r -d '' SCRIPT_FILE; do
REL="${SCRIPT_FILE#"$PROJECT_ROOT"/}"
if ! shellcheck -S warning -e SC2148 "$SCRIPT_FILE" 2>/dev/null; then
echo " [WARN] $REL has shellcheck findings"
fi
done < <(find \
"$PROJECT_ROOT/scripts" \
"$PROJECT_ROOT/.claude/hooks" \
-type f -name "*.sh" -print0 2>/dev/null)
else
echo ""
echo " [INFO] shellcheck not installed — install with: brew install shellcheck"
fi
echo ""
if [ "$ERRORS" -gt 0 ]; then
echo "LINT FAILED: $ERRORS script(s) have bash syntax errors"
exit 1
fi
echo "LINT PASSED"
exit 0
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -euo pipefail
# CI: validate YAML files in the project using Python's yaml module.
# Checks prompts/ and .github/workflows/ directories.
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ERRORS=0
echo "=== YAML Validation ==="
echo ""
if ! command -v python3 >/dev/null 2>&1; then
echo " [SKIP] python3 not found — YAML validation skipped"
exit 0
fi
if ! python3 -c "import yaml" 2>/dev/null; then
echo " [SKIP] PyYAML not installed — run: pip install pyyaml"
exit 0
fi
# Find YAML files in known directories
while IFS= read -r -d '' YAML_FILE; do
REL="${YAML_FILE#"$PROJECT_ROOT"/}"
if python3 -c "
import yaml, sys
try:
with open(sys.argv[1]) as fh:
yaml.safe_load(fh)
except yaml.YAMLError as e:
print(f'YAML error: {e}', file=sys.stderr)
sys.exit(1)
" "$YAML_FILE" 2>/dev/null; then
echo " [OK] $REL"
else
ERROR_MSG=$(python3 -c "
import yaml, sys
try:
with open(sys.argv[1]) as fh:
yaml.safe_load(fh)
except yaml.YAMLError as e:
print(str(e))
" "$YAML_FILE" 2>&1 || true)
echo " [FAIL] $REL — $ERROR_MSG"
ERRORS=$((ERRORS + 1))
fi
done < <(find \
"$PROJECT_ROOT/prompts" \
"$PROJECT_ROOT/.github/workflows" \
-type f \( -name "*.yaml" -o -name "*.yml" \) -print0 2>/dev/null)
echo ""
if [ "$ERRORS" -gt 0 ]; then
echo "YAML VALIDATION FAILED: $ERRORS file(s) invalid"
exit 1
fi
echo "YAML VALIDATION PASSED"
exit 0
+121
View File
@@ -0,0 +1,121 @@
---
title: "Phase Template Title"
phase: 0
targets:
- backend
- frontend
scope:
- "ljwx-platform-*/src/main/java/com/ljwx/platform/*/entity/*.java"
- "ljwx-platform-*/src/main/java/com/ljwx/platform/*/mapper/*.java"
- "ljwx-platform-*/src/main/java/com/ljwx/platform/*/service/*.java"
- "ljwx-platform-*/src/main/java/com/ljwx/platform/*/controller/*.java"
- "ljwx-platform-app/src/main/resources/db/migration/V0_1__example.sql"
- "ljwx-platform-admin/src/api/module.ts"
- "ljwx-platform-admin/src/router/modules/module.ts"
- "ljwx-platform-admin/src/stores/module.ts"
- "ljwx-platform-admin/src/views/module/index.vue"
depends_on: []
gate_rules:
- no-preauthorize
- no-caret
- dto-no-tenant-id
- no-any
- no-if-not-exists
- wrong-env-var
- dag-violation
- audit-columns
---
# Phase N: 标题
## 目标
本 Phase 要实现的功能概述。
## 读取清单
> 严格按此清单读取,禁止扫描整个 spec/ 目录
- `spec/01-constraints.md` §C01(多租户),§C02(权限)
- `spec/04-database.md` §相关表结构章节
- `spec/03-api.md` §相关接口章节
## 后端任务
### 实体层
**表名**:`t_xxx`
**基类**:继承 `BaseEntity`(已含 7 列审计字段)
| 字段名 | 类型 | 约束 | 说明 |
|-------|------|------|------|
| id | BIGINT | PK | 主键 |
| name | VARCHAR(100) | NOT NULL | 名称 |
### Mapper
方法列表:
- `selectByXxx(XxxQueryDTO)` — 条件查询(TenantLineInterceptor 自动注入 tenant_id)
### Service
- `listXxx(XxxQueryDTO): PageResult<XxxVO>` — 列表查询
- `createXxx(XxxCreateDTO): Long` — 创建,返回 ID
### Controller
REST 路径:`/api/v1/xxx`
| 方法 | 路径 | 权限 | 说明 |
|-----|------|------|------|
| GET | /api/v1/xxx | `xxx:read` | 分页列表 |
| POST | /api/v1/xxx | `xxx:write` | 创建 |
| PUT | /api/v1/xxx/{id} | `xxx:write` | 更新 |
| DELETE | /api/v1/xxx/{id} | `xxx:delete` | 删除 |
### Flyway 迁移
文件:`V{N}_1__create_xxx_table.sql`
## 前端任务
### API 层
文件:`src/api/xxx.ts`
- `getXxxList(params?: XxxQueryDTO): Promise<Result<PageResult<XxxVO>>>`
- `createXxx(data: XxxCreateDTO): Promise<Result<number>>`
### 路由
文件:`src/router/modules/xxx.ts`
- `/xxx` — 列表页
### 视图
文件:`src/views/xxx/index.vue`
- 搜索表单 + `el-table` 列表 + 分页
## 验收条件
1. `mvn clean compile -f pom.xml -q` 通过
2. `pnpm run type-check` 通过(在 ljwx-platform-admin/)
3. `bash scripts/gates/gate-all.sh N` 全部 PASS
4. 无 TypeScript `any`
5. 所有 Controller 方法有 `@PreAuthorize`
6. 迁移 SQL 含 7 列审计字段且无 `IF NOT EXISTS`
## PHASE_MANIFEST.txt 记录格式
```
## PHASE N
Status: PASSED
ljwx-platform-*/src/.../XxxEntity.java
ljwx-platform-*/src/.../XxxMapper.java
ljwx-platform-*/src/.../XxxService.java
ljwx-platform-*/src/.../XxxController.java
ljwx-platform-app/src/main/resources/db/migration/VN_1__create_xxx_table.sql
ljwx-platform-admin/src/api/xxx.ts
ljwx-platform-admin/src/router/modules/xxx.ts
ljwx-platform-admin/src/views/xxx/index.vue
```