58 lines
5.8 KiB
Markdown
58 lines
5.8 KiB
Markdown
# 按需复用的完整项目
|
||
|
||
这些项目随 skill 提供,都包含 `module/`、`test/` 和 `config/setting.json`。复制需要的项目到新目录,再替换业务内容,不要把整个 examples 放进 module。最小项目直接用 `dever new` 创建。
|
||
|
||
| 场景 | 项目资产 | 首次阅读 |
|
||
| --- | --- | --- |
|
||
| HTTP、受保护 REST、真实身份核验 | [http-rest](../assets/examples/http-rest/) | `config/setting.json`、`module/access/session/app.dever`、`module/content/article/` |
|
||
| 入队、持久 Job、隔离数据库与虚拟时钟 | [jobs](../assets/examples/jobs/) | `module/report/archive/`、`test/report/archive/queued.dever` |
|
||
| 外部能力、声明失败、每例独立 fake | [external-lib](../assets/examples/external-lib/) | [三语言接入说明](external-lib.md) |
|
||
| 筛选、映射、累计与逐项断言 | [collections](../assets/examples/collections/) | [集合与处理函数](language.md#集合与处理函数) |
|
||
| 普通二进制 Port、CMD 与 fake | [command](../assets/examples/command/) | [二进制调用说明](libraries.md#外部-lib-与普通二进制) |
|
||
|
||
复制后先运行 `dever fmt <root> --check` 和 `dever check <root>`,再按下面的命令运行相关测试。这些检查不准备 Worker、不连接部署数据库、不启动 HTTP/Job 服务。
|
||
|
||
文件要放在示例对应的角色中。遇到无法从业务入口调用到的代码报错(C016),接通真实调用或删除废弃代码,不添加假调用。
|
||
|
||
## HTTP 与 REST
|
||
|
||
`http-rest` 展示的是受保护内容资源和已有登录系统的 verify 接口,不包含账号注册、密码登录或签发凭据。匿名健康检查 `GET /system/health/admin/status/ready` 返回 `{"code":0,"message":"ok","data":true}`;它没有持久数据或租户依赖。
|
||
|
||
`module/content/article/api/admin/entries.dever` 的 `rest model` 生成 `/content/article/admin/entries` 下的资源接口;用 `dever api <root> --output <new-file>` 查看精确方法、路径和输入合同。REST 的权限键为 `content.article.admin.read/create/replace/delete`。例如创建正文包含 `title`、`body`,title 经同领域 pure Domain trim 后再应用 Model 长度约束。Model 自动提供 id/created_at,不手写 CRUD App。
|
||
|
||
配置中的 `admin.path = "admin"` 对应两个领域的 `api/admin/**`。
|
||
|
||
身份核验先读取 global Session,检查 UUID、subject、site、tenant key、过期与吊销状态,再检查用户、租户和成员关系。成功返回只有 id/user_id/tenant_id 的 Identity;失败返回 Unauthorized。不能原样回显 claims 冒充核验,也不从 verify 返回权限列表。
|
||
|
||
接入已有登录系统时,由它的认证流程创建 User、Tenant、Membership、Session,再按 provider 配置签发 subject/session/tenant。示例不会自动建默认用户、发演示 token 或绕过权限。
|
||
|
||
部署前替换 JWT 密钥,迁移租户数据库,再用 `dever tenant owner <root> <positive-tenant-id> admin <positive-user-id>` 建立初始 Owner。参数是数据库 ID,不是 token 的 tenant key。后续角色权限用核心 `dever.auth` 管理,不复制一套 RBAC 表。建 Owner 和迁移属于运维操作,不是普通测试。
|
||
|
||
这里开启 database 租户隔离:global 身份表在控制库,Article 在租户库,匿名 health 不触达 Article。不要添加 `tenant.mode/field/table` 或在缺少租户时回退控制库。站点没有使用 Cookie;如果改为 Cookie 登录,补充精确 `sites.admin.origin` 和 issue_cookie/clear_cookie 的同源合同。
|
||
|
||
定向测试:`dever test <root> --filter content.article.title --timeout-ms 5000`。该例验证标题规则,不证明 REST HTTP、JWT、权限或实际租户迁移已验收。
|
||
|
||
## 持久 Job
|
||
|
||
`jobs` 的 `report.archive.submit` CMD 接受一个 `input` record:
|
||
|
||
```sh
|
||
dever run <root> -- report.archive.submit '{"input":{"key":"report-2026-10","title":"Monthly report"}}'
|
||
```
|
||
|
||
这是会写示例数据库的显式运行命令,不是普通验证。CMD 只入队并退出;没有命令参数的服务启动才按配置 `runtime.mode = "worker"` 执行持久队列,不能为了跑测试启动它。
|
||
|
||
Job 声明 `database default`、同领域 App 参数类型、`retry(3)` 和 `timeout(30000)`,执行时只调用 App。
|
||
|
||
入队和入口写入在同一事务中;key 用来识别同一请求,重复提交不会创建另一个任务。Job 执行有自己的事务,Model 的 request_key 唯一约束防止重复档案。失败由核心队列重试,不另写循环、sleep 或第三方 Worker。
|
||
|
||
`dever test <root> --filter report.archive.queued --timeout-ms 5000` 使用运行器拥有的临时 SQLite。测试重复入队验证同一任务 ID,通过 `dever.test.drain_jobs(5)` 执行已到期任务,使用 `advance_clock(1000)` 推进虚拟时钟。既不使用配置里的 `data/jobs.db`,也不启动真实后台服务。
|
||
|
||
CMD/Test 的可信执行身份由核心建立为 System。若改为 HTTP 入队,只能从受保护写 API 到达;public 不得入队。核心在每次 User Job 尝试时重新验证会话、租户、组件与入队接口的精确权限,不保存角色快照。
|
||
|
||
## 来源与验证边界
|
||
|
||
集合项目可直接运行 `dever run <root> -- content.article.summarize '{"articles":[{"title":" First ","published":true},{"title":"Hidden","published":false}]}'`,结果包含 `titles: ["First"]` 和 `title_length: 5`。`dever test <root> --filter content.article --timeout-ms 5000` 同时运行集合业务和语法分句断言,无需数据库或服务。
|
||
|
||
这些项目保留了当前语言的角色边界、身份核验、Job 和 Port fake 用法,关键源码随 skill 提供。教程中的 dever 代码块必须有“源码”链接,内容与链接文件的连续片段逐字匹配,所属完整项目参加源码、业务入口、格式和测试检查。真实 Lib、数据库部署和 HTTP 仍需各自验收。
|