Files
flutter-template/CLAUDE.md
T

11 KiB
Raw Blame History

CLAUDE.md — Flutter 企业级脚手架(sunny_mochi

本文件为 Claude Code 提供项目上下文。所有 AI 辅助开发会话必须首先读取本文件 再按需加载 docs/ 下的补充文档。


项目身份信息

以下带 TODO 的字段由业务项目接手时填入,脚手架默认保留占位符。

字段 当前值(脚手架默认) 说明
项目名称 sunny_mochi TODO: 替换为实际项目名
Application ID (Android) com.example.sunny_mochi TODO: 如 com.company.projectname
Bundle ID (iOS) com.example.sunny-mochi TODO: 与 Android 对应
API Base URL (dev) http://localhost:8080 TODO: 填入 dart-defines/dev.json
API Base URL (staging) https://staging.example.com TODO: 填入 dart-defines/staging.json
API Base URL (prod) https://api.example.com TODO: 填入 dart-defines/prod.json
后端鉴权框架 sa-token(动态 header tokenName TODO: 若使用 Bearer/JWT 修改 auth_interceptor
Sentry DSN 空(未启用) TODO: 填入 dart-defines/prod.json
RSA 公钥 REPLACE_WITH_RSA_PUBLIC_KEY TODO: 填入三个 dart-defines JSON

技术栈(脚手架锁定版本)

分类 技术 版本
Flutter SDK Flutter ≥ 3.41.0
状态管理 Riverpod + riverpod_annotation ^3.3.0 / ^4.0.0
路由 GoRouter + 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 Slang ^4.0.0
UI 自适应 flutter_screenutil(基准 375×812 ^5.9.0
图片缓存 cached_network_image ^3.4.0
字体 HarmonyOS Sans SCRegular/Medium/Bold/Black GB2312 子集

版本锁定原因(勿随意升级):

  • drift: 2.31.0 — 2.32+ 需要 analyzer ^10.x,与 riverpod_generator 的 analyzer ^9.x 冲突
  • json_serializable: 6.13.0 — 6.13.1+ 同样需要 analyzer ^10.x

目录结构

lib/
├── main.dart                 # 6步启动序列(顺序固定,勿调整)
├── app.dart                  # AppRoot → ScreenUtilInit → App → MaterialApp.router
├── i18n/                     # Slang 翻译(zh-CN 基准 + en 备用)
├── core/
│   ├── config/
│   │   ├── env.dart          # 从 dart-defines 读取环境变量(只读,勿改结构)
│   │   ├── api_config.dart   # baseUrl 按 Flavor 决策
│   │   └── api_paths.dart    # ★ 新项目必填:所有 API 路径常量
│   ├── router/
│   │   ├── app_router.dart   # GoRouter providerkeepAlive
│   │   └── routes.dart       # ★ 新项目扩展:添加 @TypedGoRoute
│   ├── network/
│   │   ├── dio_client.dart   # 7 拦截器注册(顺序固定)
│   │   ├── api_response.dart # 统一 envelope 解析(parseEnvelope / unwrapVoid
│   │   ├── response_code.dart# 业务状态码(成功=00000token 类码分类)
│   │   ├── interceptors/     # 7 个拦截器(勿修改拦截顺序)
│   │   └── mock/             # MockAdapter + fixture JSONdev 调试用)
│   ├── storage/
│   │   ├── app_database.dart # Drift @DriftDatabaseschemaVersion 从 1 开始)
│   │   ├── secure_storage.dart# token / userId / tokenName 的唯一真源
│   │   ├── db_key_provider.dart# AES-256 密钥派生(勿修改策略)
│   │   ├── tables/           # Drift 表定义(Users + ErrorLogs + 业务表)
│   │   └── daos/             # DAO(只放纯 DB 操作)
│   ├── crash/                # CrashReporterpreInit/consumePending/installHooks
│   ├── error/
│   │   ├── failures.dart     # Sealed Failure 层级(唯一错误分类)
│   │   └── exception_mapper.dart # 异常 → Failure 映射
│   ├── theme/                # 5 色板 + 深色模式(ThemeNotifier + SharedPreferences
│   ├── observability/        # Talker(全局 appTalker+ SentryRelease 上报)
│   ├── sync/                 # Offline-First 同步框架骨架(SyncService
│   ├── crypto/               # RSA PKCS#1 v1.5RsaHelper.encrypt
│   ├── extensions/           # BuildContextX / StringX / NumX / DateTimeX
│   ├── utils/                # Validator / PasswordValidator / SmsCountdownMixin
│   ├── data/                 # FreshnessPolicy(缓存新鲜度判断)
│   └── widgets/              # 通用 UI 组件(AppToast / AppButton / EmptyView 等)
└── features/
    ├── auth/                 # ★ 认证(完整骨架,业务项目修改 LoginPage UI
    ├── dev_panel/            # Talker 面板(Internal 包,勿在 release 中暴露入口)
    └── error_report/         # 本地错误日志 + 上报(完整实现)

开发命令

# 代码生成(修改 Dart 文件后运行)
make gen

# i18n 生成(修改 JSON 翻译文件后运行)
make gen-i18n

# 运行
make run-dev          # dev 包(连 dev 服务器,mock 可开)
make run-staging      # staging 包(连 test 服务器,release 模式)

# 构建
make build-apk-dev    # dev APK(快速真机验证)
make build-staging    # staging APK(交测试团队)
make build-prod       # prod AAB(需 prod.json + key.properties

# 质量检查
flutter analyze       # 目标 0 errors103 条 info 为正常)
flutter test          # 全量测试

常用开发范式

新增 Feature

lib/features/{feature_name}/
├── 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,实现 domain 接口
└── presentation/
    ├── notifiers/{name}_notifier.dart  # @riverpod class XxxNotifier
    └── pages/{name}_page.dart          # ConsumerWidget / ConsumerStatefulWidget

新增路由

lib/core/router/routes.dart 添加(然后运行 make gen):

@TypedGoRoute<MyNewRoute>(path: '/my-new-path')
class MyNewRoute extends GoRouteData with $MyNewRoute {
  const MyNewRoute();

  @override
  Widget build(BuildContext context, GoRouterState state) => const MyNewPage();
}

新增 API 路径

lib/core/config/api_paths.dart 添加:

// ============== My Feature ==============
static const String myFeatureList = '/api/v1/my-feature/list';

新增 DB 表

  1. lib/core/storage/tables/ 新建表文件
  2. lib/core/storage/app_database.dart@DriftDatabase(tables: [...]) 添加
  3. 递增 schemaVersion 并在 MigrationStrategy.onUpgrade 中添加迁移
  4. 运行 make gen

错误处理标准模式

// 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!);
});

零容忍规则(AI 必须遵守)

规则 正确 禁止
API 路径 ApiPaths.xxx 常量 字符串字面量散落在代码中
错误处理 ExceptionMapper().fromUnknown(e, st) catch 直接 toString() 显示
Token 存储 SecureStorageKeychain/EncryptedPrefs 普通 SharedPreferences
数据库加密 SQLCipher(默认) 无加密 sqflite
日志输出 appTalker.info/warning/error() print() / debugPrint()
路由跳转 XxxRoute().go(context) / XxxRoute().push(context) Navigator.push()
状态管理 Riverpod @riverpod / @Riverpod(keepAlive: true) setState 跨组件共享 / Provider
Riverpod 命名 生成 provider 名(AuthNotifierauthProvider 手写 authNotifierProvider
代码生成文件 只读,不手写 .g.dart / .freezed.dart 手动修改生成文件
Domain 层 纯 Dart,无 Flutter / Drift / Dio 依赖 domain 层 import package:dio
Mock fixture assets/fixtures/{group}/{name}.json 在代码中硬编码 mock 数据
注释语言 中文(团队约定) 英文注释(除公共 API doc

关键架构决策(勿重议)

  1. SQLCipher 不可替换:企业合规要求,部署后无法无损切换到无加密数据库
  2. 7 拦截器顺序固定CertPinning→Auth→TokenRefresh→Retry→Error→AuthLogout→Log,错误处理链依赖此顺序
  3. TokenRefresh 使用 Completer 互斥:防止并发 401 重复消耗 RefreshToken,不可改为简单 flag
  4. SecureStorage 是 token 唯一真源DB 中的 refreshToken 仅作可观测性镜像
  5. GoRouter 用 ref.read(非 ref.watch)构建router 是 keepAlive 单例,通过 refreshListenable 响应 auth 变化
  6. Failure 不可绕过:所有网络/DB 异常必须经 ExceptionMapper 映射,UI 只看 Failure.message

新项目接手 Checklist

完成后删除本节或移至项目 wiki

  • 更新本文件"项目身份信息"表格
  • 填入 lib/core/config/api_paths.dart 所有路径
  • 配置三个 dart-defines/*.json(含 RSA 公钥、Sentry DSN
  • 修改 android/app/build.gradle.kts 中的 applicationId
  • 修改 pubspec.yaml 中的 name(含相关 import 路径)
  • 完成 docs/setup-android.md 中的 Android 签名配置
  • 完成 docs/setup-ios.md 中的 iOS Scheme / Signing 配置
  • 替换登录页 UI 品牌(lib/features/auth/presentation/pages/login_page.dart
  • 替换 App IconAndroid mipmap / iOS AppIcon.appiconset
  • 实现业务 Tab 页面(替换 routes.dart 中的 placeholder build
  • 更新 README.md 项目描述

参考文档

文档 内容
README.md 项目概述、技术栈、快速开始
docs/setup-project.md 完整项目配置指南(所有开发者必读)
docs/setup-android.md Android Flavor / 签名 / 构建详细配置
docs/setup-ios.md iOS Scheme / CocoaPods / 签名详细配置