feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

@@ -0,0 +1,3 @@
{"file":".trellis/spec/backend/quality-guidelines.md","reason":"Bounded HTTP/1, HTTP/2 and resource tests"}
{"file":".trellis/spec/backend/error-handling.md","reason":"Input/API/internal error mapping"}
{"file":".trellis/spec/backend/directory-structure.md","reason":"Thin API owner and shared HTTP path"}
@@ -0,0 +1,130 @@
# Dever 生产 API 边界设计
## 2026-09-28 自动权限设计
### 静态权限身份
权限是 checked HIR 的入口元数据,不是业务 Text 常量。每个非 public API 入口拥有一个 `Permission`:`key/component/domain/site/action/method`。site 由现有目录映射得到,custom action 来自 API 声明,REST 展开为 read/create/replace/delete。key 不包含 HTTP method;同一 component/domain/site 下重复自定义 action 必须静态拒绝。public 入口没有 Permission。
权限清单由 native application 内嵌。应用数据库初始化后、服务开始前,Runtime 在控制数据库事务中创建并同步 `_dever_permission`:当前清单 upsert 为 active,清单外旧行标记 inactive。build/check 不连接数据库,同步失败时服务不得启动。
### 标准角色存储与请求授权
官方 auth runtime 在授权数据库维护 `_dever_auth_role`、`_dever_auth_role_permission`、`_dever_auth_user_role`,并以 `_dever_auth_version` 管理私有 schema。关系使用稳定 permission key,不使用环境相关自增权限 ID。Role 以 `(site, id)` 为身份,user-role 和 role-permission 同样携带 site 复合边界;不同站点可以复用同一角色 ID,且不能互相覆盖或授权。旧单列角色 ID schema 在一个事务中按 role.site 回填关系并替换三表,未知或不完整 schema 拒绝启动。授权只做 allow 并集,`all_permissions` 受 site 和 enabled 限制。
verify 输出收缩为 `id: Text, user_id: ModelId?, tenant_id: ModelId?`。Runtime 完成身份 scope 后,使用当前 user、site 和 permission key 对角色关系执行单次 EXISTS 查询;没有用户或授权记录返回 Forbidden。权限不进入 token、Session claims、Identity 或源码能力。租户应用在 tenant scope 内查询本租户角色库;平台入口查询控制数据库。
认证、组件可用性、接口授权和业务执行顺序固定为:路由/站点与凭据校验 -> verify -> 建立 tenant scope -> 检查可达租户组件 -> 检查 permission key -> 解码请求与调用 App。public 入口跳过 verify 与角色检查,并且其完整调用图必须静态证明不触达租户组件。
角色写入由 Runtime 的窄接口统一完成:列出 active 权限、创建/更新角色、事务替换角色权限、分配/撤销用户角色。写入时验证 site、active permission、角色状态和当前租户;这些能力只能从受保护的写 API 到达,业务组件不直接写私有表。租户 provision 时创建 site-scoped owner role并分配首个用户,避免授权死锁;保留 Owner 不能通过普通 save/grant/revoke/disable 修改。
### Job 与租户组件
User Job 只保存一个入口 permission key 和既有 provider/site/subject/session/tenant 身份引用。执行顺序固定为重新 verify、确认当前编译权限、检查租户组件、查询当前角色;失败转 blocked 且不进入业务 dispatch。v4 capability 列表迁移到新 schema 时,旧活跃 User Job 统一阻断为 `authorization_contract_changed`,物理删除旧 capability 列,历史终态记录保留。
编译器以 tenant Model 和 tenant Job 的静态归属识别租户组件,并为 API/CMD/Job 入口计算可达租户组件集合。混合组件整体视为租户组件,它拥有的全部 Job 都绑定租户队列,即使单个 Job 只访问 global 数据。控制库 `_dever_tenant_component(tenant_id, component, disabled_at)` 只存禁用例外。禁用优先于角色授权,不删除租户数据或改变 schema。
### 配置收缩
租户配置只有 `database/max_pools/idle_timeout_ms`。`database` 选择控制连接;物理租户数据库仍由现有 database 配置的 tenant target 派生。旧 `mode`、`control_database` 及 table/field 值明确失败,不保留双读或迁移别名。
## 2026-09-26 身份、站点与租户修订
此节是用户批准后的当前合同,替代旧 Auth Boundary 中的无身份运行时限制。实现仍复用既有 AST/HIR、wire、静态路由、隐藏请求上下文、ORM、Job 和 Port,不增加 Go 应用框架层。
### 配置与路由
`sites.<key> = { path, auth, hosts? }`。path 相对每个领域 api 目录,只匹配物理父目录(SourceLayout topics 排除文件名),空 path 用于单站根 API。保留完整 topics 生成 URL,站点不改写路径。每条 HTTP API 必须得到无歧义站点归属,Host 是进一步限制,不是认证结果。CMD 不从 HTTP 目录映射取得可信身份。
API 仅有 rest 和动词到 App 的绑定,增加单个 HTTP 声明的 public 修饰;禁止源码 site 声明、隐式全站共享接口及强制按站点复制 App/Model。注册后的路由元信息是认证 Provider 选择的唯一依据。
### 认证与权限
`auth.providers.<key>` 保存凭据验证配置和业务 App verify 引用。配置引用必须经过静态签名/Effect 校验并进入生产调用图、native emission、数据库初始化和 API 契约。密码/角色/成员业务复用账号领域,认证代码并不要求名为 auth 的目录。
运行时校验凭据后由受控桥接调用 verify;普通源 record 不能写入当前身份。verify 在租户业务自动事务之前完成。只读上下文包含身份来源、站点和可选用户/租户,不携带权限集合。App 可读 auth,Domain 保持纯规则。租户一经建立在当前调用链内不变,切换接口签发新凭据。
操作权限由 API/REST 静态入口自动生成并由 Runtime 查询标准角色关系;源码不登记或检查权限字符串。自动 REST 与 App 共享权限失败及标准 JSON Error 映射。身份对象不包含权限集合或可渲染原始 Token/Cookie。
### 数据边界
Model 的静态结构与物理存储分离:global 使用平台连接,其他持久化 Model 在 tenant 开启时要求可信租户。持久化模式只支持 database。数据库名只由内部稳定租户标识导出,不提供 table/field 分支。
普通 ORM 与自动 REST 使用共同存储/范围合同;不可证明符合隔离的原生 SQL 拒绝。连接由显式可回收拥有者管理,不永久泄漏每租户的 static handle。租户初始化有受控状态与 schema 版本,业务请求不能自行建库。跨平台库引用为逻辑引用,不能产生跨库 FK/Join;写入口只拥有单物理库事务。
### 后台执行与差异实现
Job 的租户身份由入口系统生成并与入队原子持久化,不信任 payload 内自报身份。User Job 只保存 Provider、站点、subject、session、租户声明和一个入口 permission key,不保存 token 或权限集合;执行时重新调用 verify,并查询最新角色关系复核该权限。受控 System 与 User 身份明确区分,缺少可信身份或旧 schema 不能降级。Worker 使用有界调度,租户任务不得回退平台队列。CMD 使用 System 身份,不能读取 HTTP Header/Cookie 或自报用户。
租户功能、额度及配置是业务数据。Port 候选实现静态编译、共享同一签名/失败/Effect 合同,选取依据可信租户配置。log 配置使用现有 logger 并关联调用元数据;runtime 缺省按 API/Job 能力选择模式,显式 CMD 不改变部署配置。
### 验证边界
先静态反例和 runtime in-process 验证,再生成代码/AOT 及双源码 CMS 定向用例。网络/数据库用例只使用 test 自有临时目录、随机 loopback 端口或明确配置的隔离数据库,运行前说明,不启动现有服务,不运行全量测试,不使用环境变量配置。
## Source And Generated CRUD
本节记录目标方向。声明式 API/CMD、编译器生成入口、基础 REST 和部分隐藏请求上下文能力已实现;Model 字段绑定、可信 `owner`、完整 Cookie 策略、标准 API Error 与 Upload 仍是待实施合同,不能把下述示例全部视为现有语法。
```dever
# module/user/profile/model.dever
type Profile {
owner user_id: user.account.model.id = user.auth.id()
name: Text(1, 64) index
bio: Text?
}
# module/user/profile/api.dever
rest
```
路径是 `/user/profile`,不重复目录名。仅当同领域主 Model 唯一时允许无参数 `rest`;多 Model 必须显式指定,歧义时报编译错误。生成 REST 覆盖 GET 列表与 `/{id}` 详情、POST、PUT 全量替换、DELETE,默认只传输本表公开字段和外键 ID,不自动展开或嵌套写关联。分页有界,外部筛选仅允许显式 `search` 或已索引的静态字段,不接受任意 QueryPlan。
Model 字段不重复列读/写名单:普通字段由编译器按字段名推导;`create`、`replace`、`search` 表达式仅描述不同的输入来源或纯转换。`owner field = context_read()` 对生成 REST 的创建赋值及所有读写施加同一行范围;GET/PUT/DELETE 的身份条件必须进入同一数据库查询或写语句,客户端不得设置或修改 owner。字段表达式仅在生成的 REST 入口执行,不改变普通 App `model.create/get/...` 的行为。只读上下文能力和纯函数可作为静态调用目标;数据库、网络、任务和写 Effect 不允许出现在字段绑定中。多个接口需要不同权限策略时使用明确的 App 操作。
```dever
# 自定义动作才需要 App;App 签名就是 API 输入输出合同。
post publish = app.publish
cmd rebuild = app.rebuild
```
`get`、`post`、`put`、`delete` 是 API 声明而非函数名前缀;`cmd` 独立于 HTTP。GET 调用链禁止数据库写 Effect;POST/PUT/DELETE 和 CMD/Job 的数据库写入在入口调用链自动建立事务,失败或取消回滚。`rest` 与同路径同方法的显式声明冲突时报错,不暗中覆盖。无需 App 透传 CRUD、`crud ... on model`、`expose`、`package` 或手写启动 `main.dever`。
应用业务源码由 `<component>/<domain>/<role>` 唯一确定身份;固定 role 为 app/domain/model/port/adapter/api/job。App 函数均为领域公开能力,Domain 保留私有纯业务规则;topic 文件名不进入 App 调用名。非 API 主题目录只允许一层。App/Domain/Port/Adapter/Job 的根文件与主题目录互斥;主 `model.dever` 可以和附属 `model/<topic>.dever` 共存,`api.dever` 可以和 `api/**` 共存。`user/` 仅为 component,`user/profile/` 为 domain。主 Model 的逻辑身份与表名保持 domain 名,附属 Model 的身份与表名取 topic;移动文件不是纯重构。
生成的应用入口收集 API、Job 和 CMD;没有命令参数时按 setting 的 runtime mode 启动服务,CMD 由稳定的 `<component>.<domain>.<name>` 名称和一个 JSON 输入显式选择。CMD 选择不能改写部署配置;没有可运行入口或 CMD 名称歧义时失败。基础 REST 和自定义 HTTP/CMD 共享类型化 wire 与固定 JSON envelope,不能维护第二套动态解码器。
函数约束使用已检查 HIR 和生产入口调用图,不按长度或函数数量猜测质量。未被生产入口或其他真实函数引用的私有实现、完全不增加类型/范围/失败/效果合同的私有转发、只有原样 Model CRUD 的公开 App 包装是硬错误。应用 build/run 对不可达 App 能力报错;库式 check 不推测外部调用方,保留提示。W003 相似实现仍是提示,不自动合并不同业务含义。所有分句保持同文件连续声明,合法单用途复杂规则不受影响。
## Custom Handler Shapes
GET/DELETE 从类型化 query/path 输入读取,POST/PUT 从静态 JSON 请求体读取;multipart 入口接收一个包含受限 scalar/Upload 字段的 record。API 自动继承绑定的 App 签名,不再机械重写参数和唯一 `response` 输出。请求值和业务失败继续使用共享静态 codec 与固定 JSON envelope。
## Context And Response Metadata
Runtime 为每个 request 创建仅在调用链内有效的 opaque Context handle,不作为源函数参数传递。受控 API 能力返回复制的 Text 或 Secret 值,并修改 Context-owned response metadata。Native route 在 handler 成功/标准失败后统一合并 headers/cookies 并构造 envelope;handler 不能直接获得底层 Response。
Cookie使用具体record/choice表示属性。Secret cookie sink接受Secret并直接编码header,不产生Text中间值。普通response header仅接受Text且经过token/CRLF和forbidden-name检查。
## Error Mapping
官方 `dever.api.Error` 是唯一可离开API handler并被协议映射的error choice。API通常通过 `result(app.call(...))` 捕获业务错误,再用小的API-local clause映射。Native route区分:
- success -> 200/0/ok/data;
- api.Error ->对应status/code/message/null;
- InputError -> 400;
- other inferred failure/fault -> log request metadata, return generic500。
错误message有长度上限且不得包含Secret/private value。业务层不依赖HTTP status。
## Upload Lifecycle
HTTP request reader为multipart路径提供bounded streaming/spool模式。Parser逐part验证headers和limits,将文件写入 `data/tmp` 下create-new随机名,业务只看到opaque Upload、原始filename展示值、declared MIME和size。Scalar fields经过shared decoder。
Upload资源owner跟踪临时文件。Storage Adapter通过批准runtime file/stream操作消费并显式commit ownership;未commit drop/close删除。API response完成前检查所有Upload已消费/关闭,防止隐式长期文件。
普通JSON路径保留现有bounded full body,因为全局body limit明确;multipart不复用会全量聚合的`Request.body`。
## Auth Boundary
登录、Session 和资源级授权仍由业务实现。业务 verify 向隐藏调用上下文提供只读身份,供 `owner` 绑定或 App 中显式 `dever.auth` 能力使用;接口角色关系由官方 auth runtime 读取。CMD 使用受控 System 身份;认证请求入队的 User Job 持久化最小身份来源和入口 permission key,并在执行时重跑 verify 与当前授权查询。`owner` 只约束自动 REST,手写 App 的 Model 操作必须明确检查其数据范围。
@@ -0,0 +1,3 @@
{"file":".trellis/spec/backend/compiler-contracts.md","reason":"API role, typed inputs, public outputs and failure contracts"}
{"file":".trellis/spec/backend/toolchain-and-library.md","reason":"HTTP/native/runtime resource and codec boundaries"}
{"file":".trellis/spec/backend/logging-guidelines.md","reason":"Request context and secret-free error logging"}
@@ -0,0 +1,173 @@
# Dever 生产 API 边界实施计划
## 2026-09-28 自动权限与租户收口
- [x] 用户确认最终方案:API 自动权限、分层权限目录、标准角色关系、database-only 租户、组件禁用例外和 Job 当前权限复核。
- [x] 修改前完整备份:`/data/project/dever-backups/pre-auto-rbac-20260928-105925/dever.tar.gz`;gzip 校验通过,SHA-256 `700c2756dfcb4c5bceaff9dc1a16b86cfe94599fdeea798740ebc5fe3a461eb0`,约 1.5 MiB。
- [x] HIR/API checker 生成 custom/REST 权限元数据,public 不生成权限,重复 action 静态拒绝。
- [x] Runtime 控制库同步 `_dever_permission`,并提供按 component/domain/site/action 分组的只读目录。
- [x] 官方 auth runtime 建立角色、角色权限和用户角色私有表,提供事务化授权写入与单 key EXISTS 校验;verify Identity 删除 permissions。
- [x] 删除 `dever.auth.require`、`AuthRequire` intrinsic、源码权限字符串和 Job capability 集合;所有非 public API/REST 在 handler 前自动授权。
- [x] Job schema 升级并保存单一 permission key;执行时重新 verify 和查询当前角色,旧活跃 User Job 安全阻断。
- [x] 租户配置改为 `tenant.database`,删除 mode/control_database,不保留兼容分支。
- [x] 自动识别租户组件,生成入口可达组件集合;实现 `_dever_tenant_component` 和 API/CMD/Job 统一禁用检查及 CLI enable/disable。
- [x] CMS Dever/Markdown 改为标准角色分配和自动权限;删除 membership 硬编码权限列表及所有手工 require。
- [x] 增加编译器、配置、Runtime SQLite、Job、组件闭包和双源码 CMS 定向正反测试。
- [x] 运行允许的最小 cargo check/定向测试、diff 检查和独立终审;真实 PostgreSQL 作为需要外部隔离实例的单独验收项记录。
- [x] 抽取只读根 `config/setting.json` 的共享 PostgreSQL fixture,并让 ORM 与授权验收复用同一隔离数据库/随机 schema/失败清理合同;SQLite 与 PostgreSQL 授权目标复用同一数据库无关断言。
- [x] 在真实 PostgreSQL 上运行授权目录、v1→v2 角色迁移、跨站同名角色、多角色、Owner 与失效权限的 ignored 定向验收;2026-09-30 再次通过,使用显式自有实例和临时根配置,结束后恢复配置文件不存在,不探测默认服务。
## 2026-09-26 已授权执行清单
- [x] 用户批准完整修订方案,并要求修改前备份;认证优先复用现有账号领域。
- [x] 备份完整工作目录(包含 untracked 源码与 .git,排除 target)到 `/data/project/dever-backups/pre-auth-tenancy-20260926-rm6kL6/dever.tar.gz`;gzip 检查和 tar 对源逐项比较均通过。SHA-256 `e4f0666d054ca241484e8333c16270f039a26c3c616b7ddd0f0bea50476ca9b7`,约 1.4 MiB。
- [x] 读取现有调用链和规范;确认站点 path 必须匹配 API 父目录,认证 hook 需进入生产根,Model/Job/Adapter 当前启动固定绑定。
- [x] 配置、目录站点归属、public HTTP 声明、静态认证 hook、只读身份和标准错误。
- [x] global/tenant Model、database 模式按租户选择物理库、有界池、显式初始化迁移和单库事务。
- [x] 多用户成员角色示例、能力检查、REST owner 行范围与字段来源;普通 ORM 保持显式业务范围。
- [x] Job/CMD 可信租户、日志配置、runtime 缺省、app 配置消费者迁移;CMD 不接受 JSON 自报租户/用户。
- [x] 租户组件启停由核心私有表和受控 CLI 完成;table/field 隔离及租户级动态 Adapter 已被后续 database-only 决策取消,不保留兼容模式。
- [x] 完成普通/Secret Cookie、标准错误和受限 Upload 合同。
- [x] Dever/Markdown CMS 同步、定向正反验收和现有规范同步。
- [x] 独立最终审查收口;限定复核外部 Origin、密码事务、public POST 错误、契约夹具和 Job 身份撤销,未发现 P0/P1 阻断。
实施与检查使用 Trellis 子代理;最多两个独立代理并行,共享文件必须先分配唯一拥有者。主会话负责合同、整合及最终证据。现有用户改动不回退、不提交 Git。测试仅限当前改动相关定向目标。
## Start Gate
- [x] secure-data-contracts、time-typed-codec、port-adapter完成。
- [x] 用户批准父任务规划,并批准 2026-09-25 的文件/函数/入口/API 改造方案。
- [x] 核对路径冲突、主 Model 推导、CMD 输入合同及现有 API/native/runtime、SourceLayout、ORM、HTTP 边界。
## Implementation
- [x] 收紧 role 布局:Model/API 根文件可与主题目录共存,其余 role 保持互斥;主 Model 身份沿用现有规则。
- [x] 实现 `get/post/put/delete/cmd/rest` 声明、App 绑定、路径生成与 `{id}` 路由;应用严格模式拒绝旧前缀 API 函数体。
- [x] 实现生成的 run/build 入口与 CMD JSON 选择;移除维护中 CMS 的手写 main。
- [x] 实现主 Model 基础 REST:公开字段、GET 列表/详情、POST/PUT/DELETE、静态 SQL 和有界分页。
- [x] 实现 Model 字段 `create/replace/search` 来源、可信 `owner` 身份绑定与所有自动 REST 读写同语句行范围;普通 App ORM 不受隐式修改。
- [x] 实现 GET 写 Effect 拒绝和写入口自动事务;覆盖 API/CMD/Job 生成路径,持续补足提交、回滚与取消的定向运行验证。
- [x] 基于生产调用图拒绝可证明的无用私有函数、无契约纯转发、简单 Model CRUD App 包装及应用构建不可达 App;保留警告和库检查。
- [x] 扩展 API input shape 检查和 shared decoder generation,CMD 使用同一严格 JSON 对象解析。
- [x] 增加 runtime 请求级隐藏作用域,不暴露可保存或伪造的 Context 源参数;HTTP/CMD/Job 调用链静态区分。
- [x] 增加受控 Header 读取/响应写入、Secret Cookie 原始字节的版本化 base64url 读取/写入和 typed CookieOptions;禁止敏感 Header 经 Text 读取、Header 注入及 Secret Cookie 缺少 Secure/HttpOnly。
- [x] `client_address()` 由 HTTP/1、HTTP/2 的 TCP peer 提供,不信任转发 Header;HTTP/1 loopback 定向验证通过。
- [x] 拒绝 CMD/Job 或脱离请求的 Task/parallel/blocking 调用 HTTP Context;HTTP/2 并发流的 request id、path、peer 和响应 Header 隔离定向测试通过。
- [x] 完成普通 Text Cookie 的安全读策略;Secret Cookie 保持独立非 Text 通道。
- [x] 增加官方API Error及native status/envelope映射。
- [x] 重构 request read boundary,认证/路由先于正文,multipart 使用 bounded streaming/spool。
- [x] 增加 affine Upload runtime owner、App→Port→Adapter 单次传递、storage consume/close/cleanup 和 checker 规则。
- [x] JSON request、request id 与现有 HTTP/1、HTTP/2 dispatch 路径共享;后续仍需定向运行验证 HTTP/2/drain。
- [x] 更新 README、LANGUAGE、Markdown 语法与 CMS 两套源码,迁移至编译器生成入口;其余协议文档随 Context/Error/Upload 实施更新。
- [x] Job 私有存储最终升级到 v5:只持久化可复核身份引用和单一入口 permission key,拒绝无身份入队;CMD/cron/Test 显式 System,User 每次执行重新 verify,v4 活跃 User 行阻断并删除旧 capability 列。
- [x] 响应 Header/Cookie 改为 pending/committed 两阶段,序列化和数据库提交成功后才发布;登录类请求使用严格同源校验,Cookie 签发/清理统一读取配置。
- [x] PostgreSQL database 租户由显式 `tenant migrate` 通过控制连接幂等创建后迁移;普通请求/worker 保持无创建、无回退。
## 2026-09-25 定向结果
- `cargo check --offline -p dever-core -p dever-runtime -p dever-cli` 通过。
- API 声明测试 10/10、语法/格式 22/22、基础 REST 4/4、目录规则 12/12、旧 HTTP 路由 7/7 通过。
- CMS Dever/Markdown `check`、`fmt --check` 通过;CMS 同源与生成入口测试 1/1 通过。
- 无 main 的 API/CMD AOT 编译和实际 CMD JSON 调用通过,输出固定 envelope;Job AOT 编译通过。生成入口定向测试 11/11 通过。独立审查指出的必填 Json、事务并发、日志泄漏和 REST Text 边界已修复,并增加定向反例。请求上下文和 TCP peer 测试 5/5、HTTP/2 多路复用定向测试 1/1 通过;CMS 同源测试 1/1 通过。
- 仍需确定 `owner` 的可信业务 actor 来源,以及声明式 API 如何把 App 业务失败映射到官方 API Error;两项不能用客户端 Header/Cookie 自报身份或让 App 隐式依赖 HTTP 状态来代替。Model `create/replace/search` 绑定、普通 Text Cookie 策略及 multipart Upload 还未实现。
- 未运行全量测试、服务级 CMS/HTTP 集成测试、真实数据库或性能/内存压测;rustfmt/clippy 组件未安装。
## 2026-09-26 身份与配置定向结果
- typed `auth/sites/log` 配置、API 物理目录站点归属、单声明 `public`、静态 verify hook、只读 `site/auth` 上下文、HS256 凭据、Cookie Origin 约束和标准 API Error 映射已实现。
- `app` 顶层配置已移除,性能工具迁移到顶层 `performance`;runtime 缺省按 API/Job 能力推导。UUID 官方 parse/to_text 能力已补齐,供业务会话与租户标识使用。
- `/root/.cargo/bin/cargo check --offline -p dever-core -p dever-cli` 通过;`/root/.cargo/bin/cargo check --offline -p dever-runtime --features api` 通过;`api_routes` 7/7 通过(含 native/AOT);此前 `auth_runtime` 2/2、`application_config` 5/5、API 声明 14/14、性能工具 Python 测试 40/40 通过。
- database 模式多租户物理存储、Job/CMD 可信租户、普通 Text Cookie、Upload、REST owner 与字段绑定已经完成;CMS 双源码正在最终复验。
- 此处当时记录的 table/field 隔离与租户级动态 Adapter 后续已由 database-only 决策取消;当前不保留这些模式或兼容分支。
## 2026-09-26 多租户、REST 字段与 Upload 定向结果
- database-only 租户已贯通 global/tenant Model、无回退物理库选择、ready/fingerprint、显式 `tenant migrate`、有界池回收、单库事务和 tenant Job 恢复;当前配置入口是 `tenant.database`。SQLite 无回退/幂等迁移 CMD 1/1、tenant Job 物理库隔离 1/1 通过。
- REST `owner/create/replace/search` 已进入 checked HIR、生产可达图与 native;owner+search 复合索引、双静态 SQL、pure Domain/可信上下文正例和数据库/时间/响应/并发反例通过。SQLite AOT 1/1 通过(74.46 秒)。
- multipart/Upload 边界 5/5 通过,包含流式分块、limits/重复字段/路径穿越、取消清理、affine 静态反例和 loopback POST→App→Port→Adapter→storage 实际 AOT;临时目录在成功后为空。
- 写入口事务允许等待完成且目标无数据库/并发的 `blocking`,仍拒绝 `run` 等逃逸并发;自动事务、拒绝反例和显式 transaction 定向 3/3 通过。
- API AOT 路由复验 1/1 通过;认证运行时此前 2/2、CMD tenant migration 1/1 通过。CMS Plain/Markdown 使用部署 settings 的同源/application reachability 复验 1/1 通过。
- 未运行全量测试、真实 PostgreSQL、HTTP/2 上传 reset、外部对象存储原子发布、服务压测或性能/内存压测;rustfmt/clippy 组件未安装。
## 2026-09-26 可信身份与事务收口结果
- CMS Plain/Markdown 的发布操作统一调用 `dever.auth.owns_user(stored.author_id)`;租户 verify 同时要求 `platform.tenant.active`,避免仅凭有效会话绕过资源所有者或停用租户。
- public API 不再从浏览器 Cookie 建立身份,显式无效 Authorization 仍拒绝;Origin 与 Host 按站点配置的外部 HTTP/HTTPS scheme、主机和有效端口精确匹配,不根据内部监听协议或转发 Header猜测。Cookie 名称、TTL、签发和清理均来自 `config/setting.json`,没有环境变量入口。
- `_dever_jobs` 当前 v5 区分队列物理租户与执行租户,保存 provider/site/subject/session/tenant 引用及单一入口 permission key;不保存 token、Cookie、角色或权限集合。User Job 每次重试均重新 verify 并查询当前角色,legacy v4 活跃 User 行转为 `blocked/authorization_contract_changed`,匿名/无身份路径不能退化为 System。
- SQLite 写事务继续 `BEGIN IMMEDIATE`。含 password verify/hash 的 HTTP 调用链不再生成外层事务,编译器要求全部写入进入显式短 `transaction` 并禁止事务内密码计算;CMS 登录在短事务内重新检查账户、租户和成员关系后创建 session。响应元数据只在响应序列化和数据库提交后转为 committed。
- PostgreSQL 租户迁移会通过配置的控制连接创建派生数据库,SQLSTATE `42P04` 作为并发/重复创建成功处理;尚未连接真实 PostgreSQL 验证权限和服务端行为。
- 定向结果:核心/runtime 的 API、SQLite、PostgreSQL feature `cargo check` 通过;durable Job 静态、生成入口、SQLite 状态机、v5 迁移/持久化、public 边界和 tenant 隔离各 1/1 通过;认证 runtime 3/3、配置 6/6、安全契约 12/12、生成 User Job AOT 1/1 通过。
- 新增撤销回归通过 1/1:测试拥有的临时 SQLite 应用先以有效会话入队 User Job,再撤销 session 并启动 worker;任务转为 `blocked/identity_rejected`,业务副作用表保持为空。该验证使用临时 loopback 与子进程,无外部服务。
- 密码窗口并发回归包含在安全契约中:账号读取与 session 短事务之间模拟密码计算,同时另一连接可完成无关写入;短事务重新读取状态后正常创建 session,不持有跨密码计算的 SQLite 写锁或旧读快照。
- CMS Plain/Markdown `check` 与 `fmt --check` 均通过;两套源码/Model/API/config 同源检查 1/1 通过。两套 `check` 各保留 3 个预期 W001,不影响编译。
- 独立终审只读复核上述五项实现与执行路径,未发现 P0/P1 阻断;真实 PostgreSQL、性能、table/field 和动态 Adapter 不属于本轮收口范围。
- 未运行全量测试、持久服务、真实 PostgreSQL、HTTP 集成、性能/内存压测;rustfmt/clippy 组件未安装。table/field 租户隔离和租户级动态 Adapter 仍按已确认范围延期。
## 2026-09-28 自动权限与租户收口结果
- 权限由 checked HIR 自动生成,custom 使用 action,REST 使用 `read/create/replace/delete`;method 仅作元数据。跨 method/path 重复 key、public 触达租户组件、public/GET 调用角色管理能力均在 native 前拒绝。
- `_dever_permission` 在服务启动前同步;授权库使用版本化 `_dever_auth_role`、`_dever_auth_role_permission`、`_dever_auth_user_role`,三表以 `(site, role_id)` 隔离同名角色,旧单列 ID schema 事务迁移并保留授权数据。精确权限使用索引化 EXISTS,多角色取并集,`all_permissions` 只覆盖同站点。保留 `_dever_owner:<site>` 只能由 `tenant owner` provision,普通 save/grant/revoke/disable 全部拒绝。
- Identity 已固定为 `id/user_id/tenant_id`;源码 `auth.require`、AuthRequire intrinsic、权限列表和 Job capability 集合已删除。受保护 API 顺序固定为 verify、tenant scope、组件检查、精确权限、输入解码和 App。
- Job 已升级到 v5,只保存一个入口 permission key;每次执行按 verify、编译目录、租户组件、当前角色的顺序复核。v4 活跃 User Job 迁移为 `blocked/authorization_contract_changed` 并删除旧 capability 列,System 任务保持可执行。
- 租户只支持 `tenant.database/max_pools/idle_timeout_ms`。租户组件从 tenant Model/Job 自动推导,混合组件拥有的全部 Job 统一使用租户队列,并通过 `deverc tenant component enable|disable` 控制;public 入口不能静态触达租户组件。
- CMS Plain/Markdown 已同步为核心角色管理薄适配,admin/front 各有同站点管理入口,启动说明要求迁移后分别 provision Owner;membership 只表达业务成员关系。两套 `test` 此前各 1/1 通过;本次最终源码改动后,两套 `check`、`fmt --check` 及当前编译器双源码同源/完整应用可达检查通过,check 仅保留 3 个既有 W001。受磁盘空间限制未重复链接两套完整 CMS 测试程序。
- 定向验证通过:core/runtime/CLI cargo check;`application_config` 6/6、`api_declarations` 16/16、`contract_api` 9/9、`auth_runtime` 3/3、`authorization_runtime` 1/1(含旧角色 schema 迁移与跨站同名角色);REST 权限、Identity、Job v4->v5 删列、撤销后 Job 阻断、混合组件 Job 租户 AOT、租户组件 disable/enable、CMS 双源码同源及受保护 auth/Job 顺序 AOT 各 1/1。
- 两轮独立终审指出的站点角色主键、混合组件 Job、CMS 首次 Owner、v5 旧列、Job 复验顺序和旧授权 schema 升级问题均已修复并复验;最终未发现新的 P0/P1。
- 未运行全量 workspace 测试、真实 PostgreSQL、持久服务或性能/内存压测;rustfmt/clippy 组件未安装。本轮实现没有环境变量配置入口。
## 2026-09-28 PostgreSQL 授权验收准备结果
- 新增共享 PostgreSQL 测试 fixture,只接受仓库根 `config/setting.json` 的 `database.postgres_test`;URL 的数据库名必须包含且只包含一个 `{case}`。fixture 为每个目标派生专用数据库名并创建随机 schema,测试成功或 panic 后都从独立 runtime 尽力清理。
- `postgres_orm` 已迁移到共享 fixture;新增 ignored `authorization_postgres` 目标。SQLite 与 PostgreSQL 共用唯一授权合同,覆盖权限目录、旧 v1 schema 数据保留迁移、跨站同 role id、多角色并集、角色禁用/撤销、保留 Owner 限制和失效权限拒绝。
- `/root/.cargo/bin/cargo check --offline -p dever-tests --features api,postgres --test postgres_orm --test authorization_postgres` 通过;SQLite 授权 exact 1/1 通过。无 feature 的 `syntax_and_format` 与仅 SQLite 无 API 的 `sqlite_orm` 编译检查由实施子任务验证通过。
- 独立检查发现 PostgreSQL URL 的 `dbname` 查询参数可覆盖路径数据库,已拒绝明文和百分号编码的覆盖形式;纯 URL 隔离回归 1/1 通过。复验期间磁盘一度归零,两个重复定向链接已中止并清理本轮生成的可重建测试二进制/增量对象,未删除源码、配置或用户数据。
- 真实 PostgreSQL 未运行:仓库根当前没有 `config/setting.json`。测试不会读取环境变量或命令行连接覆盖,也不会自动连接、创建或清理未明确配置的数据库。
- `cargo fmt --all --check` 未运行成功,因为 rustfmt 组件未安装;新增 Rust 已手工按现有样式整理。
## 2026-09-29 真实 PostgreSQL 定向验收
- 使用仓库根 `config/setting.json` 的 `database.postgres_test` 配置(测试凭据仅存在于被 `.gitignore` 忽略的临时文件,验收后已删除),在本机隔离 PostgreSQL 数据库上运行 `authorization_postgres` ignored 定向目标,1/1 通过。
- 本次实际覆盖权限目录同步、v1 角色 schema 迁移、跨站点同名角色、多角色权限并集、角色禁用、用户角色撤销、Owner 保留限制和失效权限拒绝;测试使用随机 schema,临时数据库在验收后清理。
- `postgres_orm` 未通过,失败发生在数据库连接前的共享 fixture 编译阶段:旧 fixture 仍从 `main.dever` 调用 `user.create`,当前 Model 规则要求 Model 操作只在 owning-domain App 中调用。SQLite 共享 fixture 同样复现该编译失败,因此这是独立的 ORM fixture/语言契约迁移项,不是 PostgreSQL 实例或配置问题。
- 没有读取环境变量或命令行连接覆盖;仓库工作区未保留真实 PostgreSQL 凭据或 `config/setting.json`。
## 2026-09-30 当前 PostgreSQL 组合补验
- 共享 ORM fixture 已按 owning-domain App/Model 合同迁移,真实 PostgreSQL ORM/授权 Store ignored 各 1/1 通过,旧 09-29 ORM 失败已关闭。
- `postgres_api` exact ignored 1/1 通过 stock Dever CMS 的真实 HTTP、两个物理租户数据库、同 slug 独立发布、跨站 Cookie/跨租户登录拒绝、普通非 Owner 的多角色/跨站同名角色及同一会话撤销立即失效。测试注册仅在副本追加 `test/dever-tests/fixtures/postgres_api/` 片段,不修改生产 CMS 或 Owner 保留角色规则。
- 新报告 `target/performance/postgres-http-09-30-v1/report-1968019-1790739069361983512.json`;`test-rbac-final.log` 和 `server-rbac.log` 保留真实结果与服务日志。失败轮的站点目录读取和 DELETE body 工具错误已按现行合同修正,未放宽 checker/runtime。
- 临时控制库/租户库全部清理,自有 PG 已停,根 `config/setting.json` 恢复原先不存在;PG 下载/数据目录移入回收站可恢复。Python 工具 57/57、Rust postgres_api 非 ignored 3/3;不宣称 Markdown PostgreSQL/HTTP2 所有组合或全 workspace 复验已运行。
## Focused Verification
```bash
cargo check --offline -p dever-core -p dever-cli
cargo check --offline -p dever-core -p dever-runtime --features dever-runtime/api,dever-runtime/sqlite,dever-runtime/postgres
cargo test --offline -p dever-tests --features api,crypto,sqlite --test secure_contracts --test auth_runtime --test application_config
cargo test --offline -p dever-tests --features api,crypto,sqlite --test durable_jobs revoked_user_job_is_blocked_before_business_dispatch -- --exact
cargo test --offline -p dever-tests --features api,crypto,sqlite --test contract_execution cms_formats_share_source_model_api_and_configuration_contracts -- --exact
cargo test --offline -p dever-tests --features api,postgres --test authorization_postgres postgres_authorization_preserves_site_scoped_roles_and_catalog -- --ignored --exact
cargo run --offline --quiet -p dever-cli -- check examples/cms/dever
cargo run --offline --quiet -p dever-cli -- check examples/cms/md
cargo run --offline --quiet -p dever-cli -- fmt examples/cms/dever --check
cargo run --offline --quiet -p dever-cli -- fmt examples/cms/md --check
cargo test --offline -p dever-tests --features api --test api_routes
cargo test --offline -p dever-tests --test http_engine
cargo test --offline -p dever-tests --test http2_server
cargo test --offline -p dever-tests --test logging
cargo test --offline -p dever-tests --test pooled_network
cargo test --offline -p dever-tests --test source_architecture
cargo test --offline -p dever-tests --test markdown_source
git diff --check
```
上传测试只使用test-owned临时目录和bounded loopback peer,提前说明后运行;不启动持久服务、外部网络、全量测试或性能基准。
## Review Risks
- Context/Upload不能通过record、Task、Channel、App参数或输出逃逸request scope。
- multipart错误/取消所有路径必须删除已创建part,且不能信任filename作为路径。
- Secret cookie不能生成可被Render/log捕获的中间Text。
- API Error必须与未知App failure区分,不能把内部错误message返回客户端。
- HTTP/2并发stream的Context/temporary ownership不能串请求。
- 目录或文件重排不得隐式改变 Model identity、表名、App 调用名和 API 路由;旧 API/Main 方案不能与新方案共存。
@@ -0,0 +1,86 @@
# Dever 生产 API 边界
## 2026-09-28 自动权限与 database-only 租户修订
本节替代下文所有关于手写 `auth.require`、verify 返回权限列表、框架不提供 RBAC、`tenant.mode`、`tenant.control_database`、table/field 租户模式和 Job capability 列表的旧合同。
- `public` 是唯一匿名入口。所有非 public HTTP API 默认同时要求可信身份和当前接口权限;源码不得手写权限字符串或调用 `dever.auth.require`。
- 编译器根据 `<component>/<domain>/api/<site>/**` 和 API 声明自动生成权限目录。权限 key 为 `component.domain.site.action`;HTTP method 只保存为元数据,不进入 key。`rest` 自动生成 `read/create/replace/delete`,自定义 API 使用声明 action。public API 不生成权限项。
- 权限目录由构建产物携带,并在应用初始化时幂等同步到控制数据库 `_dever_permission`;移除的 API 标记 inactive,不直接删除授权历史。源码、组件和业务代码不注册权限。
- 官方 auth runtime 提供租户内 `_dever_auth_role`、`_dever_auth_role_permission`、`_dever_auth_user_role`。用户只通过角色取得权限,多角色取并集;不支持直接用户授权、deny、角色继承或权限优先级。`all_permissions` 仅覆盖同一站点的 active 权限。
- verify 只建立 `id/user_id/tenant_id` 可信身份,不返回权限列表。Runtime 针对当前 permission key 做索引化 EXISTS 查询,不把大量权限写入 JWT、Session 或请求上下文。`dever.auth` 只公开身份读取及签发/清理凭据能力。
- API 权限只决定能否调用动作。资源归属、状态流转和其它数据权限仍由 App 读取可信身份后调用纯 Domain 规则;Domain 不读取隐式身份。未认证返回 401,接口权限或业务授权失败返回 403。
- 多租户只保留 database 隔离。配置改为 `tenant.database`,删除 `tenant.mode` 和 `tenant.control_database`,不保留兼容分支。
- 编译器自动识别组件:拥有 tenant Model 或 tenant Job 的组件属于租户组件,其余为平台组件;混合组件按租户组件处理。租户组件默认启用,控制库 `_dever_tenant_component` 只保存禁用例外。入口携带静态可达组件集合,Runtime 在 API/CMD/Job 入口统一检查。
- User Job 保存可重新验证的身份引用和一个发起操作 permission key,不保存权限集合;每次执行前重新 verify,并按当前角色关系复核该 permission。旧 capability schema 的活跃 User Job 在迁移时阻断,不能降级为 System。
- `_dever_permission` 和 `_dever_tenant_component` 是 Runtime 私有控制表;角色表由官方 auth runtime 统一拥有。项目仍拥有 User、Session、Tenant 业务 Model。
## 2026-09-26 已批准修订
用户已批准在备份后实施完整站点、可信身份、多用户权限和多租户方案。本节替代下文涉及身份、租户、入口配置的旧限制;尚未完成的字段绑定、Cookie、标准错误和上传仍属任务,不因新增范围而消失。
- `sites.<key>.path` 是每个组件/领域 `api/` 下的相对源码目录,递归包含子目录;不是 URL 前缀。`admin` 只匹配 `api/admin/**`,不能匹配同名 `api/admin.dever`。URL 保持现有组件/领域/API topic 生成规则,不增加源码 `site` 声明。站点匹配遗漏、歧义和路由冲突在服务开始前拒绝。
- `public` 只修饰 HTTP API 声明,普通接口默认认证。站点选择配置中的认证 Provider,Host 可进一步约束入口;客户端提供的站点/用户/租户值不能自行成为可信身份。
- Provider 验证签名和站点凭据后,调用静态检查的业务 App verify,检查账号、会话、成员关系并建立只读 `site.key`、`auth.id/user_id/tenant_id`。优先复用已有账号领域,不要求新建 `auth` 领域或 `admin` 组件。
- 身份、接口权限和数据范围分别检查。接口权限由 Runtime 自动校验,数据范围由业务 App/Domain 处理,所有入口不能绕过对应边界。
- 开启多租户后,普通持久化 Model 属于当前租户,`global` Model 使用平台库;只支持 database 分库。不影响普通 DTO,不因缺租户而回退平台库。CRUD、REST、统计、关联和批量路径共用隔离合同。
- 租户连接池有界且可回收;初始化/迁移属于受控租户生命周期。跨库引用保留类型但不能隐式建立物理外键/Join;自动事务只覆盖一个物理数据库。隔离模式切换必须经过数据迁移。
- 租户功能开通和规则配置属于业务数据;实现差异复用已编译 Port/Adapter。禁止租户 ID 分支、复制整套项目或执行数据库内代码。
- Job 原子入队并保存受控租户/执行身份,执行时恢复并复核资格;CMD 不能通过自报用户 ID 伪造身份。日志关联站点/身份/租户而不泄漏凭据。
- 所有部署配置仅来自 `config/setting.json`,无环境变量。保留并应用 log,runtime 可选并按能力选择服务,移除无用途 app 配置及迁移其工具消费者。
- 同步 Dever/Markdown CMS,验证站点目录、跨站凭据、两个租户相同记录 ID、不同角色、匿名边界、Job 上下文、事务回滚和平台共享数据。
本轮已完成并逐项比对的修改前备份:`/data/project/dever-backups/pre-auth-tenancy-20260926-rm6kL6/dever.tar.gz`。SHA-256:`e4f0666d054ca241484e8333c16270f039a26c3c616b7ddd0f0bea50476ca9b7`。
## Goal
在保持固定 JSON envelope 的前提下,以 Model + `rest` 覆盖受约束的普通 CRUD,以显式 API 动词绑定 App 业务动作;同时让 API 安全承载结构化请求、会话 Cookie、显式业务错误、隐藏请求上下文和受限文件上传。本任务正在实施,以下是完整目标合同;已实现的子集以 implement.md 为准。
## Dependencies
- `secure-data-contracts`:Secret Cookie/token 和私密输出拒绝。
- `time-typed-codec`:结构化请求/响应和完整标量 codec。
- `port-adapter`:上传后的对象存储由业务 App 调用 storage Port。
## Requirements
- API 使用 `get`、`post`、`put`、`delete`、`cmd` 和 `rest` 声明;移除 `get_`/`post_`/`delete_` 前缀语法,不加入 `patch`。同领域唯一主 Model 可由无参数 `rest` 推导,自动路径为 `/<component>/<domain>`;自定义动作以 `post publish = app.publish` 等形式绑定 App 签名。
- 纯 CRUD 无需 App;编译器生成的 `rest` 才可直接降低到同领域 Model 操作。手写 API 不直接调用 Model;需要业务处理时调用同领域 App。App 中所有函数都是领域公开能力,私有辅助逻辑归 Domain,不增加 `expose` 或 `crud ... on model` 声明。
- Model 普通字段按名称推导 CRUD 输入输出;只有例外才声明 `create`、`replace`、`search` 或 `owner` 字段绑定。`owner <field> = <context-read expression>` 为自动 REST 创建赋值及 GET/PUT/DELETE 行范围,客户端不能覆盖。字段绑定表达式只能使用静态类型可检查的纯计算或只读上下文能力,禁止数据库、网络和写 Effect;它们不隐式作用于手写 App 的 Model 调用。
- `get` 调用链禁止数据库写 Effect;`post`、`put`、`delete` 写调用链默认同一事务。`cmd`、Job 的数据库写入也按 Effect 建立事务,不依赖 HTTP 动词。无需在 App 源码重复声明 `transaction`。
- 源码身份固定为 `<component>/<domain>/<role>.dever[.md]`,role 只接受 `app/domain/model/port/adapter/api/job`。一个领域优先每个角色一个文件;按主题拆分时非 API 主题只允许一层。App、Domain、Port、Adapter、Job 的根文件与主题目录互斥;主 `model.dever` 可与附属 `model/<topic>.dever` 共存,基础 `api.dever` 可与路径分组 `api/**` 共存。主题必须表达业务含义,不按函数机械拆文件;搬动 Model 文件可能改变持久化身份,不能作为无迁移的整理。
- `deverc run/build` 的目标入口由编译器生成,不要求应用编写 `main.dever`。无命令参数时按 `config/setting.json` 启动 API/worker;指定 CMD 时命令行 JSON 由该 CMD 的静态签名解码。没有可运行入口时报错;部署选择继续只读 `config/setting.json`,不用环境变量覆盖。
- App 函数只表达有生产用途的公开业务能力;私有纯业务规则属于同领域 Domain。静态拒绝可证明无生产调用的私有函数、没有增加契约的纯转发以及只透传 Model CRUD 的 App 包装;应用构建还应拒绝不可达的 App 能力,测试调用不算生产用途。结构相似但业务含义可能不同的实现先保留警告,不用函数数量或行数配额。
- 保留 JSON envelope:成功 HTTP 200、`code=0`、`message="ok"`;错误使用 HTTP status 对应数值 code,`data=null`。
- GET/DELETE 接受 wire-safe scalar 和 nullable query 参数;POST/PUT JSON 使用静态类型请求体,不接受动态字段名或任意查询 Map。
- POST multipart 接受一个包含受限 scalar/Upload 字段的 static record;JSON 和 multipart 模式由签名静态决定且互斥。
- Runtime 隐式传递请求上下文,不在业务函数签名中声明 `dever.api.Context` 参数,也不允许存储或输出。API 的受控能力提供 request id、method/path、受信任边界内的 client address、受限 Header 读取、Text/Secret Cookie 读取,以及受控 response Header/Secure Cookie 写入;身份解析仍由业务实现。
- Header name/value严格校验;禁止应用设置Content-Length、Transfer-Encoding、Connection和原始Set-Cookie。Cookie属性使用typed API并限制Domain/Path/SameSite/Secure/HttpOnly/Max-Age。
- 自定义 API handler 必须把业务失败显式映射为标准 `dever.api.Error`:Invalid/Unauthorized/Forbidden/NotFound/Conflict/TooManyRequests。生成的 REST 使用固定输入、归属和数据库错误映射;未捕获失败返回通用 500 并只写脱敏结构化日志。
- API response继续直接返回静态业务值,不暴露 `dever.http.Response`,不允许自定义绕过envelope的JSON。
- Upload采用流式读取到runtime-owned临时文件或等价有界spool,不将大文件整体复制到内存;限制总字节、单文件、part数、字段数、header和filename长度。
- Upload filename不作为路径,MIME只作声明且需业务/Adapter复核;拒绝路径穿越、重复字段和不完整multipart。
- Upload handle为affine资源:必须由批准storage操作消费或显式close;正常、失败、timeout、取消和进程退出均清理未接管临时文件。
- 登录、Session 和资源级授权由项目 App/Domain 实现;接口 RBAC 由官方 auth runtime 自动执行,不增加业务 middleware。
## Acceptance Criteria
- [x] `rest` 自动生成 GET 列表/详情、POST、PUT、DELETE;显式动词/CMD 和固定 envelope 在 Dever 与 Markdown 源码中一致,DateTime 等标量按 shared codec 格式。
- [x] 路径、角色、Model 自动识别、字段绑定 Effect、`owner` 的所有 REST 读写范围和无歧义规则均有正反例;手写 App Model 调用不受 REST 字段绑定的隐藏影响。
- [x] GET 写入被静态拒绝,POST/PUT/DELETE 及 CMD/Job 写调用链的提交、错误回滚和取消行为有定向验证。
- [x] POST/PUT record 和 GET/DELETE query/path 严格验证 duplicate/unknown/missing/type/size;非法输入返回 400 固定 envelope。
- [x] 请求上下文由 runtime 隐式传递,客户端无法伪造;源码不得声明、存储或返回原始 Context。
- [x] Cookie parse/write覆盖Secure/HttpOnly/SameSite/Path/Max-Age,header injection和受禁header拒绝。
- [x] Secret session token不能日志/JSON/string泄漏,但可通过typed secret cookie sink发送。
- [x] 标准API Error映射到400/401/403/404/409/429;未映射App failure返回脱敏500。
- [x] multipart正常上传不全量驻留内存;越界、畸形、取消和handler失败后无临时文件残留。
- [x] 手写 API 只绑定同领域 App;自动 REST 仅通过编译器生成的 Model 路径。认证示例由业务解析会话并提供只读身份能力。
- [x] HTTP/1和HTTP/2已有deadline、request id、connection drain回归不退化。
- [x] Model/API 根文件和主题目录共存、其他 role 冲突、无 main 的 run/build/CMD JSON、缺少入口以及无意义私有/App 包装都有正反测试;合法单用途业务规则和库检查不被误拒绝。
## Out Of Scope
- GraphQL、gRPC、WebDAV和任意动态路由。
- 外部 IAM、OAuth Provider、直接用户权限、deny、角色继承和复杂策略语言。
- front CORS策略和浏览器页面。
- 断点续传、分片合并、病毒扫描和对象存储协议;由后续业务Port/Adapter扩展。
@@ -0,0 +1,26 @@
{
"id": "production-api",
"name": "production-api",
"title": "Dever 生产 API 边界",
"description": "补齐结构化请求、请求上下文、Cookie、响应 Header 与受限上传能力",
"status": "in_progress",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P1",
"creator": "Antigravity",
"assignee": "Antigravity",
"createdAt": "2026-09-20",
"completedAt": null,
"branch": "main",
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": "09-20-production-application-language",
"relatedFiles": [],
"notes": "",
"meta": {}
}