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

13 KiB

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.tsxcamelCase.tsx (如 pointList.tsx, point-list.tsx)
  • 组件文件: PascalCase.tsx (如 BannerSection.tsx)
  • Hooks: camelCase.tskebab-case.ts (如 useTemplates.ts, use-template-actions.ts)
  • 工具函数: camelCase.ts (如 uploadFile.ts)
  • 类型文件: types.ts
  • 常量文件: camelCase.ts

变量与函数命名

  • 组件: PascalCase (BannerSection, ThemedText)
  • Hook 函数: camelCaseuse 开头 (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 规范

类型定义

// 使用 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

// 使用 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
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 使用

// 自定义 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 规范

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

导入规范

// 使用 @ 别名
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. 类型导入

组件库使用

// 使用 @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()

错误处理

// 统一错误处理
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. 条件渲染: 提前返回,减少嵌套
// 提前返回
if (!isLogin) return <Login />
if (loading) return <Loading />

return <Content />

性能优化

// 使用 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
/>

蓝牙通信

// 使用 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)
  • 持久化状态: 使用 AsyncStorageexpo-secure-store

环境变量

// 访问环境变量
const apiUrl = process.env.EXPO_PUBLIC_API_URL
const env = process.env.EXPO_PUBLIC_ENV // 'development' | 'test' | 'production'

// 根据环境执行不同逻辑
if (__DEV__) {
  console.log('开发模式')
}

常用命令

# 安装依赖
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 管理多语言(已集成但未完全启用)

平台差异处理

// 使用 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.mdCLAUDE.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.

记住: 代码是数字时代的文化遗产,每一行都应该有其存在的理由,追求简洁、优雅、高效。