docs: 新增技能文档
- 新增Skills.md技能说明 - 新增skills/技能文档目录 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
17
Skills.md
Normal file
17
Skills.md
Normal 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
21
skills/README.md
Normal 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 中的设计,保持体验一致。
|
||||||
|
- 复用到其他项目时,可按需裁剪(例如只保留认证 + 顶部栏 + 错误处理),并同步调整客户端与服务端约定。
|
||||||
|
- 业务相关逻辑(如回忆录、对话、付费等)不写入本目录,仅保留通用技术部分。
|
||||||
24
skills/android-navigation-routing.md
Normal file
24
skills/android-navigation-routing.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Skill:Android 路由与页面导航
|
||||||
|
|
||||||
|
与具体业务无关的 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)` 等,避免栈过深。
|
||||||
18
skills/api-backend-conventions.md
Normal file
18
skills/api-backend-conventions.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Skill:API 与后端约定
|
||||||
|
|
||||||
|
与具体业务无关的后端 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)`。
|
||||||
62
skills/auth-login-register.md
Normal file
62
skills/auth-login-register.md
Normal 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 } }`,保证回到登录且无法返回。
|
||||||
20
skills/bottom-navigation.md
Normal file
20
skills/bottom-navigation.md
Normal 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
27
skills/error-handling.md
Normal 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→AUTH,404→NOT_FOUND,5xx→SERVER 等。
|
||||||
|
- `getDisplayMessage` / `handleException`:统一得到最终展示文案。
|
||||||
|
|
||||||
|
## 组件
|
||||||
|
|
||||||
|
- **FriendlyErrorView**:全屏错误页,图标+标题+描述+重试/去登录按钮,可选动画。
|
||||||
|
- **FriendlyErrorDialog**:弹窗版,带确认/取消或重试。
|
||||||
|
- **InlineErrorMessage**:表单等内联错误,生产环境对部分技术性文案做友好替换。
|
||||||
|
- **Snackbar**:`showFriendlyError` 扩展,用于轻量提示。
|
||||||
|
|
||||||
|
## 约定
|
||||||
|
|
||||||
|
- 生产环境不直接暴露后端异常原文;开发环境可通过 `AppConfig.isDebugMode` 显示原始信息。
|
||||||
19
skills/system-bars.md
Normal file
19
skills/system-bars.md
Normal 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
23
skills/top-app-bar.md
Normal 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`。
|
||||||
Reference in New Issue
Block a user