# 星线智联接入流程

智联的接入方是 Account 原浏览器及固定微信小程序，不是任意第三方登录 SDK。所有后端路由使用 `https://account.thestarline.cn`，路径前缀为 `/api/providers/wechat/mobile`。资料依据 2026 年 10 月 23 日 `identity/server/protocols.ts`、`wechat-mobile.ts` 和 `identity/mini-program/lib/` 整理；目前联调暂停、开发上传未审核，完整流程仍待验收。

## 能力发现与发起条件

`GET /api/auth/methods` 当前返回 `wechatMobile.available`。网页应按当前响应显示入口，不根据工程内存在确认页、旧上传记录或单个 enabled 标志判断可用。服务端公众可用判断要求独立小程序配置完整、与网站微信身份不同、enabled、published、launchEnabled 均满足。

发起、状态、取消、领取和绑定是浏览器操作，仍要求 Account 来源、Cookie、CSRF 与上下文绑定。只有小程序 inspect、decide 使用单次证明免除浏览器 Cookie CSRF；若它们携带 Origin，仍只允许账户来源。这不是整个前缀免鉴权。受控预览入口另要求已认证的 Account 管理员及允许的管理登录方式。

| 方法与完整路径 | 输入 | 返回或含义 |
| --- | --- | --- |
| `POST /api/providers/wechat/mobile/start` | `intent:"login"` | `receiverToken,verificationCode,expiresAt,interval,launchUrl` |
| `POST /api/providers/wechat/mobile/preview/start` | `intent:"login"` | 管理员受控路径，返回 `previewPath`，不返回正式 URL Link |
| `POST /api/providers/wechat/mobile/inspect` | `scanToken,code` | `approvalToken,targetOrigin,browser,verificationCode,expiresAt` |
| `POST /api/providers/wechat/mobile/decide` | `approvalToken,decision` | `status:"approved"` 或 `"cancelled"` |
| `POST /api/providers/wechat/mobile/status` | `receiverToken` | 当前 `status,expiresAt` |
| `POST /api/providers/wechat/mobile/complete` | `receiverToken` | 返回 `redirect`，进入账户登录或待绑定处理，可能设置浏览器 Cookie |
| `POST /api/providers/wechat/mobile/cancel` | `receiverToken` | 取消尚可取消的事务 |
| `GET /api/providers/wechat/mobile/pending` | 无正文 | 查询当前浏览器是否有待绑定身份 |
| `POST /api/providers/wechat/mobile/bind` | `grantId`，以及当前浏览器待绑定 Cookie | 将待绑定小程序身份关联到已验证账户 |

expiresAt 为 Unix 毫秒，interval 单位为秒，当前为 5。服务器状态轮询有单独路由额度，但并不取消全局与来源限额；不要把 160 的路由配置理解为允许无限并发请求。

## 浏览器与手机的操作次序

1. 原浏览器取得 CSRF 后 start，内存保留 receiverToken、服务端 expiresAt 和两位 verificationCode。仅把服务端允许的 launchUrl 用于微信唤起，不拼接任意外部网址。
2. 确认页校验 scanToken 后只执行一次 wx.login，将 code 与扫描证明传给 inspect。缺失、非法参数时不执行 wx.login，不调用后端。
3. 服务端先锁定 receiver，再锁扫描证明，消费 scan 后才调用微信交换。交换成功返回短时 approvalToken；扫描证明已用，不能因页面刷新自动重放。
4. 小程序验证 targetOrigin 必须精确等于账户 HTTPS 来源，verificationCode 为两位数字字符串，expiresAt 为正的安全整数毫秒值，展示后才允许用户决定。
5. 用户点击确认或取消，发出一次 decide；decision 只能 `approve` 或 `deny`。响应应与本次决定匹配。小程序结束后提示手动返回原浏览器。
6. 原浏览器按间隔读取 status，approved 后 complete。完成时再次核对微信绑定与账户凭据版本，并原子消费 receiver，重复领取被拒绝。

合成请求体只表达结构，不能作为实际可用凭据：

```json
{"scanToken":"<本次页面收到的单次扫描证明>","code":"<本次wx.login临时code>"}
```

```json
{"approvalToken":"<inspect返回且仅保存在页面内存的证明>","decision":"approve"}
```

这些字符串不应出现在日志、截图、分析事件、`setData`、Storage 或复制分享内容中。小程序不接收 receiverToken；浏览器不凭 approvalToken 直接换会话。两位核对码只用于人工核对，不是决定接口的身份凭据。

## 状态机与绑定

| 服务端状态 | 浏览器 status 可见值 | 客户端动作 |
| --- | --- | --- |
| pending / exchanging / awaiting_confirmation | pending | 继续有限轮询，等待明确决定 |
| approved | approved | 原浏览器调用 complete |
| cancelled | cancelled | 停止，用户可重新开始新事务 |
| failed | failed | 停止并报告失败，旧证明不可再用 |
| 超过期限 | expired | 重新开始，不延长本次事务 |
| 已消费 receiver | 错误响应 | 不再重复领取 |

inspect 成功时保存的预期绑定包含当时关联的用户与凭据版本。等待期间有人解绑、改凭据或改变身份关联，complete 会重新检查，防止旧批准继续生效。未绑定身份进入 Account 的后续登录/绑定处理；批准本身不会自动创建一个已验证的业务账户。通用 `/api/providers/:provider/start` 不是小程序启动入口；移除已绑定身份则走相应 provider/remove，并受重新验证与最后凭据保护约束。

## 网络与错误处理

API 封装 wx.login 超时为 10 秒，请求超时为 15 秒；服务端访问微信也有限时和响应大小校验。小程序只显示本地固定提示，不原样呈现后端错误内容。调用方可按错误码定位，但不得记录携带的证明。

| 状态与代码 | 触发场景 | 处理 |
| --- | --- | --- |
| 400 `INVALID_TRANSACTION` | 证明格式不符、到期、已消费、状态不允许 | 返回原浏览器开始新请求 |
| 403 `CONTEXT_CHANGED` | 换浏览器领取 | 使用原发起浏览器，不转发 receiver |
| 403 `FORBIDDEN` / `CSRF_FAILED` | 非账户来源、管理员门禁或浏览器证明错误 | 核对来源、会话及能力范围 |
| 401 `INVALID_CREDENTIALS` | 等待期间微信绑定已改变 | 重新验证，不套用旧批准 |
| 502 `PROVIDER_FAILED` | 微信交换或 URL Link 获取失败 | 核对微信平台条件与服务端审计，重新发起 |
| 503 `PROVIDER_UNAVAILABLE` | 当前模式未开通 | 保持入口关闭，不虚报 published |

decide 提交后断网或在途跨期为 uncertain，不能自动再次提交批准；服务器可能已接受。检查原浏览器状态后再决定是否开始新事务。页面卸载取消本地请求不代表服务端已经撤销决定；需要原浏览器 cancel 才能按服务端规则改变事务。进入后台也不增加五分钟有效期。

## 检查与发布范围

在 `identity/mini-program/` 可使用 `npm test`、`npm run validate` 检查状态机与工程；账号服务测试在 `identity/tests/wechat-mobile.test.ts`、`wechat-mini-adapter.test.ts`。开发者工具编译、游客预览和合成 UI fixture 分别验证结构与显示，不能证明真实身份、审批或 Cookie 保持。

正式接入还需核对小程序主体、请求合法域名、独立服务端身份、隐私保护指引、体验与审核可执行入口，以及微信正式 URL Link 能力。现有记录已验证手机批准及原浏览器领取待绑定凭据，仍需完成实际绑定、微信复登与会话保持，再按真实审核号与发布回执记录状态。现有 `0.1.0` 开发上传不能替代这些回执，暂停流程需另行恢复。范围说明见[技术概览](https://document.thestarline.cn/zhilian/overview.md)。
