expo-duooomi-app/.github/copilot-instructions.md

496 lines
13 KiB
Markdown

# Duooomi Expo App - Copilot Instructions
## 项目概述
这是一个基于 Expo + React Native 的跨平台移动应用,使用 TypeScript 开发,集成了蓝牙设备通信、模板生成、用户认证等核心功能。项目采用 Monorepo 架构,使用 Bun 作为包管理器。
## 技术栈
### 核心框架
- **Expo SDK 54** - 跨平台开发框架
- **React 19.1.0** - UI 框架
- **React Native 0.81.5** - 原生渲染
- **Expo Router** - 文件系统路由
- **TypeScript 5.9** - 类型安全
### 状态管理与数据
- **MobX 6** + **mobx-react-lite** - 响应式状态管理
- **Better Auth** - 身份认证
- **AsyncStorage** - 本地存储
### UI 与样式
- **NativeWind 4** - Tailwind CSS for React Native
- **Tailwind CSS 3.4** - 原子化 CSS
- **tailwind-variants** - 变体管理
- **class-variance-authority** - CVA 工具
- **Expo Linear Gradient** - 渐变效果
### 蓝牙与设备
- **react-native-ble-plx** - BLE 中心设备
- **react-native-multi-ble-peripheral** - BLE 外设
- **自定义协议层** (`ble/protocol/`)
### 媒体与资源
- **Expo Image** - 图片处理
- **Expo Image Picker** - 相册选择
- **react-native-video** - 视频播放
- **Expo Media Library** - 媒体库访问
### 支付与内购
- **Expo IAP** - 应用内购买
- **Stripe** - 支付集成
- **Expo Native Alipay / WeChat** - 第三方支付
### 开发工具
- **ESLint 9** - 代码检查
- **Prettier** - 代码格式化
- **Sentry** - 错误监控
- **EAS Build & Update** - 云构建与 OTA 更新
## 项目结构
```
expo-duooomi-app/
├── app/ # Expo Router 路由页面
│ ├── (tabs)/ # 主 Tab 导航
│ │ ├── index.tsx # 首页(模板列表)
│ │ ├── explore.tsx # 探索页(测试功能)
│ │ ├── generate.tsx # 生成页(AI 生成)
│ │ └── sync.tsx # 同步页(设备同步)
│ ├── _layout.tsx # 根布局
│ ├── auth.tsx # 登录页
│ ├── service.tsx # 服务条款
│ └── pointList.tsx # 积分充值
├── components/ # 通用 UI 组件
│ ├── ui/ # UI 基础组件
│ ├── themed-*/ # 主题化组件
│ └── BannerSection.tsx # 业务组件
├── hooks/ # React Hooks
│ ├── actions/ # 业务操作 hooks
│ ├── core/ # 核心 hooks
│ └── data/ # 数据获取 hooks
├── stores/ # MobX 状态管理
│ ├── bleStore.ts # 蓝牙状态
│ ├── userStore.ts # 用户状态
│ └── userBalanceStore.ts # 用户余额
├── ble/ # 蓝牙模块
│ ├── protocol/ # 协议定义
│ │ ├── types.ts # 类型定义(Zod)
│ │ └── utils.ts # 协议工具
│ ├── managers/ # 管理器
│ │ └── bleManager.ts # BLE 中心管理
│ └── flows/ # 业务流程
├── utils/ # 工具函数
│ ├── cn.ts # className 工具
│ ├── uploadFile.ts # 文件上传
│ └── storage.ts # 本地存储
├── lib/ # 第三方库封装
│ └── auth.ts # Better Auth 客户端
├── constants/ # 常量定义
├── @share/ # Monorepo 共享模块
│ ├── components/ # 共享组件
│ ├── hooks/ # 共享 hooks
│ └── apis/ # API 封装
├── assets/ # 静态资源
├── scripts/ # 构建脚本
│ └── export-icp-source.ts # ICP 备案导出
├── .env.development # 开发环境变量
├── .env.test # 测试环境变量
├── .env.production # 生产环境变量
├── eas.json # EAS 构建配置
├── app.config.js # Expo 应用配置
└── AGENTS.md # AI Agent 协作规范
```
## 代码规范
### 命名约定
#### 文件命名
- **路由页面**: `kebab-case.tsx``camelCase.tsx` (如 `pointList.tsx`, `point-list.tsx`)
- **组件文件**: `PascalCase.tsx` (如 `BannerSection.tsx`)
- **Hooks**: `camelCase.ts``kebab-case.ts` (如 `useTemplates.ts`, `use-template-actions.ts`)
- **工具函数**: `camelCase.ts` (如 `uploadFile.ts`)
- **类型文件**: `types.ts`
- **常量文件**: `camelCase.ts`
#### 变量与函数命名
- **组件**: `PascalCase` (`BannerSection`, `ThemedText`)
- **Hook 函数**: `camelCase``use` 开头 (`useTemplates`, `useUserBalance`)
- **普通函数**: `camelCase` (`uploadFile`, `cn`)
- **常量**: `SCREAMING_SNAKE_CASE` (`BLE_UUIDS`, `APP_VERSION`)
- **枚举/对象常量**: `SCREAMING_SNAKE_CASE` (`PREPARE_TRANSFER_STATUS`)
- **类型/接口**: `PascalCase` (`Template`, `MediaItem`, `SourceLine`)
- **Store 实例**: `camelCase` (`bleStore`, `userStore`)
### TypeScript 规范
#### 类型定义
```typescript
// 使用 Zod 进行运行时校验
import { z } from 'zod'
export const PrepareTransferRequestZod = z.object({
type: z.number().describe('命令类型 0x14'),
key: z.string().describe('资源 key'),
size: z.number().describe('文件大小(bytes)'),
})
export type PrepareTransferRequest = z.infer<typeof PrepareTransferRequestZod>
// 接口定义
interface SourceLine {
content: string
filePath: string
lineNumber: number
isFileHeader: boolean
isFileEnd: boolean
}
// 类型别名
type ActiveTab = 'gen' | '' | 'new' | 'like'
```
#### 严格模式
- 启用 `strict: true`
- 避免使用 `any`,优先使用 `unknown` 或明确类型
- 使用可选链 (`?.`) 和空值合并 (`??`)
### 样式规范
#### Tailwind CSS / NativeWind
```tsx
// 使用 className 而非内联样式
<Block className="flex-row items-center justify-between px-4 py-2">
<Text className="text-sm font-bold text-white">标题</Text>
</Block>
// 使用 cn() 工具合并条件样式
import { cn } from '@/utils/cn'
<Block className={cn(
"border-2 bg-white p-4",
isSelected && "border-accent",
isDisabled && "opacity-50"
)}>
```
#### 避免内联样式
- **不推荐**: `style={{ width: 100, height: 100 }}`
- **推荐**: `className="w-[100px] h-[100px]"`
- **例外**: 动态计算的值可以使用 style (如 `style={{ width: itemWidth }}`)
### React 规范
#### 组件定义
```typescript
// 函数组件 + TypeScript
import { observer } from 'mobx-react-lite'
import React from 'react'
type Props = {
title: string
onPress?: () => void
isActive?: boolean
}
export const MyComponent = observer(function MyComponent({
title,
onPress,
isActive = false
}: Props) {
return (
<Block onPress={onPress}>
<Text>{title}</Text>
</Block>
)
})
```
#### Hooks 使用
```typescript
// 自定义 Hook
export function useTemplates() {
const [data, setData] = useState<Template[]>([])
const [loading, setLoading] = useState(false)
const execute = useCallback(async () => {
setLoading(true)
try {
const result = await api.getTemplates()
setData(result)
} finally {
setLoading(false)
}
}, [])
return { data, loading, execute }
}
```
### MobX 规范
```typescript
// Store 定义
import { makeAutoObservable, runInAction } from 'mobx'
class UserStore {
user: User | null = null
isLogin = false
constructor() {
makeAutoObservable(this)
}
async login(credentials: Credentials) {
const user = await authApi.login(credentials)
runInAction(() => {
this.user = user
this.isLogin = true
})
}
}
export const userStore = new UserStore()
// 组件使用
import { observer } from 'mobx-react-lite'
export const Profile = observer(function Profile() {
const { user, isLogin } = userStore
if (!isLogin) return <Login />
return <Text>{user.name}</Text>
})
```
### 导入规范
```typescript
// 使用 @ 别名
import { Block, Text } from '@/@share/components'
import { useTemplates } from '@/hooks/data'
import { userStore } from '@/stores'
import { cn } from '@/utils/cn'
// 按类型分组排序(自动由 eslint-plugin-simple-import-sort 处理)
// 1. React 相关
// 2. 第三方库
// 3. 绝对路径导入 (@/)
// 4. 相对路径导入 (./)
// 5. 类型导入
```
### 组件库使用
```tsx
// 使用 @share/components 中的组件,而非 react-native 原生组件
// ✅ 推荐
import { Block, Text, Img } from '@/@share/components'
// ❌ 避免
import { View, Text, Image } from 'react-native'
// Block 替代 View
<Block className="flex-1 bg-white">
<Text>内容</Text>
</Block>
// Toast 统一使用项目封装的版本
import { Toast } from '@/@share/components'
Toast.show({ title: '操作成功' })
Toast.showLoading({ title: '加载中...' })
Toast.hideLoading()
Toast.showModal(<CustomModal />)
Toast.hideModal()
```
### 错误处理
```typescript
// 统一错误处理
try {
await api.uploadFile(file)
Toast.show({ title: '上传成功' })
} catch (error) {
console.error('上传失败:', error)
Toast.show({ title: error instanceof Error ? error.message : '上传失败' })
}
// Sentry 错误上报
import * as Sentry from '@sentry/react-native'
try {
// ...
} catch (error) {
Sentry.captureException(error)
throw error
}
```
## 最佳实践
### 组件设计
1. **单一职责**: 每个组件只做一件事
2. **Props 设计**: 明确的 Props 类型,合理的默认值
3. **记忆化**: 使用 `memo`, `useMemo`, `useCallback` 优化性能
4. **条件渲染**: 提前返回,减少嵌套
```typescript
// 提前返回
if (!isLogin) return <Login />
if (loading) return <Loading />
return <Content />
```
### 性能优化
```typescript
// 使用 FlashList 代替 FlatList
import { FlashList } from '@shopify/flash-list'
<FlashList
data={items}
renderItem={({ item }) => <Item data={item} />}
estimatedItemSize={100}
/>
// 图片优化
import { Img } from '@/@share/components'
<Img
src={uri}
className="w-full h-full"
isCompression
/>
```
### 蓝牙通信
```typescript
// 使用 bleManager 管理 BLE 连接
import { bleManager } from '@/ble/managers/bleManager'
// 扫描设备
await bleManager.startScan()
// 连接设备
await bleManager.connectToDevice(device)
// 发送数据
await bleManager.transferMediaSingle(fileUrl)
// 断开连接
await bleManager.disconnectDevice()
```
### 状态管理
- **本地 UI 状态**: 使用 `useState`
- **跨组件状态**: 使用 MobX Store
- **服务端状态**: 使用自定义 Hook (如 `useTemplates`)
- **持久化状态**: 使用 `AsyncStorage``expo-secure-store`
### 环境变量
```typescript
// 访问环境变量
const apiUrl = process.env.EXPO_PUBLIC_API_URL
const env = process.env.EXPO_PUBLIC_ENV // 'development' | 'test' | 'production'
// 根据环境执行不同逻辑
if (__DEV__) {
console.log('开发模式')
}
```
## 常用命令
```bash
# 安装依赖
bun install
# 启动开发服务器
bun run start # 开发环境
bun run start:test # 测试环境
bun run start:prod # 生产环境
# 运行平台
bun run android # Android
bun run ios # iOS
bun run web # Web
# 构建
bun run build:development:android
bun run build:production:ios
# OTA 更新
bun run update:production
# 代码检查
bun run lint
# ICP 备案导出
bun run export:icp:android
bun run export:icp:ios
# Prebuild
bun run prebuild:android
```
## 注意事项
1. **不要过度设计**: 优先简单直接的解决方案
2. **代码即文档**: 通过清晰的命名和结构表达意图,避免无用注释
3. **类型安全**: 充分利用 TypeScript,减少运行时错误
4. **性能优先**: 注意列表渲染、图片加载、状态更新的性能
5. **测试覆盖**: 为核心功能编写测试(当前项目暂无测试框架)
6. **错误监控**: 关键操作使用 Sentry 上报错误
7. **国际化准备**: 使用 `i18next` 管理多语言(已集成但未完全启用)
## 平台差异处理
```typescript
// 使用 Platform 处理平台差异
import { Platform } from 'react-native'
const isIOS = Platform.OS === 'ios'
const isAndroid = Platform.OS === 'android'
// 平台特定样式
<Block className={cn(
"p-4",
isIOS && "pt-8",
isAndroid && "pt-4"
)}>
// 平台特定文件
// pointList.native.tsx - 原生平台
// pointList.tsx - Web 平台
```
## AI Agent 协作
项目采用"千门八将"AI Agent 协作模式,详见 [AGENTS.md](./AGENTS.md) 和 [CLAUDE.md](./CLAUDE.md):
- **提将(orchestrator)**: 任务规划与调度
- **正将(code-artisan)**: 代码编写(追求简洁优雅)
- **反将(architect)**: 架构设计
- **风将(scout)**: 代码审查
- **火将(guard)**: 测试编写
- **除将(fixer)**: Bug 修复
- **脱将(deploy)**: 部署发布
- **谣将(researcher)**: 技术调研
根据任务类型自动调度合适的 Agent 协作完成。
---
**Always use Context7 MCP when I need library/API documentation, code generation, setup or configuration steps without me having to explicitly ask.**
**记住**: 代码是数字时代的文化遗产,每一行都应该有其存在的理由,追求简洁、优雅、高效。