# Agency 资料与房间 Flutter 对接

## 基础约定

本地开发地址：

```text
http://127.0.0.1:13000
```

所有接口都是登录接口，需要带登录 token。

请求头：

| Header | 必填 | 说明 |
| --- | --- | --- |
| `Authorization` | 是 | `Bearer <access_token>`。 |
| `X-App-Code` | 否 | App 编码，默认 `lalu`；登录态接口最终以 token 内 app_code 为准。 |

成功和失败都使用统一 envelope：

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_xxx",
  "data": {}
}
```

客户端分支只判断 `code`，排查问题记录 `request_id`。

## 1. 查询用户所属 Agency 资料

地址：

```http
GET /api/v1/agencies/profile
```

参数：

| 参数 | 位置 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- | --- |
| `user_id` | query | 是 | string/int64 | 被查看的 host 用户 ID。 |

示例：

```http
GET /api/v1/agencies/profile?user_id=10001
Authorization: Bearer <access_token>
X-App-Code: lalu
```

返回值：

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_abc",
  "data": {
    "agency": {
      "agency_id": "7001",
      "owner_user_id": "99",
      "region_id": 30,
      "parent_bd_user_id": "501",
      "name": "Yumi Star Agency",
      "avatar": "https://cdn.example/agency.png",
      "host_count": 20,
      "status": "active",
      "join_enabled": true,
      "created_by_user_id": "1",
      "created_at_ms": 1710000000000,
      "updated_at_ms": 1710000001000
    }
  }
}
```

没有 active host 身份，或没有 active agency 归属时：

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_abc",
  "data": {
    "agency": null
  }
}
```

字段说明：

| 字段 | 说明 |
| --- | --- |
| `agency_id` | Agency ID，字符串。 |
| `owner_user_id` | Agency 会长用户 ID，字符串。 |
| `name` | Agency 自己的名称，不再读 owner 用户昵称。 |
| `avatar` | Agency 自己的头像，不再读 owner 用户头像。 |
| `host_count` | 当前 active host 数量。 |
| `status` | 当前只展示 `active`。 |
| `join_enabled` | 是否允许用户申请加入。 |
| `created_at_ms` / `updated_at_ms` | Unix epoch milliseconds。 |

## 2. 查询 Agency 下所有 host 的房间

地址：

```http
GET /api/v1/agencies/rooms
```

参数：

| 参数 | 位置 | 必填 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `user_id` | query | 是 | string/int64 | 无 | 被查看的 host 用户 ID。 |
| `limit` | query | 否 | int | 20 | 每页数量，最大 50。 |
| `cursor` | query | 否 | string | 空 | 下一页 cursor。 |
| `tab` | query | 否 | string | `hot` | `hot` 或 `new`。 |
| `query` | query | 否 | string | 空 | 搜索房间标题、房间 ID 或短号。 |

示例：

```http
GET /api/v1/agencies/rooms?user_id=10001&tab=hot&limit=20
Authorization: Bearer <access_token>
X-App-Code: lalu
```

返回值：

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_abc",
  "data": {
    "agency_id": "7001",
    "rooms": [
      {
        "room_id": "room_101",
        "im_group_id": "room_101",
        "owner_user_id": "101",
        "title": "Agency Room",
        "cover_url": "https://cdn.example/room.png",
        "mode": "voice",
        "status": "active",
        "locked": false,
        "heat": 88,
        "online_count": 12,
        "seat_count": 8,
        "occupied_seat_count": 3,
        "visible_region_id": 30,
        "app_code": "lalu",
        "room_short_id": "M20",
        "country_code": "AE",
        "country_flag": "🇦🇪"
      }
    ],
    "next_cursor": "cursor_xxx"
  }
}
```

没有 active host 身份，或没有 active agency 归属时：

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_abc",
  "data": {
    "agency_id": "",
    "rooms": [],
    "next_cursor": ""
  }
}
```

字段说明：

| 字段 | 说明 |
| --- | --- |
| `agency_id` | 当前查询到的 Agency ID；无归属时为空字符串。 |
| `rooms` | Agency 下所有 active host 的 active 房间。 |
| `next_cursor` | 下一页 cursor；为空表示没有下一页。 |
| `room_id` | 房间 ID。 |
| `im_group_id` | 腾讯云 IM 房间群 ID，进群使用这个字段。 |
| `owner_user_id` | 房主用户 ID，字符串。 |
| `title` | 房间名。 |
| `cover_url` | 房间封面。 |
| `locked` | 是否锁房。 |
| `heat` | 房间热度。 |
| `online_count` | 在线人数。 |
| `seat_count` | 麦位数量。 |
| `occupied_seat_count` | 已占用麦位数量。 |
| `room_short_id` | 房间短号。 |
| `country_code` / `country_flag` | 房主国家展示字段。 |

## 3. 修改 Agency 资料

地址：

```http
POST /api/v1/agencies/profile/update
```

权限：

只有当前登录用户是 active Agency owner 时可以修改。普通 host、Agency 成员、BD、非 active owner 都不能修改。

参数：

| 参数 | 位置 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- | --- |
| `command_id` | body | 是 | string | 客户端生成的幂等 ID。 |
| `name` | body | 否 | string | 新 Agency 名称。 |
| `avatar` | body | 否 | string | 新 Agency 头像 URL。 |

`name` 和 `avatar` 至少传一个；传了就不能是空字符串。修改 Agency 资料不会修改 owner 用户昵称和头像。

示例：

```http
POST /api/v1/agencies/profile/update
Authorization: Bearer <access_token>
X-App-Code: lalu
Content-Type: application/json

{
  "command_id": "cmd_agency_profile_001",
  "name": "New Agency Name",
  "avatar": "https://cdn.example/new-agency.png"
}
```

返回值：

```json
{
  "code": "OK",
  "message": "ok",
  "request_id": "req_abc",
  "data": {
    "agency": {
      "agency_id": "7001",
      "owner_user_id": "42",
      "region_id": 30,
      "name": "New Agency Name",
      "avatar": "https://cdn.example/new-agency.png",
      "host_count": 20,
      "status": "active",
      "join_enabled": true,
      "created_at_ms": 1710000000000,
      "updated_at_ms": 1710000005000
    }
  }
}
```

## 错误处理

失败返回：

```json
{
  "code": "INVALID_ARGUMENT",
  "message": "invalid argument",
  "request_id": "req_abc"
}
```

| HTTP 状态码 | `code` | 处理方式 |
| --- | --- | --- |
| `400` | `INVALID_ARGUMENT` | 参数错误，例如 `user_id` 非法、`tab` 非法、`limit` 非法、缺少 `command_id`、`name/avatar` 都没传或传空。 |
| `401` | `UNAUTHORIZED` | token 缺失、无效或过期，重新登录。 |
| `403` | `PROFILE_REQUIRED` | 用户资料未完成，跳转资料补全。 |
| `403` | `PERMISSION_DENIED` | 修改接口中当前用户不是 active Agency owner，不允许修改。 |
| `404` | `NOT_FOUND` | 修改接口中 Agency 事实不存在；刷新当前用户身份后再进入页面。 |
| `409` | `CONFLICT` | `command_id` 与已有不同命令冲突；重新生成新的 `command_id` 再提交。 |
| `502` | `UPSTREAM_ERROR` | 服务暂不可用，可以提示稍后重试。 |

客户端处理规则：

1. 查询资料时，`agency == null` 是正常空状态，不弹错误。
2. 查询房间时，`rooms == []` 是正常空列表，不弹错误。
3. 修改资料成功后，用返回的 `data.agency` 刷新页面，不要用 owner 用户资料覆盖。
4. 修改失败时保留本地未保存状态，让用户可以重试。
5. 所有失败日志记录 `request_id`。

## 相关 IM

无。Agency 资料修改和 Agency 房间列表不会下发新的 IM；房间卡片里的 `im_group_id` 只用于进入房间时加入腾讯云 IM 房间群。
