diff --git a/docs/backend/FRONTEND_COZSWEET_BEHAVIOR_ANALYTICS.md b/docs/backend/FRONTEND_COZSWEET_BEHAVIOR_ANALYTICS.md
deleted file mode 100644
index c3bd35aa..00000000
--- a/docs/backend/FRONTEND_COZSWEET_BEHAVIOR_ANALYTICS.md
+++ /dev/null
@@ -1,267 +0,0 @@
-# Cozsweet 全站行为埋点前端接入
-
-> 发布状态(2026-07-14):自动页面/按钮采集 SDK 已部署 `pro` 预发,生产仍是旧版支付专项 SDK。前端应先接 `pro` 完成联调;生产自动采集要等 unified 下一次生产镜像发布后再启用。
-
-## 1. 目标
-
-前端接入一次后,自动统计:
-
-- 用户访问了哪个页面。
-- Next.js 站内路由切换。
-- 所有原生按钮、链接和带 `role="button"` 的控件点击。
-- 带 `data-analytics-key` 的自定义可点击组件。
-
-支付漏斗另外上报明确业务事件,统计付费墙原因、套餐曝光、套餐点击、创建订单、打开支付页和最终支付结果。
-
-## 2. 环境地址
-
-| 环境 | SDK | 事件接口 |
-| --- | --- | --- |
-| pro 预发 | `https://proapi.banlv-ai.com/js/cozsweet-payment-analytics.js` | `https://proapi.banlv-ai.com/api/behavior/events` |
-| production 生产 | `https://api.banlv-ai.com/js/cozsweet-payment-analytics.js` | `https://api.banlv-ai.com/api/behavior/events` |
-
-## 3. Next.js 根布局接入
-
-只在根布局加载一次。预发必须先指定预发事件地址,否则 SDK 默认发送到生产。
-
-```tsx
-import Script from 'next/script'
-
-export function BehaviorAnalyticsScripts() {
- const isPro = process.env.NEXT_PUBLIC_APP_ENV === 'pro'
- const apiBase = isPro
- ? 'https://proapi.banlv-ai.com'
- : 'https://api.banlv-ai.com'
-
- return (
- <>
-
-
- >
- )
-}
-```
-
-SDK 会自动生成并持久化:
-
-- `anonymousId`:未登录用户标识。
-- `sessionId`:30 分钟会话标识。
-- `pagePath/pageTitle/referrer`。
-- `siteHost/pageUrl/UTM`。
-
-登录成功或恢复会话后设置 Token,让事件同时绑定 `userId`:
-
-```ts
-window.CozsweetPaymentAnalytics?.setToken(accessToken)
-```
-
-## 4. 所有按钮点击
-
-以下元素会自动上报 `eventType=element_click`,前端不需要在每个 `onClick` 里手工请求接口:
-
-- `button`
-- `a[href]`
-- `[role="button"]`
-- `[role="link"]`
-- `input[type="button|submit|reset"]`
-- `[data-analytics-key]`
-
-重要按钮必须提供稳定且不随语言变化的 `data-analytics-key`:
-
-```tsx
-
-
-
-
-
-```
-
-纯 `div onClick` 如果没有 `role="button"`,必须添加 `data-analytics-key`,否则浏览器无法可靠识别它是按钮。
-
-不需要统计的区域:
-
-```tsx
-
- {/* 此节点及其子节点不自动记录点击 */}
-
-```
-
-程序触发、没有真实 DOM 点击时可以手工记录:
-
-```ts
-window.CozsweetPaymentAnalytics?.elementClick(
- 'chat.retry_generation',
- 'Retry generation',
- { messageId },
-)
-```
-
-不要把聊天正文、邮箱、手机号、Token 或支付参数放进 `data-analytics-key`、标签或 metadata。
-
-## 5. 支付漏斗必须手工上报
-
-通用按钮点击只能知道“点了某个按钮”,不能知道套餐价格、订单 ID 和进入充值页的原因。以下事件必须在支付业务代码对应步骤调用。
-
-```ts
-const analytics = window.CozsweetPaymentAnalytics
-
-analytics?.paywallShown('daily_chat_limit', {
- entryPoint: 'chat_input',
- isVip: false,
-})
-
-analytics?.rechargeModalOpen('chat_input', 'daily_chat_limit')
-
-plans.forEach((plan, index) => {
- analytics?.planImpression(plan, index + 1)
-})
-
-analytics?.planClick(plan, {
- entryPoint: 'paywall_modal',
- triggerReason: 'daily_chat_limit',
-})
-
-analytics?.createOrderStart(plan, payChannel)
-
-try {
- const response = await createOrder({
- planId: plan.planId,
- payChannel,
- autoRenew,
- })
- const data = response.data
- const orderId = data.orderId
- const checkoutUrl = analytics?.extractCheckoutUrl(data)
-
- analytics?.createOrderSuccess(plan, orderId, payChannel)
- if (checkoutUrl) {
- analytics?.checkoutOpened(orderId, plan, payChannel, checkoutUrl)
- window.location.href = checkoutUrl
- } else {
- analytics?.checkoutFailed(
- orderId,
- plan,
- 'missing_checkout_url',
- payChannel,
- )
- }
-} catch (error) {
- analytics?.createOrderFailed(
- plan,
- error instanceof Error ? error.message : 'create_order_error',
- payChannel,
- )
-}
-```
-
-轮询订单状态:
-
-```ts
-analytics?.statusPollStart(orderId, plan)
-
-analytics?.statusPollUpdate(orderId, data.status, plan, {
- expiresAt: data.expiresAt,
- expiresInSeconds: data.expiresInSeconds,
-})
-
-// 前端主动放弃轮询且订单仍未进入终态时调用
-analytics?.statusPollTimeout(orderId, plan)
-```
-
-## 6. 固定事件名
-
-| 步骤 | 事件名 | 必要 metadata |
-| --- | --- | --- |
-| 触发付费墙 | `paywall_shown` | `triggerReason`, `entryPoint` |
-| 打开充值页 | `recharge_modal_open` | `triggerReason`, `entryPoint` |
-| 套餐曝光 | `payment_plan_impression` | `planId`, `amountCents`, `currency`, `position` |
-| 点击套餐 | `payment_plan_click` | `planId`, `amountCents`, `currency` |
-| 开始建单 | `payment_create_order_start` | `planId`, `payChannel` |
-| 建单成功 | `payment_create_order_success` | `planId`, `orderId`, `payChannel` |
-| 建单失败 | `payment_create_order_failed` | `planId`, `reason`, `payChannel` |
-| 打开支付页 | `payment_checkout_opened` | `planId`, `orderId`, `payChannel` |
-| 支付页缺失/打开失败 | `payment_checkout_failed` | `orderId`, `reason` |
-| 支付状态 | `payment_status_paid/failed/expired` | `orderId`, `status` |
-| 轮询超时 | `payment_status_poll_timeout` | `orderId` |
-
-`triggerReason` 使用固定值:
-
-- `daily_chat_limit`
-- `private_topic_limit`
-- `insufficient_credits`
-- `sidebar_recharge`
-- `vip_cta`
-- `ad_landing`
-- `manual_recharge`
-- `unknown`
-
-不要继续使用已经废弃的 `weekly_chat_limit` 作为新事件原因;当前免费聊天口径是每日额度。
-
-## 7. 请求格式
-
-SDK 最终批量发送:
-
-```http
-POST /api/behavior/events
-Content-Type: application/json
-Authorization: Bearer // 有登录 Token 时携带
-```
-
-```json
-{
- "events": [
- {
- "eventType": "element_click",
- "eventName": "element_click",
- "anonymousId": "browser-uuid",
- "sessionId": "session-uuid",
- "pagePath": "/chat",
- "pageTitle": "Chat",
- "elementKey": "recharge.open",
- "elementText": "Recharge",
- "elementTag": "button",
- "metadata": {
- "siteHost": "cozsweet.com",
- "pageUrl": "https://cozsweet.com/chat"
- }
- }
- ]
-}
-```
-
-成功响应:
-
-```json
-{"ok": true, "inserted": 1}
-```
-
-埋点失败不能阻塞聊天、解锁或支付流程。SDK 已吞掉网络异常,业务代码不要 `await` 埋点后再继续支付。
-
-## 8. 联调验收
-
-1. 打开浏览器 Network,筛选 `behavior/events`。
-2. 首次打开页面应看到 `page_view`。
-3. Next.js 路由切换后应再次看到新 `pagePath` 的 `page_view`。
-4. 点击任意按钮应看到 `element_click` 和稳定 `elementKey`。
-5. 从付费墙点击一个套餐,依次检查专用支付事件及 `planId`。
-6. 建单成功后必须看到同一 `orderId` 出现在建单、支付页和状态事件中。
-7. 接口响应必须为 `ok=true` 且 `inserted>0`。
-8. Manager 选择同一日期范围,确认数据出现;统计不是实时推送时,刷新页面即可。
-
-## 9. 当前线上为 0 的原因
-
-截至 2026-07-14,线上 `cozsweet.com` 页面及加载的前端 JS 中没有找到本 SDK,也没有找到支付漏斗事件代码。数据库近期大部分 `element_click/page_view` 来自 Manager 后台自己的追踪,而不是 Cozsweet 用户端。后端只能自动记录建单开始/成功/失败,无法替前端知道付费墙是否展示、套餐是否曝光、用户点击了哪个套餐、支付页是否真正打开,因此这些步骤显示 0 是符合当前数据事实的。
diff --git a/docs/backend/FRONTEND_FACEBOOK_IDENTITY_API.md b/docs/backend/FRONTEND_FACEBOOK_IDENTITY_API.md
deleted file mode 100644
index 5ecf3f1b..00000000
--- a/docs/backend/FRONTEND_FACEBOOK_IDENTITY_API.md
+++ /dev/null
@@ -1,225 +0,0 @@
-# Facebook ASID / PSID 绑定与登录接口说明
-
-## 总原则
-
-后端不再依赖 Meta 做 ASID / PSID 实时互转。前端拿到哪个 ID 就传哪个 ID,后端只用本地数据库的绑定关系判断是不是同一个用户。
-
-- ASID: Facebook Login 返回的 app-scoped id。
-- PSID: Messenger / ManyChat / Page 链接带来的 page-scoped id。
-- 只有当同一个后端用户已经同时绑定 ASID 和 PSID 时,`psid` 才能直接当作 Facebook 登录凭据换 token。
-
-生产 API Base URL:
-
-```text
-https://api.banlv-ai.com
-```
-
-## 场景 2: 已登录用户绑定 PSID / ASID
-
-### Purpose
-
-用户已经登录 Cozsweet,前端从 URL 或 Messenger 环境拿到 `psid` 后,调用该接口把 PSID 绑定到当前登录用户。
-
-### Request URL
-
-```http
-POST https://api.banlv-ai.com/api/user/facebook/identity
-```
-
-### Authentication
-
-需要登录 token:
-
-```http
-Authorization: Bearer
-```
-
-### Request Format
-
-```http
-Content-Type: application/json
-```
-
-### Parameters
-
-| Field | Type | Required | Example | Meaning |
-| --- | --- | --- | --- | --- |
-| psid | string | no | `37370387172559600` | Messenger PSID。 |
-| asid | string | no | `1582386133449953` | Facebook ASID。 |
-| fbPsid | string | no | `37370387172559600` | `psid` 的别名。 |
-| fbAsid | string | no | `1582386133449953` | `asid` 的别名。 |
-
-至少传一个字段。推荐前端只拿到 PSID 时传:
-
-```json
-{ "psid": "37370387172559600" }
-```
-
-### Request Example
-
-```bash
-curl -X POST 'https://api.banlv-ai.com/api/user/facebook/identity' \
- -H 'Authorization: Bearer ' \
- -H 'Content-Type: application/json' \
- --data-raw '{
- "psid": "37370387172559600"
- }'
-```
-
-### Response Format
-
-```json
-{
- "code": 200,
- "message": "Facebook 身份绑定成功",
- "success": true,
- "data": {
- "fbAsid": "1582386133449953",
- "fbPsid": "37370387172559600",
- "facebookBinding": {
- "conflicts": [],
- "bound": []
- }
- }
-}
-```
-
-### Failures
-
-| Status | Meaning |
-| --- | --- |
-| 400 | 没有传 `asid/fbAsid` 或 `psid/fbPsid`。 |
-| 401 | 未登录或 token 失效。 |
-| 409 | 该 ASID 或 PSID 已绑定到其他正式账号。 |
-
-## 场景 3: PSID 直接登录
-
-### Purpose
-
-前端只有 `psid`,希望后端用本地绑定关系直接换登录 token,不再触发 Facebook Login。
-
-### Request URL
-
-```http
-POST https://api.banlv-ai.com/api/auth/login/facebook/psid
-```
-
-### Authentication
-
-不需要 Bearer token。
-
-### Request Format
-
-```http
-Content-Type: application/json
-```
-
-### Parameters
-
-| Field | Type | Required | Example | Meaning |
-| --- | --- | --- | --- | --- |
-| psid | string | yes | `37370387172559600` | Messenger PSID。 |
-| deviceId | string | no | `web-abc` | 未匹配到账号时创建/返回游客 token 用;不传则后端按 PSID 生成稳定设备 ID。 |
-| bindToGuest | boolean | no | `true` | 未匹配到任何用户时,是否把 PSID 先绑定到游客账号,默认 true。 |
-
-### Request Example
-
-```bash
-curl -X POST 'https://api.banlv-ai.com/api/auth/login/facebook/psid' \
- -H 'Content-Type: application/json' \
- --data-raw '{
- "psid": "37370387172559600"
- }'
-```
-
-### Success Response: 已有完整绑定,直接登录
-
-同一个用户已有 ASID 和 PSID 时返回正式登录 token:
-
-```json
-{
- "code": 200,
- "message": "Facebook PSID 登录成功",
- "success": true,
- "data": {
- "token": "",
- "refreshToken": "",
- "matchedBy": "psid",
- "fbAsid": "1582386133449953",
- "fbPsid": "37370387172559600",
- "hasCompleteFacebookIdentity": true,
- "isGuest": false,
- "user": {
- "id": "",
- "fbAsid": "1582386133449953",
- "fbPsid": "37370387172559600"
- }
- }
-}
-```
-
-### Success Response: 未知或绑定不完整,返回游客
-
-查不到 PSID,或 PSID 对应用户还没有 ASID 时,不当作 Facebook 登录,只返回游客 token:
-
-```json
-{
- "code": 200,
- "message": "Facebook PSID 未匹配,已返回游客登录",
- "success": true,
- "data": {
- "token": "",
- "refreshToken": "",
- "matchedBy": "guest",
- "fbPsid": "37370387172559600",
- "fbAsid": null,
- "hasCompleteFacebookIdentity": false,
- "isGuest": true,
- "userId": ""
- }
-}
-```
-
-如果 PSID 查到了用户,但该用户缺 ASID,`matchedBy` 会是:
-
-```text
-psid_incomplete
-```
-
-前端应继续按游客态处理,或引导用户进行 Facebook Login。
-
-### Failures
-
-| Status | Meaning |
-| --- | --- |
-| 422 | PSID 格式无效。 |
-
-## Profile 字段
-
-`GET /api/user/profile` 和登录响应里的 `user` 会包含:
-
-```json
-{
- "fbAsid": "1582386133449953",
- "fbPsid": "37370387172559600"
-}
-```
-
-没有绑定时字段为 `null` 或不存在。
-
-## 推荐前端流程
-
-1. 页面打开时从 URL / Messenger 环境读取 `psid`。
-2. 如果本地已有登录 token:
- - 调 `POST /api/user/facebook/identity` 绑定 `psid` 到当前用户。
-3. 如果本地没有登录 token:
- - 先调 `POST /api/auth/login/facebook/psid`。
- - 如果返回 `hasCompleteFacebookIdentity=true`,保存 token,当作登录成功。
- - 如果返回 `isGuest=true`,保存游客 token。
-
-## 重要注意
-
-- 后端不会再调用 Meta 做 ASID / PSID 互转。
-- PSID 直登只相信我们数据库里已有的绑定关系。
-- `409 FACEBOOK_ID_CONFLICT` 必须提示用户换账号或联系客服,不要在前端覆盖绑定。
-- 前端保存 token 的逻辑和原登录流程一致。
diff --git a/docs/backend/FRONTEND_PRIVATE_ALBUM_API.md b/docs/backend/FRONTEND_PRIVATE_ALBUM_API.md
deleted file mode 100644
index 427564b8..00000000
--- a/docs/backend/FRONTEND_PRIVATE_ALBUM_API.md
+++ /dev/null
@@ -1,307 +0,0 @@
-# Cozsweet 独立付费图片包前端接口
-
-## 1. 用途
-
-Cozsweet 前端通过本接口展示独立的 8/15 张私密图片包,并使用用户积分解锁。FB 只导入原始图片素材,后端素材池负责跨批次自动凑成 8 张或 15 张图片包。该功能不走现金支付,不使用旧 `/moments` 接口。
-
-## 2. 接口地址
-
-| 功能 | 方法 | 路径 |
-| --- | --- | --- |
-| 图片包列表 | GET | `/api/private-room/albums` |
-| 积分解锁 | POST | `/api/private-room/albums/{albumId}/unlock` |
-
-## 4. 固定价格
-
-| 图片数量 | `unlockCost` | 单张价格 |
-| ---: | ---: | ---: |
-| 8 | 320 credits | 40 credits |
-| 15 | 600 credits | 40 credits |
-
-接口只会返回 `currency: "credits"`。前端不得显示现金价格,也不得调用支付套餐或创建订单接口。
-
-## 5. GET /api/private-room/albums
-
-### 请求参数
-
-| 参数 | 类型 | 必填 | 默认值 | 说明 |
-| --- | --- | --- | --- | --- |
-| `character` | string | 否 | `elio` | 角色 ID。 |
-| `collectionKey` | string | 否 | 全部 | 只查看一个素材分组。 |
-| `limit` | integer | 否 | 20 | 1-50。 |
-| `cursor` | ISO datetime | 否 | - | 上一页返回的 `nextCursor`。 |
-
-### 请求示例
-
-```bash
-curl 'https://api.banlv-ai.com/api/private-room/albums?character=elio&limit=20' \
- -H 'Authorization: Bearer '
-```
-
-### 锁定图片包响应
-
-```json
-{
- "code": 200,
- "message": "success",
- "success": true,
- "data": {
- "items": [
- {
- "albumId": "a1b2c3d4-0000-0000-0000-000000000000",
- "momentId": "album:a1b2c3d4-0000-0000-0000-000000000000",
- "characterId": "elio",
- "collectionKey": "manila_202607",
- "title": "Private Manila set",
- "content": null,
- "previewText": "Only for you.",
- "imageCount": 8,
- "mediaCount": 8,
- "images": [
- {
- "url": "https://dbapi.banlv-ai.com/storage/v1/object/public/elio-schedules/01.jpg",
- "type": "image",
- "locked": true,
- "index": 0
- }
- ],
- "locked": true,
- "unlocked": false,
- "unlockCost": 320,
- "requiredCredits": 320,
- "creditCostPerImage": 40,
- "currency": "credits",
- "canUnlockWithCredits": false,
- "publishedAt": "2026-07-13T00:00:00+00:00",
- "lockDetail": {
- "locked": true,
- "showContent": false,
- "showUpgrade": true,
- "reason": "private_album",
- "requiredCredits": 320,
- "currentCredits": 100,
- "shortfallCredits": 220,
- "mediaCount": 8,
- "unlockCostPerImage": 40
- }
- }
- ],
- "nextCursor": null,
- "hasMore": false,
- "creditBalance": 100,
- "currency": "credits",
- "creditCostPerImage": 40,
- "packageOptions": [
- {"imageCount": 8, "creditCost": 320},
- {"imageCount": 15, "creditCost": 600}
- ]
- }
-}
-```
-
-锁定和解锁状态都会返回完整 `images[].url`。前端必须根据 `locked` / `unlocked` / `lockDetail.locked` 决定是否显示锁层和是否允许查看原图,不能用 URL 是否为空判断解锁状态。
-
-### 已解锁图片包
-
-同一个用户解锁后,再次请求列表会返回:
-
-```json
-{
- "albumId": "a1b2c3d4-0000-0000-0000-000000000000",
- "locked": false,
- "unlocked": true,
- "content": "Only for you.",
- "imageCount": 8,
- "images": [
- {
- "url": "https://dbapi.banlv-ai.com/storage/v1/object/public/elio-schedules/01.jpg",
- "type": "image",
- "locked": false,
- "index": 0
- }
- ]
-}
-```
-
-### 分页
-
-`hasMore=true` 时,把 `nextCursor` 原样传回:
-
-```http
-GET /api/private-room/albums?cursor=&limit=20
-```
-
-## 6. POST /api/private-room/albums/{albumId}/unlock
-
-### 请求格式
-
-```http
-Content-Type: application/json
-Authorization: Bearer
-```
-
-Body:
-
-```json
-{
- "expectedCost": 320
-}
-```
-
-| 字段 | 类型 | 必填 | 示例 | 说明 |
-| --- | --- | --- | --- | --- |
-| `expectedCost` | integer | 否但建议 | 320 | 用户确认时看到的价格;价格变化则拒绝扣分。 |
-
-### 请求示例
-
-```bash
-curl -X POST 'https://api.banlv-ai.com/api/private-room/albums/a1b2c3d4-0000-0000-0000-000000000000/unlock' \
- -H 'Authorization: Bearer ' \
- -H 'Content-Type: application/json' \
- -d '{"expectedCost":320}'
-```
-
-### 解锁成功
-
-```json
-{
- "code": 200,
- "message": "success",
- "success": true,
- "data": {
- "albumId": "a1b2c3d4-0000-0000-0000-000000000000",
- "locked": false,
- "unlocked": true,
- "reason": "ok",
- "unlockCost": 320,
- "creditsCharged": 320,
- "previousCreditBalance": 500,
- "creditBalance": 180,
- "images": [
- {
- "url": "https://...",
- "type": "image",
- "locked": false,
- "index": 0
- }
- ]
- }
-}
-```
-
-前端直接使用响应里的 `images` 替换锁卡,并用 `creditBalance` 刷新余额。
-
-### 积分不足
-
-业务失败仍返回 HTTP 200:
-
-```json
-{
- "code": 200,
- "message": "success",
- "success": true,
- "data": {
- "albumId": "a1b2c3d4-0000-0000-0000-000000000000",
- "locked": true,
- "unlocked": false,
- "reason": "insufficient_credits",
- "unlockCost": 320,
- "requiredCredits": 320,
- "creditBalance": 100,
- "shortfallCredits": 220,
- "creditsCharged": 0,
- "images": [
- {"url": "https://dbapi.banlv-ai.com/storage/v1/object/public/elio-schedules/01.jpg", "type": "image", "locked": true, "index": 0}
- ]
- }
-}
-```
-
-前端可以打开积分充值页,但后端不会创建图片包现金订单。用户充值积分后,再次点击同一个解锁接口。
-
-### 重复解锁
-
-```json
-{
- "unlocked": true,
- "locked": false,
- "reason": "already_unlocked",
- "creditsCharged": 0,
- "creditBalance": 180,
- "images": [{"url": "https://...", "locked": false, "index": 0}]
-}
-```
-
-## 7. `reason` 处理
-
-| `data.reason` | 含义 | 前端动作 |
-| --- | --- | --- |
-| `ok` | 已扣积分并解锁 | 显示真实图片并更新余额。 |
-| `already_unlocked` | 以前已解锁,本次不扣 | 直接显示返回图片。 |
-| `insufficient_credits` | 积分不足,未扣分 | 保持锁定,可引导购买积分。 |
-| `cost_changed` | 价格与 `expectedCost` 不一致 | 刷新列表并重新确认。 |
-| `unlock_in_progress` | 同一图片包正在并发解锁 | 禁用按钮并稍后刷新。 |
-| `deduct_failed` | 扣积分失败 | 保持锁定并允许重试。 |
-| `persist_failed_refunded` | 解锁记录失败,积分已尽力退回 | 保持锁定、刷新余额并告警。 |
-| `not_found` | 图片包不存在或已停用 | 移除卡片。 |
-
-## 8. TypeScript 建议
-
-```ts
-export interface PrivateAlbumImage {
- url: string;
- type: "image";
- locked: boolean;
- index: number;
-}
-
-export interface PrivateAlbum {
- albumId: string;
- momentId: string;
- characterId: string;
- collectionKey: string;
- title: string;
- content: string | null;
- previewText: string;
- imageCount: 8 | 15;
- mediaCount: 8 | 15;
- images: PrivateAlbumImage[];
- locked: boolean;
- unlocked: boolean;
- unlockCost: 320 | 600;
- requiredCredits: 320 | 600;
- creditCostPerImage: 40;
- currency: "credits";
- canUnlockWithCredits: boolean;
- publishedAt: string;
-}
-```
-
-## 9. 前端流程
-
-1. 进入图片包页面,调用 `GET /api/private-room/albums`。
-2. `locked=true` 时可使用返回 URL 渲染封面/模糊图,但必须覆盖锁层并禁止打开原图。
-3. 用户确认后调用解锁接口并传当前 `expectedCost`。
-4. `reason=ok/already_unlocked` 时使用返回的真实图片。
-5. `reason=insufficient_credits` 时保持锁定并引导购买积分。
-6. 充值完成后重新调用解锁接口,不需要恢复现金订单。
-7. 解锁请求进行中禁用按钮,避免重复点击。
-
-## 10. HTTP 错误
-
-| HTTP 状态 | 原因 | 处理 |
-| ---: | --- | --- |
-| 401 | Token 无效或缺失 | 刷新 Token/重新登录。 |
-| 422 | `albumId`、query 或 body 格式错误 | 修正请求。 |
-| 500 | 数据库或服务异常 | 保持当前锁定状态并允许重试。 |
-
-## 11. 测试方法
-
-1. 先在 pro 执行 `database/private-albums-migration.sql`。
-2. 使用 FB 测试导入生成一个 8 张图片包。
-3. 用少于 320 积分的测试账号请求解锁,确认不扣积分、不出现现金订单。
-4. 给测试账号补足积分,再请求解锁,确认扣 320 且返回 8 个真实 URL。
-5. 重复解锁,确认 `creditsCharged=0`。
-6. 刷新列表,确认仍为 `unlocked=true`。
-7. 15 张图片包按同样方式验证扣 600。
-8. 测试结束后删除测试素材、图片包、图片和解锁记录。
diff --git a/docs/backend/FRONTEND_TIP_PAYMENT_API.md b/docs/backend/FRONTEND_TIP_PAYMENT_API.md
deleted file mode 100644
index 9ae49a99..00000000
--- a/docs/backend/FRONTEND_TIP_PAYMENT_API.md
+++ /dev/null
@@ -1,132 +0,0 @@
-# Cozsweet 咖啡打赏接口
-
-## 1. 用途
-
-前端展示三个一次性咖啡打赏档位,并复用现有支付建单、支付跳转和订单轮询流程。
-
-## 2. 接口地址
-
-| 功能 | 方法 | 路径 | 鉴权 |
-| --- | --- | --- | --- |
-| 查询打赏品类 | GET | `/api/payment/tip-plans` | 不需要 |
-| 创建打赏订单 | POST | `/api/payment/create-order` | Bearer Token |
-| 查询订单状态 | GET | `/api/payment/order-status?order_id=...` | Bearer Token |
-
-## 3. 查询打赏品类
-
-```bash
-curl 'https://api.banlv-ai.com/api/payment/tip-plans'
-```
-
-成功响应:
-
-```json
-{
- "code": 200,
- "message": "success",
- "success": true,
- "data": {
- "plans": [
- {
- "planId": "tip_coffee_usd_4_99",
- "planName": "Small Coffee",
- "orderType": "tip",
- "tipType": "coffee_small",
- "description": "Buy Elio a small coffee",
- "amountCents": 499,
- "currency": "USD",
- "autoRenew": false,
- "isFirstRechargeOffer": false,
- "firstRechargeDiscountPercent": 0
- },
- {
- "planId": "tip_coffee_usd_9_99",
- "planName": "Medium Coffee",
- "orderType": "tip",
- "tipType": "coffee_medium",
- "description": "Buy Elio a medium coffee",
- "amountCents": 999,
- "currency": "USD",
- "autoRenew": false,
- "isFirstRechargeOffer": false,
- "firstRechargeDiscountPercent": 0
- },
- {
- "planId": "tip_coffee_usd_19_99",
- "planName": "Large Coffee",
- "orderType": "tip",
- "tipType": "coffee_large",
- "description": "Buy Elio a large coffee",
- "amountCents": 1999,
- "currency": "USD",
- "autoRenew": false,
- "isFirstRechargeOffer": false,
- "firstRechargeDiscountPercent": 0
- }
- ]
- }
-}
-```
-
-当前三个档位如下,顺序就是接口返回顺序:
-
-| `planId` | `tipType` | 价格 |
-| --- | --- | ---: |
-| `tip_coffee_usd_4_99` | `coffee_small` | USD 4.99 |
-| `tip_coffee_usd_9_99` | `coffee_medium` | USD 9.99 |
-| `tip_coffee_usd_19_99` | `coffee_large` | USD 19.99 |
-
-三个档位都不按国家换币、不参与首充半价,也不发会员或积分。前端必须使用接口返回的 `planId`,不要根据价格自行拼接。
-
-## 4. 创建打赏订单
-
-```bash
-curl -X POST 'https://api.banlv-ai.com/api/payment/create-order' \
- -H 'Authorization: Bearer ' \
- -H 'Content-Type: application/json' \
- -d '{
- "planId": "tip_coffee_usd_9_99",
- "payChannel": "stripe",
- "autoRenew": false
- }'
-```
-
-| 字段 | 类型 | 必填 | 固定/可选值 | 说明 |
-| --- | --- | --- | --- | --- |
-| `planId` | string | 是 | 上表三个 ID 之一 | 咖啡打赏产品 ID。 |
-| `payChannel` | string | 是 | `stripe` / `ezpay` | 支付渠道。 |
-| `autoRenew` | boolean | 是 | `false` | 打赏是一次性支付,必须传 false。 |
-
-成功响应与现有充值相同:
-
-```json
-{
- "code": 200,
- "message": "success",
- "success": true,
- "data": {
- "orderId": "pay_xxx",
- "payParams": {
- "url": "https://checkout.example/..."
- },
- "expiresAt": "2026-07-14T10:30:00+00:00",
- "expiresInSeconds": 1800
- }
-}
-```
-
-前端必须打开 `payParams` 中的支付 URL,并每 3-5 秒轮询订单状态。
-
-## 5. 订单状态与 WebSocket
-
-支付完成后:
-
-```json
-{
- "orderId": "pay_xxx",
- "status": "paid",
- "orderType": "tip",
- "planId": "tip_coffee_usd_9_99",
- "creditsAdded": 0
-}
-```
diff --git a/docs/backend/notify.md b/docs/backend/notify.md
deleted file mode 100644
index 9d70b1f8..00000000
--- a/docs/backend/notify.md
+++ /dev/null
@@ -1,3 +0,0 @@
-curl -X POST "https://flow.banlv-ai.com/webhooks/action-notify?chat_id=oc_xxx" \
- -H "Content-Type: application/json" \
- -d '{"message":"Gitea 内容操作完成,已同步。"}'
\ No newline at end of file