# Wardrobe - AI 衣物管理系统 基于 **Tauri 2.x** 封装的跨平台衣物管理应用,目标平台包括 **Android / Windows / macOS**。 ## 功能特性 - 📸 **数字衣橱** - 拍照录入、AI 识别、分类管理 - 💡 **AI 搭配推荐** - 按季节/场合智能推荐 - 📅 **穿搭日历** - 记录每日 OOTD - 📊 **风格统计** - 衣橱利用率、分类分析 - 🧺 **清洁管理** - 清洁周期提醒 - 🔐 **邮箱/手机注册** - 验证码认证 (暂定 `1111`) - 🗄️ **MCP 服务** - AI 平台数据管理接口 - 🦆 **DuckDB** - 本地嵌入式数据库 ## 技术栈 | 层 | 技术 | |----|------| | 前端 | React 18 + TypeScript + Vite + Zustand | | 桌面壳 | Tauri 2 (WebView) | | 后端 | Rust + DuckDB (bundled) | | 移动端 | Tauri Android | | 状态管理 | Zustand | | 路由 | React Router v6 | ## 目录结构 ``` ├── src/ # React 前端 │ ├── api/ # Tauri IPC 封装 │ ├── components/ # 通用组件 (Layout) │ ├── pages/ # 页面 │ │ ├── Landing.tsx # 项目首页 (响应式, 含 APK 下载) │ │ ├── Login.tsx # 登录/注册 (邮箱/手机 + 验证码) │ │ ├── Home.tsx # 首页/今日推荐 │ │ ├── Closet.tsx # 衣橱列表 │ │ ├── AddClothing.tsx # 添加衣物 │ │ ├── ClothingDetail.tsx │ │ ├── Outfits.tsx # 搭配推荐 │ │ ├── Calendar.tsx # 穿搭日历 │ │ └── Profile.tsx # 我的 (含 OTA 升级区) │ ├── api/ │ │ ├── index.ts # Tauri IPC 封装 │ │ └── ota.ts # OTA 封装 (Tauri + Web 双路径) │ ├── version.ts # 版本/构建号 (vite define 注入) │ ├── stores/ # Zustand 状态 │ ├── styles/ # 全局样式 │ └── types/ # TS 类型 ├── server/ # OTA 服务端 (Express) │ ├── index.js # 静态 dist + SPA fallback + /api/health │ └── routes/ota.js # OTA check/bundle/manifest-web 接口 ├── scripts/ │ ├── build-ota.mjs # OTA 打包 + minisign 签名 + latest.json │ ├── ota-genkey.mjs # 生成 minisign 密钥对 │ ├── upload-ota-r2.sh # OTA 包上传 R2 │ └── ... # Android 构建/签名/上传脚本 ├── src-tauri/ # Rust 后端 │ ├── src/ │ │ ├── main.rs # 桌面入口 (薄壳) │ │ ├── lib.rs # 应用逻辑 + mobile_entry_point + hotswap 插件 │ │ ├── db.rs # DuckDB 数据层 │ │ ├── models.rs # 数据模型 │ │ ├── auth.rs # 认证 (验证码 1111) │ │ └── mcp.rs # MCP 服务 │ ├── Cargo.toml │ ├── tauri.conf.json # 含 plugins.hotswap (OTA 端点 + 公钥) │ └── capabilities/default.json ├── prototype/ # HTML 交互原型 └── photograph/ # 竞品截图 ``` ## 快速开始 ### 前置要求 - [Node.js](https://nodejs.org) ≥ 18 - [Rust](https://rustup.rs) ≥ 1.77 - [Android Studio](https://developer.android.com/studio) (Android 构建) ### 开发 ```bash npm install npm run tauri dev # 桌面端开发 ``` ### Android 构建 ```bash npm run tauri android init # 首次生成 Android 工程 npm run tauri android dev # Android 设备调试 npm run tauri android build # 生成 APK ``` ## 关键设计 ### 数据库 (DuckDB) - 数据文件: `%APP_DATA%/wardrobe/wardrobe.duckdb`, Android 下存于应用私有目录 - 表: `users`, `clothing_items`, `outfits`, `daily_records` - 读写均通过 `Mutex` 串行化,保证线程安全 ### 优雅停机 - `ctrlc` 信号捕获 → 设置 shutdown flag - 窗口关闭事件 → 记录日志、释放连接 - DuckDB 连接在进程结束时由 OS 正常关刷 ### 验证码 (临时) - 统一固定为 `1111` - 有效期 5 分钟,成功后自失效 - 注册: 邮箱 或 手机号 (二选一) + `1111` ### MCP 服务 详见 [MCP.md](MCP.md)。通过 `mcp_list_tools` / `mcp_call_tool` IPC 命令暴露 10 个数据管理工具。 ## Android CI/CD 参考 [D:\workbench\iboard](../iboard) 的 Gitea Actions 部署模式。 ### 触发方式 推送 `android-*` 分支 (如 `android/release`) 自动触发构建。 ### 流程 (`.gitea/workflows/android-build.yml`) ``` push android-* → checkout → mise( node/rust ) → JDK 17 → 定位可复用 Android SDK (优先 runner 预装 /usr/local/lib/android/sdk, 其次 CI 缓存, 最后下载) → 缓存复用 NDK 27.2 / Rust 工具链 / Tauri target → tauri android init --ci → 从配置中心拉取全部密钥 (签名 + R2) → scripts/ci/android-signing.sh 注入签名 → tauri android build --apk → 断言签名生效 → scripts/upload-r2.sh 用 wrangler 上传 APK 到 R2 公开桶 (store/data/android/wardrobe.apk) → 输出公共下载地址 (https://pub-...r2.dev/data/android/wardrobe.apk) ``` ### CI secrets (仅配置中心连接) | Secret | 说明 | |--------|------| | `CONFIG_CENTER_URL` | 配置中心地址 (未设时回退 `http://bh.vps.honor3.com:8008`) | | `CONFIG_CENTER_TOKEN` | 配置中心访问 token | 所有业务密钥 (签名 keystore / R2 token) 一律来自配置中心,不进 Gitea secrets。 ### 配置中心存储约定 | 项目 | 分组 | key | 用途 | |------|------|-----|------| | `service-wardrobe` | `signing` | `ANDROID_KEYSTORE_B64` | keystore base64 (JKS RSA 2048) | | `service-wardrobe` | `signing` | `ANDROID_KEY_ALIAS` | `wardrobe` | | `service-wardrobe` | `signing` | `ANDROID_KEY_PASSWORD` | store/key 密码 | | `service-wardrobe` | `ota` | `MINISIGN_PRIVATE_KEY` | OTA 包 minisign 私钥 (整段 .key, 多行) | | `service-wardrobe` | `ota` | `CF_OTA_ENDPOINT` | OTA 检查端点 (部署参考) | | `CommonExternalService` | `cloudflare` | `r2/CF_API_TOKEN` | Cloudflare API token (wrangler 上传) | | `CommonExternalService` | `cloudflare` | `r2/CF_R2_PUBLIC_URL` | R2 公共访问域名 | CI 的 `Fetch config center` 步骤拉取以上全部 key 注入环境变量,签名与上传步骤均不再依赖 Gitea secrets。 建议用 `CONFIG_CENTER_TOKEN` 为配置中心加鉴权(当前 REST API 无鉴权,任何人可读/写)。 ### 本地构建 (可选, WSL) ```bash bash scripts/build-apk.sh debug # 或 release # 脚本自动复用本机 Android SDK/NDK (~/android-sdk, NDK 27.2.x) ``` ## 项目首页 (Landing) `/` 为公开的项目首页 (`src/pages/Landing.tsx`),响应式适配桌面与手机 web: - 项目简介 + 功能特性 + 技术栈 - **APK 下载**: 按钮直链 R2 公共桶 `https://pub-...r2.dev/data/android/wardrobe.apk`(由 android-build.yml 上传),附版本号、复制链接与安装提示 - web 新版本提示: 启动时请求 `/api/ota/manifest-web`,有新构建号时底部浮出"刷新"横幅 - 登录后的应用首页迁移到 `/home`(底部导航同步更新) 部署: `npm run build && OTA_PACKAGE_DIR=ota-package npm start`,server 同时托管首页 dist 与 OTA 接口。 ## OTA 升级 参考 [iboard](../iboard),采用 **tauri-plugin-hotswap** 前端热替换方案(minisign 签名 + 下载 + 校验 + 原子替换),升级不经过应用市场。 ### 原理 - **Tauri 客户端**: 启动时 `notifyReady()`;检查更新走插件内置 `checkUpdate()`,下载/校验/替换/回滚均由插件完成(公钥在 `src-tauri/tauri.conf.json` → `plugins.hotswap.pubkey`,端点在 `plugins.hotswap.endpoint`) - **Web 浏览器**: 只比对 `/api/ota/manifest-web` 的 `build_id` 与当前 `BUILD_ID`,提示刷新(Vite 指纹会缓存失效) - 构建号 `__BUILD_ID__`(YYYYMMDD.HHmmss)由 `vite.config.ts` 每次构建注入 ### 服务端 (`server/`) | 接口 | 说明 | |------|------| | `GET /api/ota/check/:seq` | 有新包 → 200 + manifest;无 → 204 | | `GET /api/ota/bundle/:file` | 下载 tar.gz 升级包 (流式) | | `GET /api/ota/manifest-web` | Web 简化版 manifest | | `GET /api/health` | 健康检查 | 数据源: 环境变量 `OTA_PACKAGE_DIR`(默认 `ota-package/`)下的 `latest.json` + `wardrobe-ota.tar.gz`。 `PORT` 默认 `3002`(与 iboard 的 3001 同机共存)。可选 `OTA_PUBLIC_BASE` 让客户端直连 R2 下载 bundle。 ### 本地生成 OTA 包 ```bash npm run build # 先构建 dist minisign -G -W -p ota-package/hotswap.pub -s ota-package/hotswap.key # 或 npm run ota:genkey npm run build:ota -- --notes "v0.2 更新说明" # 打包 + 签名 + 写 latest.json npm start # 起服务, 手动验收 /api/ota/* ``` 首次需安装 [minisign](https://jedisct1.github.io/minisign/)(Windows: scoop/choco 或官方 win64 二进制)。 生成的 `hotswap.key` 请存到配置中心 `service-wardrobe / ota / MINISIGN_PRIVATE_KEY`(不要提交 git), `hotswap.pub` 的公钥行写入 `src-tauri/tauri.conf.json`。 ### OTA 发布 CI (`.gitea/workflows/ota-build.yml`) 手动 `workflow_dispatch` 触发: ``` build frontend → npm run build → apt install minisign → 从配置中心拉取 MINISIGN_PRIVATE_KEY (service-wardrobe/ota) + CF_API_TOKEN (cloudflare) → node scripts/build-ota.mjs 打包+签名 → scripts/upload-ota-r2.sh 上传到 R2 (store/ota/wardrobe-ota.tar.gz + latest.json) ``` ### 客户端升级操作 「我的」页 → 「检查更新 (OTA)」: - 检查更新 / 立即升级(带进度)/ 回滚(仅 OTA 覆盖时显示) - Web 端仅可检查新构建号提示刷新 ## mise 本地工具链 本项目用 [mise](https://mise.jdx.dev) 统一管理 Node/npm/Rust 版本,仓库根目录 `.mise.toml` 声明工具版本,`cd` 进入目录后自动激活。 ```toml [tools] node = "24.21.0" npm = "12.0.2" rust = "stable" ``` ### Windows 安装 (已完成) 1. 下载 `mise-v*-windows-x64.zip` → 解压到 `~\.local\bin\mise.exe` 2. 用户 PATH 追加: `~\.local\bin` 与 `~\AppData\Local\mise\shims` 3. PowerShell `$PROFILE` 添加: `& "$env:USERPROFILE\.local\bin\mise.exe" activate powershell` 4. `mise use -g node@24.21.0 npm@12.0.2 rust@stable` 安装全局工具 > 注意: Windows 下 mise 数据目录在 `~\AppData\Local\mise`,shims 位于 `~\AppData\Local\mise\shims` (非 `~\.local\share\mise\shims`)。 ## 原型 浏览器打开 `prototype/index.html` 查看可交互原型。 ## License Private