Squash merge feat/expo-app: app-expo, .cursor, workflows, package.json, .husky; remove app-android, app-ios, react-app
This commit is contained in:
@@ -4,29 +4,21 @@ alwaysApply: true
|
||||
|
||||
# Backend Fastapi
|
||||
|
||||
1. `**common/` / `utils/` / `shared/` / `helpers/` 禁止创建**:只有 truly cross-cutting 能力进 `core/`,业务 DTO/校验/错误码归 feature
|
||||
2. **router 是 HTTP + OpenAPI 契约边界**:所有数据访问通过 repo,所有业务逻辑通过 service;但 `response_model`、`status_code`、`responses`、`summary`、`description`、`tags` 等契约元数据必须定义在 router / `APIRouter` 上
|
||||
## 架构规则
|
||||
1. **`common/` / `utils/` / `shared/` / `helpers/` 禁止创建**:只有 truly cross-cutting 能力进 `core/`,业务 DTO/校验/错误码归 feature
|
||||
2. **router 禁止操作 DB**:所有数据访问通过 repo,所有业务逻辑通过 service
|
||||
3. **service 禁止 import adapter**:只依赖 port protocol,通过 DI 注入。代码中出现 `from adapters.xxx import ...` 即为违规
|
||||
4. **feature 间禁止 import router**:跨 feature 调用通过 service 注入
|
||||
5. **所有 schema 变更走 Alembic**:禁止直接 DDL
|
||||
6. **新增 provider 必须实现 port protocol**:不得在 feature 中直接调用 SDK
|
||||
7. **事务边界:repo 不提交,service 管事务**:`repo.py` 只做 `add/delete/query`,`commit/rollback` 由 service 或 UoW 统一执行。`get_async_db()` 不自动 commit;`flush()` 仅在明确需要提前拿主键或触发约束检查时受控使用
|
||||
7. **事务边界:repo 不提交,service 管事务**:`repo.py` 只做 `add/delete/query`,`commit/rollback` 由 service 或 UoW 统一执行。`get_async_db()` 不自动 commit
|
||||
8. **port 边界不可打穿**:service 需要厂商增强能力时,必须扩充 port 或定义第二个窄 port,禁止直接引用 adapter 扩展方法
|
||||
9. **quota 是独立 feature**:conversation、memoir、payment 如需配额检查,通过注入 `QuotaService`,不得直接 import quota 内部函数
|
||||
10. **成功响应不强制包装**:`core/errors.py` 只统一错误响应格式 `{error_code, message, request_id}`,成功响应直接返回 Pydantic model / FileResponse / 原始结构
|
||||
11. **配置统一通过 `pydantic-settings` 管理**:只允许在 `core/config.py` 中定义 `BaseSettings` / `SettingsConfigDict`;除配置模块外,禁止业务代码直接 `load_dotenv()`、`dotenv_values()` 或散落 `os.getenv()`
|
||||
12. **依赖真相源是 `api/pyproject.toml` + `api/uv.lock`**:`requirements.txt` 如存在仅作兼容导出,不作为主依赖入口
|
||||
13. **运行时基础库保持收敛**:Redis 客户端统一使用 `redis` / `redis.asyncio`,JWT 统一使用 `PyJWT`
|
||||
14. **service 装配走 FastAPI dependency graph**:router 只依赖 `get_xxx_service()`,不得在路由函数里手工 new service 或自行拼装 `db + adapter + settings`
|
||||
15. **每个 feature router 必须维护共享 tags / responses**:使用 `APIRouter(prefix=..., tags=..., responses=...)` 收敛文档边界与共享错误响应
|
||||
16. **内部接口显式隐藏**:不对外暴露的 path operation 使用 `include_in_schema=False`,禁止依赖“没人知道 URL”
|
||||
17. **OpenAPI 全局自定义只做增强**:`custom_openapi()` 只做全局 schema 增强,不替代 router 上的正常声明
|
||||
18. **WebSocket 协议必须独立成文**:实时消息 schema、错误、鉴权、状态流转、重连与幂等规则不得只存在于代码实现中
|
||||
19. **memory 的定义是素材检索与事实组织,不是聊天 persona 记忆**:不实现通用“记住这个”或面向终端用户的自然语言 `forget`
|
||||
20. **memory 必须采用混合检索**:至少包含 metadata filter + PostgreSQL FTS + vector retrieval;纯向量库不得作为唯一真相源
|
||||
21. **原始素材、摘要、事实、时间线必须分层存储**:不得把所有语义压进单一向量表
|
||||
22. **memory 写入必须可追溯**:summary / fact / timeline event 必须能追溯到 `source` 或 `chunk`
|
||||
23. **conversation / memoir 只通过 `MemoryService` 调用 memory**:不得直接查询 memory 表
|
||||
24. **memory feature 不得直接耦合具体 embedding SDK**:只依赖 `EmbeddingProvider`(可选 `Reranker` 同理)
|
||||
25. **所有 pgvector / FTS schema 变更必须走 Alembic**:索引、扩展、generated column、operator class 变更都要纳入 migration
|
||||
26. **章节生成必须优先使用 evidence bundle**:不得只凭当前会话上下文裸生成
|
||||
|
||||
## 依赖管理(uv)
|
||||
11. **依赖统一用 uv 管理**:禁止直接 `pip install`、禁止手动编辑 `pyproject.toml` 的 `[project.dependencies]` 或 `[dependency-groups]`
|
||||
12. **新增依赖用 `uv add <pkg>`**,dev 依赖用 `uv add --dev <pkg>`,移除用 `uv remove <pkg>`
|
||||
13. **`uv.lock` 必须纳入版本控制**:保证 CI 和本地环境精确一致
|
||||
14. **安装环境统一用 `uv sync`**:开发环境 `uv sync --dev`,生产环境 `uv sync --no-dev`
|
||||
15. **运行命令统一用 `uv run`**:如 `uv run pytest`、`uv run alembic upgrade head`、`uv run uvicorn ...`
|
||||
|
||||
30
.cursor/rules/Expo-ui.mdc
Normal file
30
.cursor/rules/Expo-ui.mdc
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: Expo UI 与 reusables CLI 规范
|
||||
globs: app-expo/src/**/*.{ts,tsx}
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Expo UI
|
||||
|
||||
- `app-expo` 页面开发默认假设存在刘海、状态栏、Home Indicator 和底部 Tab,不要把内容直接顶到屏幕边缘。
|
||||
- 根布局保持单一 `SafeAreaProvider`,放在 `app-expo/src/app/_layout.tsx` 一类的顶层布局中;不要在普通页面里重复包 provider。
|
||||
- 普通静态页面优先使用 `SafeAreaView` 作为页面内容外层容器。
|
||||
- 只有在需要精细控制顶部、底部、左右边距时,才使用 `useSafeAreaInsets()` 手动计算 `padding` 或 `contentInset`。
|
||||
- 带 `ScrollView`、底部固定操作栏、自定义 header、沉浸式背景的页面,必须显式处理 `top` 和 `bottom` inset。
|
||||
- 页面如果已经有底部 Tab,还要把 tab 占位和 `bottom` inset 一起考虑,避免按钮或正文被遮挡。
|
||||
- `react-native-reusables` 组件优先使用 CLI 添加,不要手抄文档代码。默认命令:`npx @react-native-reusables/cli@latest add <component>`。
|
||||
- 组件生成路径与别名以 `app-expo/components.json` 为准,UI 组件默认放在 `@/components/ui`,不要随意改散。
|
||||
- Web 可以按布局需要弱化 safe area 处理,但 iOS/Android 页面不能省略。
|
||||
- 禁止使用废弃 API:`useSafeArea`、`SafeAreaConsumer`、`SafeAreaContext`、`initialWindowSafeAreaInsets`。
|
||||
|
||||
```tsx
|
||||
// ❌ BAD
|
||||
export default function Page() {
|
||||
return <View style={{ flex: 1 }} />;
|
||||
}
|
||||
|
||||
// ✅ GOOD
|
||||
export default function Page() {
|
||||
return <SafeAreaView style={{ flex: 1 }}>{/* content */}</SafeAreaView>;
|
||||
}
|
||||
```
|
||||
41
.cursor/rules/app-expo-design-system.mdc
Normal file
41
.cursor/rules/app-expo-design-system.mdc
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
description: app-expo NativeWind utility-first 与 reusable 组件规范
|
||||
globs: app-expo/src/**/*.{ts,tsx}
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# App Expo Design System
|
||||
|
||||
- `app-expo/design-tokens.json` 是唯一静态设计源;当前包含语义颜色、字体家族、圆角基准值,以及少量跨端共享的静态布局值(`contentMaxWidth`、`screenGutter`)。
|
||||
- `@/constants/theme-bridge` 只服务于不能直接使用 NativeWind className 的运行时场景,例如旧 `Themed*` 组件、导航主题对象、第三方仅接受颜色值的 API。
|
||||
- `@/constants/layout` 放 layout/app shell 常量,例如 `MaxContentWidth`、`BottomTabInset`、`ScreenGutter`;其中 `BottomTabInset` 这类环境值不要塞回 design token。
|
||||
- 优先使用 NativeWind/Tailwind 原生 utility class 和默认 scale,不要先造一层新的排版或间距命名体系。
|
||||
- **禁止**在 `tailwind.config.js` 的 `theme.extend.spacing` 或 `theme.extend.borderRadius` 中注入 design-tokens 的自定义语义名(如 `tight`、`relaxed`、`card`、`card-compact`)。这会与 Tailwind 默认 scale 并行,违反 utility-first 原则。间距用 `gap-2/4/6`、`p-4/6`,圆角用 `rounded-lg/xl/2xl`。
|
||||
- 颜色优先使用语义 token,而不是调色板色名。常见包括:
|
||||
- 背景:`bg-background`、`bg-card`、`bg-popover`、`bg-muted`、`bg-accent`、`bg-primary`、`bg-secondary`、`bg-destructive`、`bg-success`、`bg-warning`、`bg-info`
|
||||
- 文字:`text-foreground`、`text-muted-foreground`、`text-card-foreground`、`text-popover-foreground`、`text-primary-foreground`、`text-secondary-foreground`、以及其他 `*-foreground`
|
||||
- 边框和焦点:`border-border`、`border-input`、`ring-ring`
|
||||
- 圆角优先使用 `rounded-sm/md/lg/xl`,它们由 `radius` token 派生;不要默认写 `rounded-[Npx]`。
|
||||
- 字号、行高、间距优先使用默认 utility:`text-sm/base/lg/xl`、`leading-5/6/7`、`p-2/4/6`、`gap-2/4/6`、`rounded-md/lg`。
|
||||
- 只有默认 scale 无法满足并且会被重复复用时,才增加少量自定义 token 或 utility,例如 `max-w-content`、`px-screen-gutter`、`border-hairline` 或少数语义颜色。
|
||||
- `@/components/ui/*` 里的 reusable/CLI 生成组件默认不要改;把它们当项目内基础件。
|
||||
- 如果需要定制,优先顺序是:传 `className` 覆盖、组合现有 `ui` 组件、新建业务 wrapper 组件;最后才改 `@/components/ui/*` 源码。
|
||||
- 不要重新引入 `ThemedText` / `ThemedView` 这类过渡包装层;新页面统一使用 NativeWind utility class 和 `@/components/ui/*`。
|
||||
- TypeScript 常量只保留 utility 不方便表达的场景;不要把常见字号、行高、间距重新包装成一套并行设计系统。
|
||||
- 如果要新增主题 token,先问一句:这是不是 NativeWind 现有 utility 已经能表达?能表达就直接用 utility。
|
||||
|
||||
```tsx
|
||||
// ✅ GOOD
|
||||
<Card className="bg-card">
|
||||
<Text variant="h3" className="text-foreground" />
|
||||
<Text className="text-base leading-6 text-muted-foreground" />
|
||||
<Button className="mt-4 rounded-lg">
|
||||
<Text>Continue</Text>
|
||||
</Button>
|
||||
</Card>
|
||||
|
||||
// ❌ BAD
|
||||
<View className="rounded-[18px] bg-white px-[22px] py-[13px]">
|
||||
<Text className="text-[23px] leading-[31px] text-slate-900">Title</Text>
|
||||
</View>
|
||||
```
|
||||
53
.cursor/rules/app-expo-responsive-design.mdc
Normal file
53
.cursor/rules/app-expo-responsive-design.mdc
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
description: app-expo 响应式设计规范(mobile-first)
|
||||
globs: app-expo/src/**/*.{ts,tsx}
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# App Expo Responsive Design
|
||||
|
||||
## 断点与数据源
|
||||
|
||||
- 断点定义在 `app-expo/design-tokens.json` 的 `layout.breakpoints`,是唯一数据源。
|
||||
- Tailwind/NativeWind 的 `sm:`、`md:` 等前缀从 design-tokens 读取,与 JS 共用同一套值。
|
||||
- 当前断点(mobile-first):`base` < 390px、`sm` ≥ 390px、`md` ≥ 768px、`lg` ≥ 1024px、`xl` ≥ 1280px、`2xl` ≥ 1536px。
|
||||
|
||||
## Mobile-first 原则
|
||||
|
||||
- 无前缀的 utility 作用于所有尺寸(最小屏优先)。
|
||||
- `sm:`、`md:` 等前缀表示「该断点及以上」生效。
|
||||
- 先实现 base 布局,再按 sm → md → lg 逐步增强。
|
||||
|
||||
```tsx
|
||||
// ✅ GOOD:base 居中,sm 及以上左对齐
|
||||
<View className="text-center sm:text-left" />
|
||||
|
||||
// ✅ GOOD:base 竖排,md 及以上横排
|
||||
<View className="flex flex-col md:flex-row" />
|
||||
|
||||
// ❌ BAD:sm: 不是「小屏」,而是「≥390px」
|
||||
<View className="sm:text-center" />
|
||||
```
|
||||
|
||||
## 何时用 Tailwind 类 vs Hooks
|
||||
|
||||
- **优先用 Tailwind 类**:布局、间距、字号、显示/隐藏等用 `sm:`、`md:` 前缀即可。
|
||||
- **需要 JS 分支时用 hooks**:`useBreakpointMatches`、`useBreakpointValue`、`isBreakpointUp`(来自 `@/hooks/use-breakpoint`)。
|
||||
|
||||
```tsx
|
||||
// ✅ GOOD:纯样式用 Tailwind
|
||||
<View className="flex flex-col md:flex-row gap-4 md:gap-6" />
|
||||
|
||||
// ✅ GOOD:逻辑分支用 hook
|
||||
const { isMd } = useBreakpointMatches();
|
||||
return isMd ? <TabletLayout /> : <MobileLayout />;
|
||||
|
||||
// ✅ GOOD:响应式取值用 useBreakpointValue
|
||||
const columns = useBreakpointValue({ base: 1, sm: 2, md: 3 });
|
||||
```
|
||||
|
||||
## 禁止
|
||||
|
||||
- 禁止在 `tailwind.config.js` 中硬编码断点,必须从 `design-tokens.json` 读取。
|
||||
- 禁止使用 Tailwind 默认 breakpoint(640/768/1024...)覆盖设计;项目已用 390/768/1024... 适配原生设备。
|
||||
- 禁止在 `layout.ts` 或业务代码中重复定义断点数值。
|
||||
Reference in New Issue
Block a user