diff --git a/.blueprint/rules.md b/.blueprint/rules.md new file mode 100644 index 0000000..f2f1261 --- /dev/null +++ b/.blueprint/rules.md @@ -0,0 +1,42 @@ +# 项目私有规则 + +> 本文件由梦核分析 + 用户确认后生成,Claude 每次对话开始时读取并合并应用。 +> 规则格式与 CONVENTIONS 自动推荐规则库相同,优先级高于全局规则。 +> 来源:2026-07-04 梦核分析,基于 40 条复盘笔记 + 跨项目返工数据。 + +## 规则列表 + +### P01 — Android 画布/地图叠加面板必须用 absolute 定位 +- **触发条件**:在地图、画布、SVG 可缩放视图上叠加侧边/底部面板 +- **自动动作**:确认面板用 `position: absolute` 覆盖;严禁通过 `Animated.timing` / `LayoutAnimation` 改变父容器 flex 宽高——会触发底层视图重新布局,Android 上出现闪白/黑块 +- **confidence**: 0.90 +- **evidence_count**: 3 +- **derived_from**: FoldableLayout 3 轮返工(4e1d922→cea2a5d→3dbc6f0),JS 线程宽度动画两次都有 Android 渲染问题,absolute 定位彻底解决 + +### P02 — 选图统一用 expo-document-picker,禁用 expo-image-picker +- **触发条件**:需要从相册选取图片 +- **自动动作**:直接使用 `expo-document-picker`(`ACTION_GET_CONTENT`);发现代码中引用 `expo-image-picker` 时提示替换 +- **confidence**: 0.92 +- **evidence_count**: 3 +- **derived_from**: 摄像头任务 3 轮返工(expo-image-picker SDK52 API 废弃 + 三星 Photo Picker 系统崩溃),expo-document-picker 彻底绕开 + +### P03 — 全屏预览 Modal 不用 transparent prop +- **触发条件**:实现全屏照片预览、全屏地图等需要覆盖整个屏幕的 Modal +- **自动动作**:去掉 `transparent` prop 改为非透明黑底;FlatList pagingEnabled 改为手势驱动单张渲染 +- **confidence**: 0.88 +- **evidence_count**: 2 +- **derived_from**: MarkerPhotoPanel 返工(transparent Modal 渲染范围被限制为父容器宽度,FlatList 分页宽度异常) + +### P04 — 列表页禁止 N+1 查询 +- **触发条件**:列表组件需要展示每行的统计数据(照片数、物品数、数量合计等) +- **自动动作**:在 SQL 层通过 `LEFT JOIN` 子查询或 `GROUP BY` 一次聚合取数;发现逐行查询时标记需重构 +- **confidence**: 0.80 +- **evidence_count**: 1 +- **derived_from**: ItemList 照片数统计 N+1 查询,O(n) 查库,内容量增大后有性能风险(2026-04-11 复盘) + +### P05 — 动态数据前置:表单骨架初始化前先确认数据源 +- **触发条件**:设计表单组件 / 列表筛选 chip / 下拉选择器 +- **自动动作**:先问"这些选项/分类将来是否动态?";有动态数据则在 `_layout.tsx` 根布局一次性接入对应 `Context/Provider`,不得在组件层后补 +- **confidence**: 0.80 +- **evidence_count**: 2 +- **derived_from**: ItemFields 分类 chip 3 轮返工(硬编码→动态 CategoriesContext 后补)+ Expo 骨架 2 轮返工(CategoriesProvider 初版未加) diff --git a/CLAUDE.md b/CLAUDE.md index 7200bc9..90037a1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,40 +1,14 @@ # react-phone-apps - + ## 项目蓝图 -本项目使用 `.blueprint/` 目录维护项目全景架构图,驱动需求讨论和任务管理。 - -### 对话开始时必须执行 +蓝图工作流规则统一维护在 @AGENTS.md 的 BLUEPRINT_MANAGED 区(跨工具单一来源,勿在此复制)。 +对话开始时必须执行: 1. 读取 `.blueprint/manifest.yaml` 了解项目全景和当前状态 2. 读取 `.blueprint/CONVENTIONS.md` 了解完整工作流规则 - -### 需求讨论 → 蓝图同步规则 - -| 用户说的 | Claude 应做的 | -|----------|--------------| -| "我想加个 XX 功能" | 确认需求后:manifest 新增模块(status: concept),创建 `.blueprint/modules/.md` | -| "XX 功能需要 A、B、C" | 在模块文件中拆分为任务卡 | -| "这个方案确定了" | 模块 status → planned,补充任务卡 files/acceptance | -| "开始做 XX" | 模块 status → in_progress | -| 没提蓝图但在讨论功能 | 主动提议更新蓝图 | - -### 复杂度决策(讨论新功能 / 拆解需求时) - -| complexity | 执行流程 | -|-----------|---------| -| S / M | 直接拆任务卡,确保每张卡有 `files` + `acceptance` + `complexity` → 标记 📋 | -| L(复杂系统设计) | 先 `/architect` 输出设计文档,用户确认后 `/splitter` 拆成 S/M 任务卡 | - -> L 级任务禁止直接写代码,必须先经过 `/architect` → `/splitter` 流程。 - -### 任务执行两阶段提交 - -- **开始写代码前**:任务卡前缀改为 🔵,status → in_progress -- **完成验收后**:任务卡前缀改为 ✅,status → done,更新 manifest `updated` 日期 - -完整规则(迭代管理、阻塞处理、复盘笔记等)详见 `.blueprint/CONVENTIONS.md`。 +3. 遵循 AGENTS.md 中的蓝图工作流(需求→蓝图同步、复杂度决策、两阶段提交) ## 命令执行规则 @@ -48,3 +22,36 @@ ``` - Windows 环境变量 → bash 语法用 `export VAR=value`,**不用** PowerShell 的 `$env:VAR` - 只有以下情况才让用户手动操作:需要交互式登录(如 `gcloud auth login`)、需要输入密码、或明确的破坏性操作需确认 + +## 开发注意事项(踩坑提炼) + +### Android 平台 + +- **Modal 不用 `transparent` prop**:transparent Modal 渲染范围被限制为父容器宽度(如侧栏 260px),FlatList pagingEnabled 等全屏功能失效。改用非透明 Modal(黑底),强制创建独立原生全屏窗口 +- **Modal 内手势需额外 GestureHandlerRootView**:Modal 是独立 native window,父级 RNGH 上下文无法穿透。内容最外层必须包 `` +- **禁止在 Alert 回调内启动相机/相册**:Alert 关闭动画期间 Activity 焦点未恢复,intent 被系统忽略。改为 UI 直接放按钮触发 +- **三星设备 Photo Picker 崩溃**:用 `expo-document-picker`(`ACTION_GET_CONTENT`)替代 `expo-image-picker` 的相册选择 +- **手势组合用 `Simultaneous` + `maxPointers`**:避免 `Exclusive` 导致 pinch 延迟。Pan 加 `maxPointers(1)` 天然分离单指/双指 + +### Expo SDK 52 + pnpm Monorepo + +- expo 包版本用 `~`(如 `~13.0.2`),**禁止 `^`**,防止 pnpm 解析到 SDK 53+ 导致 `expo-module-gradle-plugin not found` +- 构建始终从 app 目录运行 `pnpm expo run:android`,不进 `android/` 直接执行 Gradle +- `metro.config.js` 必须设置 `unstable_serverRoot` 指向 app 目录(修复 Windows monorepo 路径解析 bug) +- `expo-image-picker` v16 移除了 `MediaType` 枚举,`mediaTypes` 用字符串数组 `['images']` + +### 地图与布局 + +- FoldableLayout 面板用 absolute 定位叠加在地图上方,地图 `flex:1` 始终满屏渲染,禁止用动画改变地图宽度(会触发 Android 地图重新布局闪白) +- SVG 地图文件更新后须重新运行生成脚本(`scripts/` 下),当前未纳入 watch 模式 + +### 数据库 + +- 新增字段时先评估未来 2-3 步迭代可能需要的字段,避免反复 ALTER TABLE(初版遗漏 unit/spec/confirmed_at 导致返工) +- 迁移脚本用 `try/catch` 逐步执行,单个迁移失败不阻断后续;迁移全部幂等,多次启动安全 +- 删除标记点时级联删除 items → photos 并同步删除文件系统文件,不能只删数据库行 +- **列表页禁止 N+1 查询**:凡需附加统计字段(照片数、物品数等)必须在 SQL 层通过 `LEFT JOIN` 子查询或 `GROUP BY` 一次取数,禁止逐行查询(ItemList 照片数统计返工来源) + +### 表单与组件 + +- **动态数据前置**:设计表单/列表骨架前,先确认 chip/下拉选项是否会变为动态数据;有则在骨架初始化时(`_layout.tsx`)一次性接入对应 `Context/Provider`,不得后补(分类 Context 后补返工来源) diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..d7569a3 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,16 @@ +# 接入包标准 lefthook 配置(炼境分发) +# 作用:强制 Conventional Commits + 提交前类型检查 +# 安装:pnpm add -D lefthook && pnpm exec lefthook install + +pre-commit: + parallel: true + commands: + # TODO: 按项目调整 typecheck 命令与 glob(monorepo 用 --filter typecheck) + typecheck: + glob: "*.{ts,tsx}" + run: pnpm typecheck + +commit-msg: + commands: + conventional: + run: "head -1 .git/COMMIT_EDITMSG | grep -qE '^(feat|fix|docs|chore|refactor|ci|perf|style|test|build|revert)(\\(.+\\))?!?: .+' || exit 1"