# 新项目 PRD（多租户 + 微信登录/分享 + 余额支付）

## 当前实现说明

- 认证方式已切换为 OTP + JWT；WeChat OAuth/JS-SDK 暂未落地，保留为规划
- 路由当前使用 `/v1` 前缀，多租户 `/t/:tenant_code` 待统一改造

## 1. 范围与约束

### 1.1 多租户（从第一天开始）

- 所有站点与 API 都在路径前缀下：`/t/:tenant_code/...`
- `tenant_code` 规则：不区分大小写，允许字符集 `a-z0-9_-`
- 系统内部以 `tenant_uuid`（UUID）作为租户在 OSS 的存储分区标识
  - OSS Key：`quyun/<tenant_uuid>/<md5>.<ext>`
- 数据隔离：所有业务表均包含 `tenant_id`，所有查询必须带 `tenant_id` 过滤

### 1.2 微信能力

- 保留：微信网页授权登录（OAuth）、JS-SDK 签名与分享
- 移除：微信支付/退款/回调（多租户版本完全不支持，历史也不兼容）

### 1.3 支付能力

- 仅支持：余额支付（单位：分），后台可充值余额
- 可退款：仅余额订单（退款 = 返还余额 + 撤销授权）

### 1.4 技术栈约束

- 后端开发语言：Golang（Go）
- 前端技术栈：Vue 3 + Vite
- UI 组件库（推荐）：PrimeVue（配合 TailwindCSS，性能较好且扩展/主题定制能力强）

---

## 2. 角色与端

### 2.1 WeChat H5 端（C 端用户）

- 访问曲谱列表、搜索
- 查看曲谱详情
- 播放：未购买只能播放“预览版（short=true）”，已购买播放“完整版（short=false）”
- 余额购买
- 查看已购列表（快速播放）
- 查看个人资料与余额
- 分享（JS-SDK）

### 2.2 Admin 管理端（租户运营人员）

- 登录（租户维度账号）
- 仪表盘统计
- 媒体库管理：上传（预签名）、列表、预览、删除
- 曲谱管理：创建/编辑/发布/草稿、绑定媒体资源、设置封面（≤3）
- 用户管理：列表、详情、查看已购、给用户充值余额
- 订单管理：列表、退款（余额订单）
- 运营操作：赠送曲谱给指定用户

---

## 3. 核心业务对象

### 3.1 曲谱（Post）

- 字段：标题、简介、正文、价格（分）、折扣（0~100）、状态（draft/published）
- 关联媒体：
  - `head_images`：封面媒体 ID 列表（≤3）
  - `assets`：媒体资产数组（见 MediaAsset），包含视频/音频/文件等

### 3.2 媒体（Media）

- 字段：name、mime_type、size、hash(md5)、path(OSS key)、metas
- metas：`short`（是否预览资源）、`duration`、`parent_hash`
- hash 去重：在租户维度内去重（同租户相同 md5 视为同一资源）

### 3.3 授权（UserPosts）

- 记录用户购买/赠送后获得的曲谱访问权
- 唯一约束：同一租户同一用户同一曲谱只能有一条

### 3.4 订单（Order）

- 仅余额订单：`payment_method = balance`
- 状态：`pending/completed/refund_success/cancelled`（具体枚举在技术规格中确定）

---

## 4. 关键流程

### 4.1 租户识别

- 进入任意页面时，根据 URL 中的 `:tenant_code` 识别租户
- 服务端需校验：
  - code 正则：`^[a-z0-9_-]+$`（不区分大小写）
  - code 存在且启用
- 解析成功后，将 `tenant_id`、`tenant_uuid` 注入到请求上下文

### 4.2 微信登录

1) 未登录请求 API → 401（XHR）或 302 → `/t/:tenant/v1/auth/wechat?redirect=...`
2) `/auth/wechat` 生成微信授权地址（回调到 `/t/:tenant/v1/auth/login` 并透传 redirect）
3) `/auth/login` 换取 openid + 用户信息，按 `(tenant_id, open_id)` 获取或创建用户，签发会话 token（cookie）

### 4.3 播放策略（预览/完整版）

- assets 中选择 `type == "video/mp4"` 的资源：
  - 未购买：选择 `metas.short == true`
  - 已购买：选择 `metas.short == false`
- 媒体 URL 通过 OSS 预签名下发

### 4.4 余额购买与授权

- 下单：创建订单 `pending`
- 校验余额足够：
  - 足够：扣减余额 → 订单 `completed` → 写入 `user_posts`
  - 不足：返回业务错误（提示联系管理员充值）

### 4.5 余额退款

- 仅允许对 `completed + payment_method=balance` 的订单退款
- 退款动作：
  - 返还余额
  - 删除/撤销 `user_posts` 授权
  - 订单标记为 `refund_success`

---

## 5. 非功能性要求（简版）

- 所有写操作必须带租户隔离与鉴权校验
- 关键唯一约束在 DB 层实现（避免并发重复授权/重复订单号）
- 租户 UUID 由业务代码生成并写入（不依赖 DB 扩展）
