Files
doodle-store/README.md
T
2026-10-19 17:48:57 +08:00

116 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Doodle Store
当前进度、旧线上服务保留约束、验证结果及下一步任务见 [开发交接文档](docs/v3.5/开发交接文档.md)(2026-10-19)。
独立于 `doodle-mini` 的 pnpm Monorepo,用于维护统一业务后端、后续管理后台和用户 Web 网站。小程序源码与 CloudBase 兼容函数仍在 `doodle-mini`,两个项目通过 HTTPS API 协作。
## 当前范围
当前已完成基础工程、本地数据库、小程序登录鉴权及分类服务:
- `apps/server`:可运行的 NestJS 服务,已接入日志、中间件、Swagger、微信静默登录、JWT 与真实账户检查,提供本人摘要、分类查询/管理、题型列表/详情与组合筛选和数据库就绪接口。
- `packages/contracts`:公开响应、登录请求/结果、本人摘要、分类与安全错误类型,不包含数据库模型或私有实现。
- `packages/asset-sync`:本地云存储备份同步七牛的独立 Node.js 工具,支持预演、校验、重试,头像与其他资源共用公开空间。
- `apps/admin`、`apps/web`:仅预留目录与说明,尚未选择或安装前端框架。
- 本地 PostgreSQL 18.6 Docker 开发环境已启动,13 张表及初始配置已创建,并于 2026-10-15 与最新 SQL 复核一致;Prisma 与微信登录已接入,七牛、其他业务及生产部署待实施。
## 本地使用
先按 [本地数据库说明](infra/README.md) 配置根 `.env`,执行 `pnpm infra:up`。默认数据库地址为 `127.0.0.1:5434`,开发库为 `doodle_dev`。图片等资源直接使用七牛,本地仅启动 PostgreSQL。生产与按需测试的安排见 [v3.5 开发与部署环境方案](docs/v3.5/开发与部署环境方案.md)。
使用 Node.js **24.20.0** 与 pnpm **11.24.0**。如使用 fnm,可在本目录执行 `fnm use --install-if-missing`。
```bash
pnpm install --frozen-lockfile
pnpm build
pnpm dev
```
默认地址为 `http://127.0.0.1:8800/api/v1/health`。该接口只证明服务进程可以处理 HTTP 请求,不代表数据库、文件存储或业务系统已经可用。
`pnpm dev` 在服务监听成功后显示完整 Swagger 地址(默认 `http://127.0.0.1:8800/api-docs`),并使用系统默认浏览器自动打开一次。热更新不会重复打开;关闭 Swagger 时不打开。链接按实际 HOST/PORT 生成,建议使用输出的 IP 地址,避免 `localhost` 解析到其他项目。
可在 `apps/server/.env` 中配置 `PORT`、`HOST`,变量示例见 `apps/server/.env.example`。未配置时使用安全的本地默认值。不要提交真实 `.env` 或密钥。
JWT_SECRET 必须配置为至少 32 字节的独立密钥,本机开发密钥已生成。Swagger 默认开发开启:`http://127.0.0.1:8800/api-docs`,生产未显式配置时关闭;其他设置与账户查询接入边界见 [Server 基础设置](docs/v3.5/Server基础设置.md)。
微信小程序配置在 `apps/server/.env` 中填写 `WECHAT_MINI_APP_ID` 和 `WECHAT_MINI_APP_SECRET`。两项均为启动必填;DATABASE_URL 同样必须配置。真实 AppSecret 仅由服务端持有,不提交仓库。
```bash
pnpm check # 格式、代码检查、类型检查、构建与测试
pnpm test:db # 独立临时数据库中的登录/鉴权/分类测试,结束后清理
pnpm build # 按工作区依赖顺序构建
pnpm start # 运行已构建的服务端
pnpm format # 格式化源码与配置
```
## 目录
```text
apps/
server/ NestJS 服务端
admin/ 后续管理后台,当前仅占位
web/ 后续用户网站,当前仅占位
packages/
asset-sync/ 云存储备份同步七牛的独立脚本
contracts/ 可公开的接口类型
deploy/ 后续部署说明,当前未部署
infra/ 本地 PostgreSQL Docker 配置
docs/ 工程初始化与接入边界说明
```
每个实际应用与包声明自己的依赖。工作区内部使用 `workspace:*`,按应用独立构建、发布;不要求后台、网站与 API 同时上线。暂不引入 Turborepo、Nx、Redis、队列或微服务。
数据库模型、密钥和未来私有生成/绘制逻辑只能由服务端持有,不能放进公共契约包供前端导入。小程序不直接依赖本仓库源码或本地工作区包。
登录请求、恢复错误码、数据库基线及联调边界见 [服务端登录接入说明](docs/v3.5/服务端登录接入说明.md)。
分类公开/管理 API、本地导入工具及本批 6 条分类的导入结果见 [分类接口与数据导入](docs/v3.5/分类接口与数据导入.md)。
51 条旧题型数据已导入本地库,预览文件仍待迁移;导入工具、异常年级和计数对账见 [题型数据导入说明](docs/v3.5/题型数据导入说明.md)。
题型查询支持分类、审核年级、年龄段、Tag、最新/热门、运营标记和分页,见 [题型查询接口说明](docs/v3.5/题型查询接口说明.md)。
现有功能迁移的权威方案见 [docs/云服务端迁移方案.md](docs/云服务端迁移方案.md),小程序产品规划与历史设计仍保留在 `doodle-mini`。本仓库的初始化说明见 [docs/初始化说明.md](docs/初始化说明.md)。
## 云存储备份同步七牛
独立脚本项目位于 [packages/asset-sync](packages/asset-sync/README.md),配置入口为该目录的 `.env`,已填写本地 cloud_backup 源目录。`pnpm assets:sync` 默认只预演;填写七牛 AK/SK 与 bucket 后,使用 `pnpm assets:sync --apply --only assets/previews` 同步题型预览。支持保留相对路径、同内容跳过、冲突保护、有限重试和报告;头像与其他资源共用 QINIU_BUCKET 公开空间。该工具不修改业务数据库或自动替换旧 cloud 引用。
### 服务端资源地址配置
`apps/server/.env` 与 asset-sync 使用同一组公开配置;服务端无需配置七牛 AK/SK:
```dotenv
QINIU_PUBLIC_DOMAIN=https://cdn.joeyone.cn
QINIU_KEY_PREFIX=doodle-assets/
QINIU_BUCKET=doodle-cn
```
地址规则为「域名 / 对象 key」。字体等固定资源由 `publicResourceUrl(config, 'assets/fonts/ToneOZ-Pinyin-Regular.ttf')` 补上前缀,得到 `https://cdn.joeyone.cn/doodle-assets/assets/fonts/ToneOZ-Pinyin-Regular.ttf`。支持空前缀;域名仅接受 HTTPS origin,不包含目录。修改配置后重启 server。
数据库 `assets.object_key` 存完整 key,例如 `doodle-assets/assets/previews/math/example.jpg`,返回预览时直接拼域名,不再次添加前缀。`QINIU_BUCKET` 是对象所属空间,不拼进 URL,也不会自动修改资产记录。图片上传成功后仍需根据同步报告回填资产的 key、bucket、摘要等字段并标记 ready;pending 资产继续返回空预览,配置域名不会自动宣布迁移完成。
资源上传后,可将成功同步报告映射回本地 `assets`,保留原资源 ID 与业务表外键:
```bash
# 预演:重新核对本地文件与七牛对象,仅允许本机 doodle_dev
pnpm assets:map --report /绝对路径/成功同步报告.json
# 核对通过后,整批事务写入并记录迁移审计
pnpm assets:map --report /绝对路径/成功同步报告.json --apply
```
当前工具处理已有 cloud 来源的题型预览:根据原文件相对路径匹配,回填 bucket、完整 objectKey、MIME、大小和 SHA-256,设置 ready。重复执行同一映射会跳过,已就绪但映射不同的资产会拒绝覆盖;有缺失或核对失败则整批不写入。不创建用户头像记录、不猜测头像归属。
业务表(例如 worksheets.preview_asset_id、users.avatar_asset_id)仅保存资源 ID;assets 保存文件定位和元数据,不保存七牛完整访问 URL。固定字体未作为业务记录入库,小程序通过 `miniprogram/config/assets.ts` 统一配置域名和前缀;接口提供的图片地址直接使用,不在小程序重复拼接。
### 微信登录上游失败排查
`503 / AUTH_UPSTREAM_UNAVAILABLE` 表示服务端兑换微信 code 未成功。查看同一 requestId 的 `wechat_exchange_failed` 日志:只记录失败阶段、HTTP 状态和微信数值错误码,不输出 AppSecret、code、完整请求 URL 或微信 errmsg。
若 `wechat_errcode=40164`,且有 `egress_ip`,表示微信拒绝当前服务器公网出口 IP。登录对应 AppID 的微信公众平台,在服务端接口调用的 IP 白名单中添加该出口 IP(与代码上传白名单分别核对),保存后在小程序重新触发登录。换网络或代理出口后需重新核对 IP;上线时使用实际服务器的固定出口 IP。仅修改本站后端 `.env` 无法解除微信侧白名单限制。
### 小程序业务接口迁移
除微信预拉取外,用户资料、头像、收藏、下载记录、年龄推荐、动态首页兜底和各管理页已迁至本站 API;详见 [小程序云接口迁移清单](docs/v3.5/小程序云接口迁移清单.md)。上传凭据仅由服务端持有,本地已沿用 asset-sync 的七牛配置。`20261019000000_member_assets` 已在本地应用;云端历史用户及关联记录仍需单独导入。管理功能要求数据库当前角色为 admin,不自动授权开发者账户。