hyapp-server/docs/多App租户架构.md

111 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 不需要拆新微服务;只有当业务规则、部署生命周期或数据合规要求必须强隔离时,才考虑单独部署一套服务集群。