# 轻客户端原则

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

## 4. 客户端的基本原则

这里的“客户端”指任何 UI 或平台层：共享跨端代码、Web、Android、iOS、小程序、桌面端、管理端、测试壳或其他 runtime。

客户端职责应保持窄边界：

- 渲染服务端状态。
- 收集用户输入并发送意图。
- 维护真正属于表现层的本地 UI 状态。
- 为网络、存储、图片、文件、上传、状态栏、权限和 native view 实现平台 adapter。

如果项目存在共享客户端层，DTO、API 契约、消息解析和核心页面/状态逻辑应放在那里。平台壳负责适配平台能力，不要 fork 业务行为。

生成产物不是源码。除非用户明确要求修改某个生成产物，并且知道它会被构建流程覆盖，否则不要手改构建输出。

### 服务端驱动 UI

当服务端下发 UI 数据时，客户端只渲染这些数据。客户端不得发明缺失的视觉、文字、动作或默认值来掩盖协议错误。

- `images` 描述外观。
- `hotspots` 描述点击/触摸区域，并回传 `panel_id + action_id`。
- 文字、图片、选中态和可见性应来自服务端数据。
- 所有后续可能变化的 UI 元素都需要稳定 `id`。
- 首包应发送完整 panel/dialog 结构。
- 后续更新应使用稳定 patch 协议，例如 `panel_id.element_id -> value`。

如果服务端没有下发必需图片、hotspot、id 或文字，调试阶段应暴露缺失信息，而不是静默画一个替代品。

### 响应式和跨端

对任何响应式客户端框架，都不要先把动态列表算成一次性局部快照，再长期依赖它。应在 render/update 边界内读取响应式状态，或使用该框架已验证的列表重建模式。

UI 不更新时，按顺序检查请求是否成功、回调是否执行、状态是否变更、渲染是否失效/重建、平台 adapter 是否正确。

Web 可用不代表 native 或小程序可用。需要分别确认平台 API base URL、网络权限、token 存储、图片 adapter、上传路径、状态栏处理和 WebSocket 鉴权约束。

mock connector 和测试账号也应走与真实连接一致的鉴权、刷新、解析和更新路径，除非用户明确要求纯 UI mock。

### 资源和 CDN

资源要尽可能复用，不要重复下载。图片、Spine/动画资源、地图、脚本包、字体和构建产物都应有稳定 URL、缓存策略和复用路径。

可长期缓存的资源应使用内容哈希、版本号或改名方式发布。AI 时代生成和批量改名的成本更低，因此更新资源时优先通过新文件名或新版本路径触发刷新，而不是让客户端反复下载同名资源。

静态资源应尽量走 CDN 提速。服务端只负责生成、引用、鉴权或回源控制；高频访问的大图片、地图、动画、构建包和公共库应交给 CDN 缓存分发。

图片不显示时，先调试真实路径，不要先加 placeholder 逻辑。

检查顺序：

1. 状态中是否包含预期 URL 或资源路径。
2. URL 是否可直接访问。
3. 响应字节是否与 content-type 匹配。
4. 图片 source 是否在 render/update 边界内读取实时状态。
5. 动态列表是否真的重建或 patch。
6. native 或平台 image adapter 是否已注册。

placeholder 可以是最终产品体验的一部分，但不能作为调试捷径掩盖坏数据。

### 客户端验证

客户端问题的调试顺序：

1. 确认请求或 WebSocket 消息已发送。
2. 确认响应已到达并解析成功。
3. 确认回调或消息处理已执行。
4. 确认状态已更新。
5. 确认 UI 已失效、重建或 patch。
6. 确认平台 actual/adapter 行为与共享语义一致。

常用客户端命令：

```bash
cd client
gradle :apps:miniapp:jsMiniAppDevelopmentWebpack
./gradlew build
```
