# 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 <TOKEN>
```

### 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 <TOKEN>' \
  -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": "<JWT>",
    "refreshToken": "<REFRESH_TOKEN>",
    "matchedBy": "psid",
    "fbAsid": "1582386133449953",
    "fbPsid": "37370387172559600",
    "hasCompleteFacebookIdentity": true,
    "isGuest": false,
    "user": {
      "id": "<USER_ID>",
      "fbAsid": "1582386133449953",
      "fbPsid": "37370387172559600"
    }
  }
}
```

### Success Response: 未知或绑定不完整，返回游客

查不到 PSID，或 PSID 对应用户还没有 ASID 时，不当作 Facebook 登录，只返回游客 token:

```json
{
  "code": 200,
  "message": "Facebook PSID 未匹配，已返回游客登录",
  "success": true,
  "data": {
    "token": "<GUEST_JWT>",
    "refreshToken": "",
    "matchedBy": "guest",
    "fbPsid": "37370387172559600",
    "fbAsid": null,
    "hasCompleteFacebookIdentity": false,
    "isGuest": true,
    "userId": "<GUEST_USER_ID>"
  }
}
```

如果 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 的逻辑和原登录流程一致。
