前端、业务后端、共享服务如何分工
用一个产品的操作拆清页面、业务规则、共享能力、数据所有者和部署位置。
当几个产品都需要登录、文件和管理页面时,很容易把一切放进一个总后端。短期少了几个入口,过一阵却可能不知道一个改动会影响谁。这一章用轻联的分工来讲。
三个部分,用一次撤销解释#
轻联由三块组成。本机连接器就是 npm 包 device-center,在你的电脑上提供面板(http://127.0.0.1:5174)和 MCP,只用本机时不需要账号。云端控制面是可选的:一个 Node.js 24 的模块化单体,用内置 SQLite 管设备登记、配对、回报、撤销和中转额度。账号交给 App Services 核验。
撤销一台设备时,面板收集点击,控制面在当前账号范围里找到设备并标记撤销,App Services 只回答“登录的是谁”。平台确认“你是谁”,轻联决定“你能不能撤销这台设备”。
门户、共享平台与独立模块#
我给自己的产品体系分了层,和这一章有关的是三层:
- 个人站是门户:介绍、导航和统一登录界面,不管其他产品的业务数据。
- App Services 是共享平台:账号与会话、产品空间、权益、用量、AI 网关和上传签名。
- 影片、Demo、轻联是独立模块:各有前端、业务后端和领域数据,独立版本、独立发布。
模块之间只经公开契约协作,不跨模块直写数据表。轻联在个人站的产品页只做介绍并链接公开指南,不显示设备在线状态或已绑定数量;控制面允许从别的网站顶层打开 /start、/login,但面板仍要登录,API 和写请求不在这个例外里。入口挂在个人站,不等于业务数据交给个人站。
按接入等级选共享能力#
同在一个体系里,三个产品用到的共享能力差别很大:
| 产品 | 接入等级 | 用了哪些共享能力 | 自己管的数据 |
|---|---|---|---|
| 轻联,只用本机 | 相当于 L0 | 不依赖任何在线服务 | 本机数据库 |
| 轻联官方控制面 | L2 统一账号 | 只核验身份 | 设备、配对、回报、中转计数 |
| 影片 | L3 平台能力 | 应用登记、产品空间与权益 | 作品与分享 |
| Demo | L1 展示 | 不用共享账号 | 自包含的静态页面 |
等级只表示接入了多少共享能力,升级要有真实需求。轻联只需要知道“是谁”,所以停在 L2:控制面向 App Services 的 /v1/me 核验身份,不复制签名密钥,不信任客户端自己解码的令牌,上游不可用时直接拒绝。影片要按产品开通成员和权益,是 L3。Demo 是有独立地址的自包含 H5 页面,用不到账号。
按数据所有者分工#
| 数据或动作 | 负责组件 | 必须回答的问题 |
|---|---|---|
| 面板操作与等待状态 | 账号面板、本机面板 | 显示的是不是真实回报 |
| 设备登记、配对、撤销 | 轻联云端控制面 | 当前账号能否操作这台设备 |
| 资源回报与中转计数 | 控制面自己的 SQLite | 回报是否来自已登记的连接器 |
| 账号核验 | App Services | 身份是否有效,上游不可用时是否拒绝 |
| 日志授权 | 目标设备上的连接器 | 哪个管理身份、哪个文件、到什么时候 |
设备表引用的账号空间,由 App Services 的核验结果算出;反过来,App Services 看不到设备。云端登记也不授予日志权限,读日志要目标设备另外授权。
共享能力需要合同:输入什么、返回什么、如何核验调用方、拒绝时是什么状态。新增共享能力,我的门槛是至少两个模块需要,或者必须集中管控安全与费用。轻联的中转额度只关乎它自己的流量,就由控制面持久计数,每账号每天 100 MiB。
独立服务不等于独占机器#
前端、业务服务和共享服务可以各自发布,却不必各占一台机器。我的规则是:独立发布不要求独立主机或独立仓库,但要有独立的版本、CI 和回滚。
反向代理负责 HTTPS,只把请求转给控制面监听的回环地址,并覆盖 Host 和 X-Forwarded-Proto。它不替控制面判断权限:控制面自己再核对 Host、HTTPS 标记和请求来源,对不上就拒绝。
画两张自己能画的图#
调用关系和数据关系分开画,别混在同一条箭头里。
- 调用图:从一个用户动作出发,标出每一跳凭什么身份。轻联里,批准、撤销凭账号会话;设备回报凭设备签名,归属只能来自已登记的连接器;发起配对不用登录,批准前不属于任何账号。
- 数据图:每张表只写一个负责组件。写不出唯一写入方,说明边界还没定。
轻联是怎么做的#
当时想解决什么。 第一版只在本机:面板读取这台电脑的真实内存和磁盘,MCP 交给本机 Agent。人在外面也想看设备、需要中转日志时,就得有一个本机之外的地方。
交给 Agent 什么。 我没有让云端接手本机的事。实现时要守的边界写在随包的架构和托管说明里:控制面不读服务器的 SSH,不把服务器装成管理电脑,没有云端远程 shell 或 MCP;账号经 App Services 核验,不新增注册接口;设备私钥留在设备上。
得到什么。 本机连接器不需要账号;设备、配对、回报和中转计数都在控制面自己的 SQLite 里;App Services 只回答身份。自建用同一个 CLI,--cloud 换成自己的 HTTPS 控制面,官方地址只是默认值;但账号仍要一套受信任的 App Services 和同父域会话,不是通用的第三方 OAuth。
怎样检查。 文档写明了隔离测试的范围:用临时身份和注入的上游,验证真实 TLS、中转密文、权限、账号和额度;也写明它们不是对真实设备的授权验收,不构成第三方安全审计。
为什么调整。 早期的控制面只接受配置里的一位所有者。官方服务要开放给其他人试用,0.2 系列切到多账号模式,账号空间取上游发行方与稳定 profile.id 的摘要,不按邮箱合并。改动全落在产品自己的数据上:登记表加了账号空间列,历史记录保留原归属。也因此多了一条规则:有了多账号数据,不能只把代码切回不支持账号查询的旧版本,旧版会读出所有账号的设备。
换成你自己的项目#
请读当前项目的代码和文档,整理服务边界,写到 docs/service-boundaries.md。这一步只写文档,不改代码。
1. 列出组件:前端、业务后端、用到的共享服务(账号、存储、AI 等),每个写一句职责和一句“不负责什么”。
2. 列出每类数据的唯一写入方;写不出的标为待决定。
3. 以主路径里的“[写一个操作]”为例画调用图,标出每一跳凭什么身份:账号会话、签名,还是匿名。
4. 写清共享服务不可用时,这个操作是拒绝、明示降级,还是误放行。
5. 判断项目需要哪一级共享能力:只要身份、还要产品空间与权益,或完全不用账号,说明理由。
不要写入密钥、主机地址和服务器路径。把方括号里的内容换成自己的需求。
- 每类数据只有一个写入方,没有“顺便存进共享服务”的业务表
- 调用图里每一跳都写了身份来源,没有直接信任前端传来的用户 ID
- 共享服务不可用时,结果是拒绝或明示降级
- 隐藏管理入口之后,直接调用业务 API 仍然被检查
下一章把这个边界变成工程目录与可重复启动的骨架。HTTP 合同可用 OpenAPI 描述;反向代理职责可参考 Nginx 官方入门。