Files
core/.trellis/tasks/09-20-port-adapter/prd.md
T

3.2 KiB
Raw Blame History

Dever Port 与 Adapter

Goal

把外部 HTTP、邮件、对象存储等依赖变成编译期验证、运行时可配置替换的 Port/Adapter 边界,同时收紧应用角色依赖,禁止 App 绕过 Port 和 Domain/Adapter 反向依赖业务层。

Dependencies

  • secure-data-contracts:Secret setting 和不可观察边界。
  • time-typed-codec:类型化 setting 解码和共享 wire schema。

Requirements

  • port.dever/port/*.dever 只允许类型和 bodyless function contract;每个 contract 显式 fails 同领域 App 公开 error choice 或公开标准 error choice,至少一个显式 error variant。Port 自有 DTO 仍私有。
  • Port contract 输入、命名输出、failure contract 和逻辑身份稳定,不从任一 Adapter 实现反推。
  • Adapter 通过 qualified Port target 显式实现;签名必须相同,实际 failure set 必须是声明集合的子集。
  • Adapter 可包含同文件私有类型/helper,但不能调用 App、Domain、Model、其他 Adapter 或 Port;只能调用标准库和自身 helper。
  • App 只能调用同领域 Port;Domain 只能调用同领域 Domain;Model 无业务函数;API/Job 只调用同领域 App。
  • Port 调用的 suspend/effect 是所有可选实现的保守并集,仍由现有静态 effect 系统决定 worker/await 边界。
  • 单实现自动绑定;多个实现必须由 config/setting.json 的稳定 Port identity 选择,未配置、未知实现或未知 setting 字段启动失败。
  • Adapter 可声明一个 typed setting record;只有被选择实现的 setting 必须存在并解码,Secret 字段不进入日志/错误。
  • 编译产物包含闭合实现集合和直接 match,不使用动态库、反射、trait-object business dispatch 或运行时源码扫描。
  • Test 可在同一个测试文件完整 fake 多个 Port;fake 只绑定当前 TestCase,测试不读取项目 Adapter setting 或回退到生产实现。
  • Port/Adapter 的 .dever.md 文档合同与普通源码一致。

Acceptance Criteria

  • 合法 bodyless Port 和单 Adapter 可被 App 调用并生成直接静态实现调用。
  • Port body、Adapter 缺失/重复实现、签名/命名输出/failure 不匹配在 check 阶段拒绝。
  • App 直调 Adapter、Domain 访问 Model/Port/Adapter、Adapter 反调 App/Domain/Model 和跨领域 Port 调用全部拒绝。
  • 多 Adapter 通过 setting.json 在不重新编译的情况下选择;未知选择、缺配置、未知字段和错误类型启动失败。
  • 未选择 Adapter 的 setting 不要求存在,其代码仍通过静态检查并包含在闭合产物中。
  • Secret setting 可以用于批准 sink,但不能出现在日志、错误、API/Job output 或普通字符串中。
  • 两个应用测试可以对同一 Port 使用不同 fake,单套件编译后各自运行且互不泄漏。
  • Port effect/failure 通过 App、transaction、handler specialization 正确传播,不出现动态 fallback。

Out Of Scope

  • 运行时安装插件、动态库、服务发现和远端代码加载。
  • 跨领域直接共享 Port;领域间继续通过 App 合同协作。
  • 通用依赖注入容器、Service locator 或应用可变全局 registry。
  • Adapter 热切换;setting 在进程启动时验证并固定。