docs: 新增技能文档

- 新增Skills.md技能说明
- 新增skills/技能文档目录

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
iammm0
2026-02-03 11:30:12 +08:00
parent 32534eca0e
commit 6526c08c3a
9 changed files with 231 additions and 0 deletions

17
Skills.md Normal file
View File

@@ -0,0 +1,17 @@
# 项目通用技术设计Skills
本文档已拆分为独立 Skill 文件,统一放在 **`skills/`** 目录下。
👉 **请查看 [skills/README.md](skills/README.md)** 获取完整索引与各块设计说明。
## 快速索引
| 设计块 | 文件 |
|--------|------|
| 登录与注册机制 | [skills/auth-login-register.md](skills/auth-login-register.md) |
| 顶部导航栏App Bar | [skills/top-app-bar.md](skills/top-app-bar.md) |
| 系统状态栏与导航栏 | [skills/system-bars.md](skills/system-bars.md) |
| 底部导航栏Tab 栏) | [skills/bottom-navigation.md](skills/bottom-navigation.md) |
| Android 路由与导航 | [skills/android-navigation-routing.md](skills/android-navigation-routing.md) |
| 错误处理 | [skills/error-handling.md](skills/error-handling.md) |
| API 与后端约定 | [skills/api-backend-conventions.md](skills/api-backend-conventions.md) |

21
skills/README.md Normal file
View File

@@ -0,0 +1,21 @@
# 项目通用技术设计Skills
本目录描述与本项目**具体业务无关**的技术设计与约定,供新功能开发、重构或跨项目复用时参考。
## Skill 列表
| Skill | 说明 |
|-------|------|
| [auth-login-register.md](auth-login-register.md) | 登录与注册机制(服务端 API + 客户端 Android |
| [top-app-bar.md](top-app-bar.md) | 顶部导航栏App Bar与透明化 |
| [system-bars.md](system-bars.md) | 系统状态栏与系统导航栏 |
| [bottom-navigation.md](bottom-navigation.md) | 底部导航栏Tab 栏) |
| [android-navigation-routing.md](android-navigation-routing.md) | Android 路由与页面导航 |
| [error-handling.md](error-handling.md) | 错误处理Android 友好错误展示) |
| [api-backend-conventions.md](api-backend-conventions.md) | API 与后端约定 |
## 使用约定
- 新增与「登录注册、导航栏、系统栏、路由、错误展示」相关的功能时,优先符合对应 Skill 中的设计,保持体验一致。
- 复用到其他项目时,可按需裁剪(例如只保留认证 + 顶部栏 + 错误处理),并同步调整客户端与服务端约定。
- 业务相关逻辑(如回忆录、对话、付费等)不写入本目录,仅保留通用技术部分。

View File

@@ -0,0 +1,24 @@
# SkillAndroid 路由与页面导航
与具体业务无关的 Android 路由与 NavHost 设计:路由定义、转场与返回栈。
---
## 路由定义
- 使用 **Screen** sealed class所有路由字符串集中定义`Screen.ConversationList.route``Screen.CreateMemory.createRoute(conversationId)` 等)。
## NavHost
-**AppNavigation** 中统一注册 `composable(route = ..., enterTransition = ..., exitTransition = ..., popEnterTransition = ..., popExitTransition = ...)`
- 转场动画由 **NavigationTransitions** 提供:水平进出(如 `slideInHorizontally``slideOutHorizontally`)、从左侧返回(`slideInHorizontallyFromLeft``slideOutHorizontallyToRight`)、淡入淡出、缩放等,按页面类型选用。
## 起始目的地
- `startDestination = if (isLoggedIn) Screen.ConversationList.route else Screen.Login.route`,与 TokenManager 的登录状态一致。
## 返回栈
- 登录后进入主界面:`popUpTo(Screen.Login.route) { inclusive = true }`
- 登出:`popUpTo(0) { inclusive = true }` 清空栈再 navigate 到 Login。
- Tab 切换时按设计选择 `popUpTo(ConversationList)` 等,避免栈过深。

View File

@@ -0,0 +1,18 @@
# SkillAPI 与后端约定
与具体业务无关的后端 API 与配置约定:前缀、敏感信息与数据库。
---
## 前缀与路由
- 认证:`/api/auth`
- 其他业务按模块分 router如 user、conversations、books、chapters 等),在 `main.py` 中挂载,统一带 `/api` 前缀时在挂载处配置。
## 敏感配置
- 环境变量中敏感项SECRET_KEY、API_KEY、PASSWORD、TOKEN 等)在日志中脱敏(只打 key 或前后几位)。
## 数据库
- 异步 SQLAlchemy + `get_async_db`;需当前用户时 `Depends(get_current_user)`

View File

@@ -0,0 +1,62 @@
# Skill登录与注册机制
与具体业务无关的认证设计:服务端 API 与客户端 Android 的登录、注册、令牌与鉴权约定。
---
## 服务端API
### 认证方式
- **访问令牌Access Token**JWT用于接口鉴权默认有效期 2 小时(`ACCESS_TOKEN_EXPIRE_MINUTES`)。
- **刷新令牌Refresh Token**:随机字符串,存库,默认 30 天有效;用于在访问令牌过期后换取新访问令牌。
### 密码
- 使用 **bcrypt** 哈希存储,不存明文。
- 注册/登录时由 `auth_service.hash_password` / `verify_password` 处理。
### 登录/注册入口
- 手机号 + 密码:`POST /api/auth/login``POST /api/auth/register`
- 手机号 + 短信验证码:`POST /api/auth/login/sms`(未注册则自动注册,需提供昵称)。
- 所有入口均要求请求体中 `agreed_to_terms == true`,否则 400。
### 令牌刷新
- `POST /api/auth/refresh`Body: `{ "refresh_token": "..." }`
- 校验:存在、未撤销、未过期、对应用户存在;通过后返回新的 `access_token``refresh_token` 原样返回(不轮换)。
### 鉴权依赖
- 需要登录的接口:`Depends(get_current_user)`,从 `Authorization: Bearer <access_token>` 解析 JWT校验 `type == "access"` 并加载用户。
- 可选登录:`Depends(get_optional_user)`,无 token 或无效时返回 `None`
### 路由与安全
- 认证相关路由统一前缀:`/api/auth`(如 login、register、refresh、logout 等)。
- OAuth2 约定:`OAuth2PasswordBearer(tokenUrl="/api/auth/login")`,仅用于声明从哪里取 token实际登录仍用上述接口。
---
## 客户端Android
### 令牌存储
- 使用 **DataStore Preferences**`TokenPreferences`)存 `access_token``refresh_token``user_id`
- 通过单例 **TokenManager** 读写;提供 `initialize(context)``saveTokens``getAccessToken`/`getRefreshToken`(含 suspend 与 sync 版本)、`clearTokens`
### 登录状态
- TokenManager 维护 `isLoggedIn`(有有效 access_token 即为 true并提供 `rememberIsLoggedIn()` 供 Compose 使用。
- 登出或刷新失败时调用 `clearTokens()``notifyTokenRefreshFailed()`,由回调统一处理(如清栈并跳转登录页)。
### 请求头与刷新
- 使用 **AuthInterceptor**Ktor Client 插件):请求前自动附加 `Authorization: Bearer <access_token>`
- 收到 401 时:用当前 refresh_token 调 `AuthService.refreshToken()`;成功则写回新 token失败则 `clearTokens()` + `notifyTokenRefreshFailed()`,由 App 层跳转登录。
### 登录成功/登出与导航
- 登录成功:由各登录入口回调 `onLoginSuccess`,主流程将 `isLoggedIn = true` 并导航到主界面(如会话列表),并 `popUpTo(Login)` 清掉登录页。
- 登出或刷新失败:`onLogout` / TokenManager 回调中执行 `navController.navigate(Screen.Login.route) { popUpTo(0) { inclusive = true } }`,保证回到登录且无法返回。

View File

@@ -0,0 +1,20 @@
# Skill底部导航栏Tab 栏)
与具体业务无关的底部 Tab 栏设计:显示条件、实现方式与选中态。
---
## 显示条件
- 仅在部分主 Tab 页显示:如会话列表、回忆录、我的(以 `Screen.ConversationList``Screen.MyMemoir``Screen.Profile` 等当前路由判断)。
- 子页如设置、关于、FAQ不显示底部栏。
## 实现
-`Scaffold.bottomBar` 中按 `currentRoute` 条件渲染底部栏;使用 `Surface` + `windowInsetsPadding(WindowInsets.navigationBars)` 避免与系统导航栏重叠。
- 底部项使用 **AppDestinations** 枚举(如 CHAT、MEMOIR、PROFILE每项含 label、icon点击时 `navController.navigate(对应 Screen.route)` 并配合 `popUpTo` 控制返回栈。
## 选中态
- 通过 `currentDestination` 与当前路由同步(`LaunchedEffect(currentRoute)`),保证高亮与实际页面一致。
- 可选:选中缩放/按下缩放等动画(如 `BottomNavItem` 中的 `animateFloatAsState`)。

27
skills/error-handling.md Normal file
View File

@@ -0,0 +1,27 @@
# Skill错误处理Android
与具体业务无关的 Android 错误展示设计:错误类型、友好文案与组件。
---
## 错误类型
- **ErrorType** 枚举NETWORK、SERVER、TIMEOUT、AUTH、NOT_FOUND、VALIDATION、UNKNOWN。
## ErrorHandler
- `getFriendlyError(errorType, originalMessage)`:生产环境返回友好文案,开发环境可带出 `originalMessage`(如 VALIDATION
- `detectErrorType(exception)`:根据异常 message 关键词推断类型。
- `detectErrorTypeByStatusCode(statusCode)`401/403→AUTH404→NOT_FOUND5xx→SERVER 等。
- `getDisplayMessage` / `handleException`:统一得到最终展示文案。
## 组件
- **FriendlyErrorView**:全屏错误页,图标+标题+描述+重试/去登录按钮,可选动画。
- **FriendlyErrorDialog**:弹窗版,带确认/取消或重试。
- **InlineErrorMessage**:表单等内联错误,生产环境对部分技术性文案做友好替换。
- **Snackbar**`showFriendlyError` 扩展,用于轻量提示。
## 约定
- 生产环境不直接暴露后端异常原文;开发环境可通过 `AppConfig.isDebugMode` 显示原始信息。

19
skills/system-bars.md Normal file
View File

@@ -0,0 +1,19 @@
# Skill系统状态栏与系统导航栏
与具体业务无关的系统栏设计:边缘到边缘、显示/隐藏与外观。
---
## 边缘到边缘
- `MainActivity``enableEdgeToEdge()``WindowCompat.setDecorFitsSystemWindows(window, false)`,内容可延伸到系统栏下。
## 显示/隐藏
- 使用 **SystemUiController** Composable`LaunchedEffect` 内通过 `WindowInsetsController``show`/`hide` 控制 `statusBars()``navigationBars()`
- 本项目主界面常将状态栏与导航栏隐藏(`isStatusBarVisible = false`, `isNavigationBarVisible = false`),由自定义顶部栏和底部栏替代。
## 行为与外观
- `systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE`:隐藏时仍可从边缘滑出临时显示。
- 图标颜色随主题:`isAppearanceLightStatusBars = !darkMode`,亮色主题用深色图标,暗色主题用浅色图标。

23
skills/top-app-bar.md Normal file
View File

@@ -0,0 +1,23 @@
# Skill顶部导航栏App Bar
与具体业务无关的顶部导航栏设计:透明化、状态栏占位与使用约定。
---
## 透明化
- 使用 **TransparentTopAppBar**Material3 TopAppBar 封装),支持三种模式:
- `FULLY_TRANSPARENT`:背景完全透明。
- `SEMI_TRANSPARENT`:半透明,可设 `alpha`
- `GRADIENT`:自上而下渐变透明(常用)。
- 已处理状态栏占位:`windowInsetsPadding(WindowInsets.statusBars)`
- 标题/返回/图标颜色需根据背景选:浅底用 `onSurface`,深色底用浅色,以保证可读性。
## 使用约定
- 普通页:在 `Scaffold.topBar` 中放 `TransparentTopAppBar`,按需选 `transparencyType``gradientColors`/`alpha`
- 聊天页等:可用 **ChatHeader**,通过 `isTransparent``transparencyType``alpha` 控制透明效果。
## 文档
- 详细用法见:`app-android/doc/透明化导航栏使用指南.md`