111 lines
5.0 KiB
Markdown
111 lines
5.0 KiB
Markdown
# Multi App Tenant Architecture
|
||
|
||
本文定义 `hyapp-server` 同时服务多个 App 时的租户边界。当前后端不再默认只服务单个 App;`popoo`、`lalu`、`siya` 这类产品都必须先解析成内部 `app_code`,再进入用户、房间、钱包、活动和 host 业务链路。
|
||
|
||
## Core Rule
|
||
|
||
`app_code` 是后端内部租户键。客户端包名、Bundle ID、渠道名和展示 App 名都不能直接作为业务表隔离键。
|
||
|
||
首个内置映射:
|
||
|
||
| package_name | platform | app_code | status |
|
||
| --- | --- | --- | --- |
|
||
| `com.org.laluparty` | `android` | `lalu` | `active` |
|
||
|
||
新增 App 时,只新增 `apps` 注册表记录和对应 App 的基础配置/种子数据,不新建一套服务,也不复制业务代码。
|
||
|
||
## App Registry
|
||
|
||
`apps` 表由 `user-service` 持有,放在 `hyapp_user` 库:
|
||
|
||
```sql
|
||
apps(
|
||
app_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||
app_code VARCHAR(32) NOT NULL,
|
||
app_name VARCHAR(128) NOT NULL,
|
||
package_name VARCHAR(191) NOT NULL,
|
||
platform VARCHAR(32) NOT NULL DEFAULT '',
|
||
status VARCHAR(32) NOT NULL,
|
||
created_at_ms BIGINT NOT NULL,
|
||
updated_at_ms BIGINT NOT NULL,
|
||
UNIQUE KEY uk_apps_code (app_code),
|
||
UNIQUE KEY uk_apps_package_platform (package_name, platform)
|
||
);
|
||
```
|
||
|
||
`gateway-service` 可以通过包名和平台解析 `app_code`,也可以校验显式传入的 `app_code`。解析入口是 `user-service.AppRegistryService.ResolveApp`。
|
||
|
||
## Request Flow
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as Client
|
||
participant G as gateway-service
|
||
participant U as user-service
|
||
participant R as room-service / wallet-service / activity-service
|
||
|
||
C->>G: HTTP request + package/platform/app_code header
|
||
G->>U: ResolveApp(package_name, platform, app_code)
|
||
U-->>G: active app_code
|
||
G->>G: write request context and JWT claims
|
||
G->>R: gRPC RequestMeta.app_code
|
||
R->>R: all reads and writes are scoped by app_code
|
||
```
|
||
|
||
Header 约定:
|
||
|
||
| Header | Meaning |
|
||
| --- | --- |
|
||
| `X-App-Code` / `X-HY-App-Code` / `App-Code` | 已知内部 `app_code` |
|
||
| `X-App-Package` / `X-Package-Name` / `X-App-Bundle-ID` / `X-Bundle-ID` | 客户端包名或 Bundle ID |
|
||
| `X-App-Platform` / `X-Platform` | `android` 或 `ios` |
|
||
|
||
已登录请求以 JWT 里的 `app_code` 为准。未登录登录/注册请求允许通过包名解析;解析成功后,`user-service` 签发的 token 必须带同一个 `app_code`。
|
||
|
||
## App Scoped IDs
|
||
|
||
对客户端暴露的用户长 ID 和房间长 ID 都带 App 前缀,格式为:
|
||
|
||
```text
|
||
<app_code>_<uuid>
|
||
```
|
||
|
||
例如 `com.org.laluparty` 解析到 `lalu` 后,新用户的 `user_id` 是数值型主键,新房间的 `room_id` 仍按 App 生成 `lalu_<uuid>`。服务间主关联使用 `users.user_id`,JWT 只携带数值型 `user_id`,gateway 直接把该 ID 透传给后端 RPC。
|
||
|
||
用户短号 `display_user_id` 按 App 独立发号,首个号段从 `163000` 开始。创建房间时 `room_short_id` 等于创建者当前短号,用于客户端搜索、分享和展示。
|
||
|
||
## Data Boundary
|
||
|
||
以下业务库表都必须有 `app_code`,并且查询、唯一键和幂等键都必须带 `app_code`:
|
||
|
||
| Service | Database | Scope |
|
||
| --- | --- | --- |
|
||
| `user-service` | `hyapp_user` | `users`、登录身份、session、国家、区域、短号、host/Agency/BD 事实 |
|
||
| `room-service` | `hyapp_room` | 房间元数据、房间列表、快照、命令日志、room outbox |
|
||
| `wallet-service` | `hyapp_wallet` | 账户、交易、分录、wallet outbox、礼物价格 |
|
||
| `activity-service` | `hyapp_activity` | 活动状态、事件消费幂等、activity outbox |
|
||
|
||
规则:
|
||
|
||
- 跨 App 可以存在相同 `display_user_id`、相同三方 `provider_subject`、相同钱包 `command_id`;对外长 ID 自带 `app_code` 前缀,仍然要求落库唯一键带 `app_code`。
|
||
- 业务查询不能只用 `user_id`、`room_id` 或 `command_id`;必须同时带 `app_code`。
|
||
- outbox envelope 必须带 `app_code`,消费者按事件所属 App 落库和幂等。
|
||
- 默认 `lalu` 只用于本地开发和历史测试兜底;真实客户端请求必须能解析出明确 App。
|
||
|
||
## Admin Boundary
|
||
|
||
后台管理后端使用独立 `hyapp_admin` 库,不把后台审计表写进 App 业务库。后台操作某个 App 的用户、区域、host、钱包或房间时,HTTP 请求必须显式携带或由后台上下文选择 `app_code`,再调用对应业务能力。
|
||
|
||
`hyapp_admin.admin_operation_logs` 可以在 `detail` 中记录 `app_code`、目标对象和变更摘要;不要为了审计把 admin 表复制到各 App 业务库。
|
||
|
||
## Adding A New App
|
||
|
||
以新增 `popoo` 为例:
|
||
|
||
1. 在 `apps` 表插入 `app_code=popoo`、包名、平台和状态。
|
||
2. 为 `popoo` 初始化国家、区域、礼物价格、登录 provider/Firebase 配置。
|
||
3. 客户端请求携带包名和平台,gateway 解析到 `popoo`。
|
||
4. 注册、房间、钱包、活动、host 数据自动按 `app_code=popoo` 写入现有表。
|
||
|
||
新增 App 不需要拆新微服务;只有当业务规则、部署生命周期或数据合规要求必须强隔离时,才考虑单独部署一套服务集群。
|