docs(ops): TOS bucket + Aliyun SMS integration spec for team handoff
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m8s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m8s
后端 / 运维同学填回 yaml 模板后,前端 (Claude) 直接接入。 内容覆盖: - TOS 桶配置 / 目录结构 / 公共读 / CDN - 阿里云短信签名 + 模板 + RAM AK - Redis / MySQL / NextAuth 上下游依赖 - 验收清单 + 时间线 - 敏感信息 (AK/SK) 走密钥管理,不入文档 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d2b8c0afdc
commit
409c4c4b50
247
docs/团队对接-TOS与短信登录.md
Normal file
247
docs/团队对接-TOS与短信登录.md
Normal file
@ -0,0 +1,247 @@
|
||||
# 团队对接 · TOS 资源桶 + 阿里云短信登录
|
||||
|
||||
> 这是给后端 / 运维同学的对接清单。把每一项的「需要回填」补齐后,原文回给前端(Claude)就能直接接入。
|
||||
> 文件里所有变量名都跟 `.env.example` 对齐,回填时直接写值即可。
|
||||
|
||||
---
|
||||
|
||||
## A. 火山引擎 TOS · 静态资源
|
||||
|
||||
### A.1 目标
|
||||
|
||||
把 36 位艺人的立绘 / 氛围图 / 三视图 / 表演视频 + Hero PV 全部走 TOS + CDN 引用。
|
||||
当前本地 ~1GB 资源已 `.gitignore`,**不入 git**。
|
||||
|
||||
### A.2 桶配置建议
|
||||
|
||||
| 项 | 建议值 | 备注 |
|
||||
|---|---|---|
|
||||
| 桶名 | `cyber-star` | 名字仅用于服务端 SDK,前端只看域名 |
|
||||
| 区域 | `cn-beijing` 或就近 | 跟用户群体所在区域一致 |
|
||||
| 读权限 | **公共读 (Public Read)** | 投票网站资源全部对外可访问,不需要签名 URL |
|
||||
| 写权限 | 私有 | 仅服务端 / 运维通过 AK/SK 写入 |
|
||||
| CDN 加速 | **强烈建议开启** | 火山 TOS 可直接挂火山 CDN,全国边缘加速;不开 CDN 时直接走桶域名也行,只是速度差一些 |
|
||||
| 防盗链 | 可选 | 起步阶段不限制;后期可加 Referer 白名单 `*.airlabs.art` |
|
||||
| HTTPS | **必须** | 网站走 HTTPS,资源也必须是 HTTPS,否则浏览器拦截 |
|
||||
|
||||
### A.3 桶内目录结构(请保持一致)
|
||||
|
||||
```
|
||||
cyber-star/
|
||||
├── portraits/
|
||||
│ ├── 001.png # 立绘(卡片用,半身)
|
||||
│ ├── 001-2.png # 氛围图 2
|
||||
│ ├── 001-3.png # 氛围图 3
|
||||
│ ├── 001-view.png # 三视图(详情页备用,可暂不上传)
|
||||
│ ├── 002.png
|
||||
│ ├── ...
|
||||
│ └── 036-3.png
|
||||
└── videos/
|
||||
├── hero-pv.mp4 # 首页 Hero 背景 PV
|
||||
└── artists/
|
||||
├── 001.mp4
|
||||
├── 002.mp4
|
||||
├── 004.mp4 # 003 / 010 / 017 / 027 暂时缺,先不传
|
||||
└── ...
|
||||
```
|
||||
|
||||
> 路径与本地 `public/portraits/` `public/videos/` 完全对齐。前端代码里只需要把 `/portraits/...` 替换为 `${TOS_DOMAIN}/portraits/...`。
|
||||
|
||||
### A.4 前端要的信息(**必填**)
|
||||
|
||||
```yaml
|
||||
# ── 公共域名(前端代码引用资源用,必须公网 HTTPS 可达)──
|
||||
NEXT_PUBLIC_TOS_DOMAIN: "" # 例:https://cyber-star.tos-cn-beijing.volces.com
|
||||
# 或挂 CDN 后:https://cdn.cyber-star.airlabs.art
|
||||
|
||||
# ── 是否启用公共读 ──
|
||||
PUBLIC_READ: "" # yes / no(若 no 请说明签名策略)
|
||||
|
||||
# ── CDN 是否启用 + 加速域名 ──
|
||||
CDN_ENABLED: "" # yes / no
|
||||
CDN_DOMAIN: "" # 启用 CDN 时填这个,前端用这个域名而不是桶原域名
|
||||
```
|
||||
|
||||
### A.5 服务端要的信息(**仅当后端要写桶 / 头像直传时需要**,前端暂时不需要)
|
||||
|
||||
> ⚠️ AK/SK 是高敏感信息,**不要发到聊天里**。请用密钥管理工具同步给运维 / CI 环境变量,或者通过加密渠道(飞书加密文件 / 1Password)给。下面只是占位提醒。
|
||||
|
||||
```yaml
|
||||
TOS_ENDPOINT: "" # tos-cn-beijing.volces.com
|
||||
TOS_REGION: "" # cn-beijing
|
||||
TOS_BUCKET: "" # cyber-star
|
||||
TOS_ACCESS_KEY: "" # 走密钥管理,不写明文
|
||||
TOS_SECRET_KEY: "" # 走密钥管理,不写明文
|
||||
```
|
||||
|
||||
### A.6 上传分工
|
||||
|
||||
- [ ] **前端**(Claude)负责压缩。把 `public/portraits/` 和 `public/videos/` 用 sharp + ffmpeg 批量转换,输出到 `assets-compressed/`,保持 A.3 的目录结构。压缩目标:
|
||||
- 立绘 PNG → WebP,目标单张 ≤ 800KB(卡片清晰度足够)
|
||||
- 三视图 PNG → WebP,目标单张 ≤ 1.5MB
|
||||
- Hero PV mp4 → H.264 1080p,目标 ≤ 15MB
|
||||
- 单人 solo mp4 → H.264 1080p,目标单条 ≤ 3MB
|
||||
- [ ] **运维 / 后端** 拿到 `assets-compressed/` 后用 `tosutil` 整目录上传到桶根:
|
||||
```bash
|
||||
tosutil cp -r -f assets-compressed/* tos://cyber-star/
|
||||
```
|
||||
- [ ] **前端**(Claude)回填 `NEXT_PUBLIC_TOS_DOMAIN` 进 `.env`,封装 `tosUrl(path)` 工具函数,把代码里所有 `/portraits/...` `/videos/...` 改成走该函数。
|
||||
|
||||
### A.7 验收
|
||||
|
||||
- [ ] 浏览器直接打开 `${NEXT_PUBLIC_TOS_DOMAIN}/portraits/001.png` 能看到图
|
||||
- [ ] 同样地址在 https 下不报 mixed-content
|
||||
- [ ] 网站首页加载,Network 面板看到立绘从 TOS 域名下载,状态 200
|
||||
|
||||
---
|
||||
|
||||
## B. 阿里云短信服务 · 手机号 OTP 登录
|
||||
|
||||
### B.1 目标
|
||||
|
||||
`/api/auth/send-otp` 现在只在控制台打 log,需要接真实短信通道,给用户发 6 位验证码完成手机号登录。
|
||||
全国大陆手机号,5 分钟内有效,单号码 60 秒限频(前端已做)。
|
||||
|
||||
### B.2 阿里云控制台需要申请的东西
|
||||
|
||||
按这个顺序在阿里云控制台 → **短信服务** 申请:
|
||||
|
||||
#### B.2.1 短信签名
|
||||
|
||||
- **签名内容**:`Cyber Star` 或 `虚拟偶像出道企划` 或公司主体相关
|
||||
- **签名类型**:通用
|
||||
- **使用场景**:验证码(推荐)/ 网站会员注册
|
||||
- **审核材料**:网站备案截图 / 公司营业执照(看运营那边怎么对接)
|
||||
- **审核时长**:1-2 工作日
|
||||
|
||||
#### B.2.2 短信模板
|
||||
|
||||
- **模板类型**:验证码
|
||||
- **模板内容**(必须严格使用 `${code}` 占位符):
|
||||
```
|
||||
您的验证码是 ${code},5 分钟内有效,请勿泄露。
|
||||
```
|
||||
- **审核时长**:1-2 工作日
|
||||
- 申请通过后会拿到一个 `SMS_xxxxxxxx` 的模板 Code
|
||||
|
||||
#### B.2.3 RAM 子账号 + AccessKey
|
||||
|
||||
- 在阿里云 RAM 创建子账号 `cyber-star-sms`,授予 `AliyunDysmsFullAccess` 权限
|
||||
- 生成 AccessKey ID + Secret(一次性显示,存好)
|
||||
|
||||
### B.3 前端要的信息(**必填**)
|
||||
|
||||
```yaml
|
||||
# ── 短信签名与模板(公开信息,可以聊天里给)──
|
||||
SMS_SIGN_NAME: "" # 例:Cyber Star
|
||||
SMS_TEMPLATE_CODE: "" # 例:SMS_298765432
|
||||
|
||||
# ── 接入信息(敏感,走密钥管理)──
|
||||
SMS_ACCESS_KEY: "" # 阿里云 RAM 子账号 AK
|
||||
SMS_SECRET_KEY: "" # 阿里云 RAM 子账号 SK
|
||||
SMS_REGION: "" # 默认 cn-hangzhou,国内一般不变
|
||||
```
|
||||
|
||||
### B.4 上下游依赖(**必填,缺一个都跑不起来**)
|
||||
|
||||
#### B.4.1 Redis
|
||||
|
||||
```yaml
|
||||
REDIS_URL: "" # redis://default:PASSWORD@host:port
|
||||
# 用途:① OTP 验证码 5min TTL 存储 ② 限流计数(手机号 60s/IP 5min 等)
|
||||
```
|
||||
|
||||
如果还没有 Redis 实例,可以先用火山 Redis(同地域低延迟)或自建。**最低规格够用**,QPS 不大。
|
||||
|
||||
#### B.4.2 MySQL
|
||||
|
||||
```yaml
|
||||
DATABASE_URL: "" # mysql://user:pwd@host:port/db?charset=utf8mb4
|
||||
# 用途:用户表 / 投票记录 / 应援关系 / 每日额度
|
||||
```
|
||||
|
||||
- 火山 RDS for MySQL 8 或自建均可
|
||||
- 第一次部署需要跑:
|
||||
```bash
|
||||
npx prisma migrate deploy
|
||||
npx prisma db seed # 灌 36 位艺人 + ActivityConfig(活动开关 / 起止时间 / 每日额度)
|
||||
```
|
||||
|
||||
#### B.4.3 NextAuth
|
||||
|
||||
```yaml
|
||||
AUTH_SECRET: "" # openssl rand -base64 32 生成
|
||||
AUTH_URL: "" # 例:https://cyber-star.airlabs.art(生产域名,不含末尾斜杠)
|
||||
```
|
||||
|
||||
### B.5 后端要做的代码改动(仅 1 处,~10 行)
|
||||
|
||||
`src/app/api/auth/send-otp/route.ts` 第 41-53 行现在长这样:
|
||||
|
||||
```ts
|
||||
const redis = getRedis();
|
||||
if (redis) {
|
||||
await redis.set(`sms:otp:${phone}`, code, "EX", 300);
|
||||
}
|
||||
|
||||
// TODO[团队]: 接入真实短信服务(阿里云 / 火山引擎 SMS)
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
console.log(`[dev-otp] 发送给 ${phone}: ${code}`);
|
||||
}
|
||||
```
|
||||
|
||||
要改成调阿里云 SDK 真实发短信。**这一步前端(Claude)可以代写**,需要后端确认接 SDK 用 `@alicloud/dysmsapi20170525` 还是 `@alicloud/pop-core`,或者后端自己写也行。
|
||||
|
||||
### B.6 验收
|
||||
|
||||
- [ ] 真实手机号点「获取验证码」,30 秒内收到短信,内容包含 6 位数字
|
||||
- [ ] 验证码填回去能登录成功,导航栏显示头像
|
||||
- [ ] 60 秒内对同一手机号再次请求,接口返回 429(限流生效)
|
||||
- [ ] OTP 5 分钟后失效
|
||||
|
||||
---
|
||||
|
||||
## C. 回填模板(**直接复制这一块改值,整段返回给前端**)
|
||||
|
||||
```yaml
|
||||
# ───── A. TOS 资源桶 ─────
|
||||
NEXT_PUBLIC_TOS_DOMAIN: ""
|
||||
PUBLIC_READ: ""
|
||||
CDN_ENABLED: ""
|
||||
CDN_DOMAIN: ""
|
||||
|
||||
# ───── B. 阿里云短信 ─────
|
||||
SMS_SIGN_NAME: ""
|
||||
SMS_TEMPLATE_CODE: ""
|
||||
SMS_REGION: ""
|
||||
|
||||
# ───── B.4 基础依赖 ─────
|
||||
REDIS_URL: ""
|
||||
DATABASE_URL: ""
|
||||
AUTH_SECRET: ""
|
||||
AUTH_URL: ""
|
||||
|
||||
# ───── 备注(其他需要前端知道的事情)─────
|
||||
# 例如:访问令牌怎么续期、桶有没有 Referer 白名单、SMS 模板审核状态等
|
||||
NOTES: |
|
||||
|
||||
```
|
||||
|
||||
**敏感信息(AK/SK)请单独走密钥管理或加密渠道,不要写在这个文件里。**
|
||||
|
||||
---
|
||||
|
||||
## D. 时间线建议
|
||||
|
||||
```
|
||||
Day 0 (今天) ─ 后端 / 运维拿到这份文档,开始走流程
|
||||
Day 1 ─ 阿里云提交签名 / 模板审核(等 1-2 天)
|
||||
─ 创建 TOS 桶 + CDN 域名
|
||||
─ 部署 MySQL / Redis 实例
|
||||
Day 1-3 ─ 前端这边:本地压缩 1GB 资源 → 输出到 assets-compressed/
|
||||
─ 前端代码适配 NEXT_PUBLIC_TOS_DOMAIN 占位
|
||||
Day 2-3 ─ 短信审核通过 → 回填模板 + AK
|
||||
─ 资源上传到 TOS
|
||||
Day 3 ─ 联调:真实手机号收验证码,登录,投票,资源走 CDN
|
||||
Day 4 ─ 上线
|
||||
```
|
||||
Loading…
x
Reference in New Issue
Block a user