# 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 // 接口定义 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 而非内联样式 标题 // 使用 cn() 工具合并条件样式 import { cn } from '@/utils/cn' ``` #### 避免内联样式 - **不推荐**: `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 ( {title} ) }) ``` #### Hooks 使用 ```typescript // 自定义 Hook export function useTemplates() { const [data, setData] = useState([]) 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 return {user.name} }) ``` ### 导入规范 ```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 内容 // Toast 统一使用项目封装的版本 import { Toast } from '@/@share/components' Toast.show({ title: '操作成功' }) Toast.showLoading({ title: '加载中...' }) Toast.hideLoading() Toast.showModal() 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 if (loading) return return ``` ### 性能优化 ```typescript // 使用 FlashList 代替 FlatList import { FlashList } from '@shopify/flash-list' } estimatedItemSize={100} /> // 图片优化 import { Img } from '@/@share/components' ``` ### 蓝牙通信 ```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' // 平台特定样式 // 平台特定文件 // 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.** **记住**: 代码是数字时代的文化遗产,每一行都应该有其存在的理由,追求简洁、优雅、高效。