Files
flutter-template/CLAUDE.md
T
SkyJourney b8b63282ee fix: 清除 platform-flutter 残留代码,重构文档与开发者体验
P0 代码修复:删除 imSdkAppId、清除内网 IP 与原项目域名、修正 USE_MOCK 默认值
P1 CLAUDE.md 重组:零容忍规则前置,新增 dart-defines 字段对照表
P2 文档优化:先跑再配的 setup 流程,新增 architecture.md 架构图
2026-05-14 13:21:06 +08:00

239 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md — Flutter 企业级脚手架(sunny_mochi
> 本文件为 Claude Code 提供项目上下文。**每次新会话首先读取本文件**,
> 需要时再按需加载 `docs/` 下的补充文档。
---
## ⚡ 30 秒上手(开箱即用验证)
```bash
flutter pub get && make gen && make gen-i18n
# dev.json 默认 USE_MOCK=true,无需后端即可运行:
make run-dev
# 期望结果:App 启动 → 显示登录页 → 右上角可进 Dev PanelTalker 日志)
```
**这是脚手架,不是完整 App**。以下内容"需要业务项目填写":
- `lib/core/config/api_paths.dart` — 所有路径均为空字符串
- `lib/core/config/api_config.dart` — 三套 baseUrl 均为 localhost 占位符
- `dart-defines/*.json` — RSA 公钥 / Sentry DSN 均为占位符
---
## 项目身份信息
> **业务项目接手后,将下表 TODO 字段替换为真实值,AI 才能给出精准建议。**
| 字段 | 当前值(脚手架占位)| 说明 |
|------|-----------------|------|
| 项目名称 | sunny_mochi | TODO: 替换为实际项目名 |
| Application ID | com.example.sunny_mochi | TODO: 如 com.company.appname |
| API Base URL (dev) | http://localhost:8080 | TODO: 改 api_config.dart + dev.json |
| API Base URL (staging) | https://staging.your-domain.com | TODO: 改 api_config.dart |
| API Base URL (prod) | https://api.your-domain.com | TODO: 改 api_config.dart |
| 后端鉴权框架 | sa-token(动态 tokenName header| TODO: 若用 Bearer JWT 改 auth_interceptor |
| Sentry DSN | 空(不上报)| TODO: prod.json |
| RSA 公钥 | 空(加密跳过)| TODO: 三个 dart-defines JSON |
---
## 零容忍规则(必须遵守,不可商量)
| 规则 | ✅ 正确 | ❌ 禁止 |
|------|---------|---------|
| API 路径 | `ApiPaths.xxx` 常量 | 字符串字面量散落代码中 |
| 错误处理 | `ExceptionMapper().fromUnknown(e, st)` | 裸 `catch (e)` 直接 `toString()` 显示 |
| Token 存储 | `SecureStorage`Keychain / EncryptedPrefs| 普通 `SharedPreferences` |
| 数据库加密 | SQLCipher(默认,禁止替换)| 无加密 sqflite |
| 日志 | `appTalker.info/warning/error()` | `print()` / `debugPrint()` |
| 路由跳转 | `XxxRoute().go(context)` | `Navigator.push()` |
| 状态管理 | `@riverpod` / `@Riverpod(keepAlive: true)` | `setState` 跨组件 / Provider 包 |
| Riverpod provider 命名 | 生成名(`AuthNotifier``authProvider`| 手写 `authNotifierProvider` |
| 生成文件 | 只读,运行 `make gen` 刷新 | 手动修改 `.g.dart` / `.freezed.dart` |
| Domain 层依赖 | 纯 Dart,无 Flutter/Drift/Dio | domain 层 `import 'package:dio'` |
---
## 禁止修改的文件(架构决策,除非全面评估影响)
```
lib/core/network/dio_client.dart # 7 拦截器顺序固定,顺序即语义
lib/core/storage/db_key_provider.dart # AES-256 密钥派生策略,改动会破坏已有 DB
lib/core/error/failures.dart # 全局错误分类,改 sealed 影响所有 switch
lib/core/network/response_code.dart # 业务码分类,影响 TokenRefresh 互斥逻辑
```
---
## dart-defines 字段完整对照表
| JSON 键 | `Env.dart` 读取字段 | 类型 | 说明 |
|---------|-------------------|------|------|
| `ENV` | `Env.name` | String | `dev` / `test` / `release` |
| `API_BASE_URL` | `Env.apiBaseUrlOverride` | String | 留空则用 api_config.dart 中的固定 URL |
| `USE_MOCK` | `Env.useMock` | bool | `true` = 走 MockAdapter,无需后端 |
| `INTERNAL_BUILD` | `Env.isInternalBuild` | bool | `true` = 显示 Dev Panel 入口 |
| `SENTRY_DSN` | `Env.sentryDsn` | String | 留空时 Sentry 自动跳过 |
| `PINNED_FINGERPRINTS` | `Env.pinnedFingerprints` | List | 逗号分隔的 SHA-256 指纹,留空跳过 SSL 绑定 |
| `RSA_PUBLIC_KEY` | `Env.rsaPublicKey` | String | DER-SPKI Base64,留空时密码不加密传输 |
---
## 技术栈(脚手架锁定版本)
| 分类 | 技术 | 版本 |
|------|------|------|
| 状态管理 | flutter_riverpod + riverpod_annotation | ^3.3.0 / ^4.0.0 |
| 路由 | go_router + go_router_builder | ^17.0.0 / ^4.3.0 |
| 网络 | Dio | ^5.9.0 |
| 本地数据库 | Drift + SQLCipher | **2.31.0(锁定)** |
| 安全存储 | flutter_secure_storage | ^10.0.0 |
| 序列化 | Freezed + json_serializable | ^3.x / **6.13.0(锁定)** |
| 日志 | Talker + talker_flutter | ^5.x |
| 错误追踪 | sentry_flutter | ^9.0.0 |
| i18n | Slangbase_locale: zh-CN| ^4.0.0 |
| UI 自适应 | flutter_screenutil(基准 375×812| ^5.9.0 |
> `drift: 2.31.0` 和 `json_serializable: 6.13.0` 锁定原因:
> 更新版本需要 analyzer ^10.x,与 riverpod_generator 的 analyzer ^9.x 冲突。**勿升级。**
---
## 目录结构与关键文件
```
lib/
├── main.dart # 启动序列(固定顺序:preInit→consumePending→SentryInit→installHooks
├── app.dart # AppRoot → ScreenUtilInit(375×812) → App → MaterialApp.router
├── i18n/ # Slang 翻译(zh-CN 基准 + en 备用)
├── core/
│ ├── config/
│ │ ├── env.dart # ← 读取 dart-defines,只读
│ │ ├── api_config.dart # ★ 填入三套环境 baseUrl
│ │ └── api_paths.dart # ★ 填入所有 API 路径常量
│ ├── router/
│ │ ├── app_router.dart # GoRouter providerref.read + refreshListenable
│ │ └── routes.dart # ★ 添加业务 @TypedGoRoute(然后 make gen
│ ├── network/
│ │ ├── dio_client.dart # 7 拦截器(禁止改顺序)
│ │ ├── api_response.dart # envelope 解析(parseEnvelope / unwrapVoid
│ │ ├── response_code.dart # 业务状态码(成功=00000,token 类码分类)
│ │ ├── interceptors/ # 7 个拦截器(禁止改顺序)
│ │ └── mock/ # USE_MOCK=true 时生效,读 assets/fixtures/
│ ├── storage/
│ │ ├── app_database.dart # schemaVersion=1@DriftDatabase([Users, ErrorLogs])
│ │ ├── secure_storage.dart # token / userId / tokenName 的唯一真源
│ │ ├── db_key_provider.dart # AES-256 密钥派生(禁止改策略)
│ │ ├── tables/ # ★ 业务项目在此添加 Drift 表
│ │ └── daos/ # DAO(只放纯 DB 操作)
│ ├── error/
│ │ ├── failures.dart # sealed Failure(禁止改结构)
│ │ └── exception_mapper.dart # 异常 → Failure 映射 + Riverpod provider
│ └── widgets/ # AppToast / AppButton / EmptyView / AvatarWidget 等
└── features/
├── auth/ # ★ 修改 LoginPage UI 品牌,业务路由骨架已就绪
├── dev_panel/ # Talker 面板(INTERNAL_BUILD=true 时可路由进入)
└── error_report/ # 本地错误日志 + 批量上报(完整实现)
```
---
## 常用开发范式
### 新增 Feature(标准目录结构)
```
lib/features/{feature}/
├── domain/
│ ├── entities/{name}_entity.dart # @freezed,纯 Dart
│ └── repositories/{name}_repository.dart # abstract interface
├── data/
│ ├── models/{name}_model.dart # @freezed + fromJson + toEntity()
│ ├── datasources/{name}_remote_datasource.dart # @riverpod,只用 Dio
│ └── repositories/{name}_repository_impl.dart # @riverpod,实现接口
└── presentation/
├── notifiers/{name}_notifier.dart # @riverpod class XxxNotifier
└── pages/{name}_page.dart # ConsumerWidget
```
### 新增路由(routes.dart → make gen
```dart
@TypedGoRoute<MyRoute>(path: '/my-path')
class MyRoute extends GoRouteData with $MyRoute {
const MyRoute();
@override
Widget build(BuildContext context, GoRouterState state) => const MyPage();
}
```
### 标准错误处理
```dart
// Notifier 层
} on Object catch (e, st) {
final failure = ExceptionMapper().fromUnknown(e, st);
state = MyState.error(failure.message);
}
// UI 层
ref.listen(myProvider, (_, next) {
if (next is AsyncError) context.showError(ref, next.error!, next.stackTrace!);
});
```
### 新增 DB 表
1. `lib/core/storage/tables/{name}_table.dart` — 定义 `@DataClassName` + 字段
2. `app_database.dart``@DriftDatabase(tables: [..., NewTable])` + 递增 schemaVersion + 添加 onUpgrade 迁移
3. `lib/core/storage/daos/{name}_dao.dart``@DriftAccessor(tables: [NewTable])`
4. 运行 `make gen`
---
## 开发命令
```bash
make gen # build_runner → .g.dart / .freezed.dart(改 Dart 文件后必跑)
make gen-i18n # slang → lib/i18n/strings.g.dart(改翻译 JSON 后必跑)
make run-dev # dev 包(USE_MOCK=true,无需后端)
make run-staging # staging 包(连 test 服务器)
make build-staging# staging APK
make build-prod # prod AAB(需先配置 prod.json + key.properties
flutter analyze # 目标 0 errors(当前正常 info 数约 103 条)
flutter test # 全量测试
```
---
## 新项目接手 Checklist
> 完成并删除本节(或移至项目 wiki)
- [ ] 更新本文件"项目身份信息"表格(让 AI 上下文准确)
- [ ] 修改 `lib/core/config/api_config.dart` 三套 baseUrl
- [ ] 填入 `lib/core/config/api_paths.dart` 所有路径
- [ ] 配置三个 `dart-defines/*.json`RSA 公钥 / Sentry DSN
- [ ] 修改 Android 包名:`android/app/build.gradle.kts` applicationId
- [ ] 修改 iOS Bundle IDXcode → Runner Target → General
- [ ] 修改 `pubspec.yaml` name 并批量替换 import 路径(见 setup-project.md Step 5
- [ ] Android 签名:`cp android/key.properties.template android/key.properties` 并填写
- [ ] iOS 签名:Xcode → Signing & Capabilities(见 setup-ios.md
- [ ] 替换登录页 UI 品牌(`lib/features/auth/presentation/pages/login_page.dart`
- [ ] 替换 App IconAndroid mipmap / iOS AppIcon.appiconset
- [ ] 实现 Tab 页面(`lib/core/router/routes.dart` HomeRoute / MineRoute 的 build
- [ ] 更新 README.md 项目描述和快速开始地址
---
## 参考文档
| 文档 | 内容 |
|------|------|
| [README.md](../README.md) | 项目概述、技术栈、基础设施一览 |
| [docs/setup-project.md](setup-project.md) | 完整配置指南(dart-defines / 包名 / 首次运行)|
| [docs/setup-android.md](setup-android.md) | Android Flavor / 签名 / 构建 / CI |
| [docs/setup-ios.md](setup-ios.md) | iOS Scheme / CocoaPods / 证书 / Archive |
| [docs/architecture.md](architecture.md) | 数据流 / 认证流 / 错误链 ASCII 架构图 |