# Zust + Rust 服务器设计

摘自《Harness 原则 / AGENTS.md》。这一部分可以单独复制到项目的 AGENTS.md 或团队规范中使用。

## 3. Zust + Rust 的服务器架构设计

典型 Zust + Rust 服务端项目通常分为这些层：

```text
client(s)
  -> HTTP / WebSocket / platform bridge
  -> Rust server
  -> Zust route dispatch
  -> Zust business scripts
  -> database / ROOT / runtime state
```

常见目录职责：

```text
server/
  src/              # HTTP、WebSocket、静态文件、上传处理、分发
  scripts/          # Zust 启动、路由、系统、世界、UI、业务逻辑
  static/           # 被服务端托管的资源，或构建后的客户端产物

client/
  shared/           # 跨端 DTO、API 契约、共享状态/页面
  apps/*            # Web、Android、小程序、桌面端、管理端或其他壳工程

docs/
  *.md              # 架构说明和接入文档
```

服务端拥有游戏或业务状态的权威性。客户端输入应被视为意图，而不是真实状态。移动、碰撞、战斗、任务进度、经济、背包、鉴权和状态推进默认都属于服务端，除非项目文档另有说明。

Rust 服务端负责基础设施：

- HTTP 路由、headers、body 限制、静态文件、上传和 WebSocket 建连。
- 把请求 payload 规范化后交给 Zust。
- 脚本加载、ROOT 初始化、路由分发和响应转换。
- 处理平台传输约束，例如 WebSocket 鉴权限制。

Zust 脚本负责领域行为：

- 启动配置和路由注册。
- 业务校验、权限检查、状态变更和响应数据。
- 服务端驱动 UI 时的 UI、dialog、panel 结构。
- ROOT 中的运行期状态和数据库中的持久状态。

### HTTP 分发

HTTP 层应只做直接、可预测的映射：`POST /api/foo` 映射到 `local/http/post/foo`，`GET /api/foo` 映射到 `local/http/get/foo`，不要在 Rust HTTP 层塞业务分支。

简单项目可以在 `start.zs` 里直接注册这些 `local/http/*` handler 并完成分发。复杂项目则让 `start.zs` 调用各系统自己的启动函数，由系统内部注册和分发自己的 HTTP 路径。

```text
HTTP method + path
  -> local/http/{method}/{path}
  -> root::send_msg(...) 或等价分发
  -> Zust handler
  -> map/list response
  -> HTTP response conversion
```

开发环境可以直接使用 HTTP；HTTPS 应由统一网关、反向代理或部署层提供，不要让每个业务服务重复实现证书和 TLS 细节。

简单、公开、对后台完全只读的接口可以使用 GET 语义。其他情况使用 POST 语义；没有把握时也使用 POST。公开图片获取、公开产品信息查询等不需要考虑参数安全的场景，可以使用 query 参数。其他大部分接口使用 POST + JSON body。

请求 payload 应在保留字段中保存传输元数据，例如 `@method`、`@path`、`@header`、`@query`，再合并通过校验的 JSON body 字段。

响应 map 可以使用 `@status`、`@content-type`、`@body` 等保留字段。没有自定义响应需求时，普通 map/list 可直接作为 JSON 返回。

HTTP 状态码 `200` 表示调用路径正确、请求参数格式正确、服务端成功返回业务结构。业务返回尽量使用 JSON 数据结构；一般使用 `code` 表示业务返回码，`0` 表示正确，使用 `message` 或 `msg` 表示返回信息。

multipart 上传通常应先在 Rust 层处理。文件名、content-type、字节数据和业务字段解析完成后，再打包成有明确类型的 payload 交给 Zust。不要假设上传路由和普通 JSON 路由完全一样。

### WebSocket 分发

WebSocket 分发应拆开 auth、connect、message、disconnect handler。推荐注册稳定路径，例如：

```text
local/ws_handlers/auth
local/ws_handlers/connect
local/ws_handlers/message
local/ws_handlers/disconnect
```

### 事务和调试

任何包含多次持久化写入的业务动作，都需要一个事务，或等价的原子边界。

通用顺序：

1. 校验输入和权限。
2. 锁定或读取必须保持一致的状态。
3. 一次性完成状态、流水、索引和缓存更新。
4. 只提交一次。
5. 失败时整体回滚。

不要让业务流程停留在半成功状态。

服务端问题的调试顺序：

1. 确认路由注册在预期 ROOT 路径。
2. 确认 method/path 或 WebSocket message type 与注册一致。
3. 确认 payload 字段和运行时类型。
4. 运行或隔离 Zust handler。
5. 确认数据库写入和事务行为。
6. 确认响应结构符合 Rust 转换层约定。

### 验证命令

使用能证明本次改动的最窄命令。

```bash
cd server
cargo test
cargo check
cargo run
cargo run --bin import_tmx_maps
```

如果命令不可用、太慢或被环境限制阻塞，要说明原因，并说明实际验证了什么。
