RealWorld 规范仓库实战指南:CLAUDE.md 定位解读、Hurl/Bruno 测试套件运行机制与文档工作流
本文以 CLAUDE.md 为主线,结合 Makefile、specs/api、specs/e2e 与 docs/ 的源码与脚本细节,完整讲清楚 RealWorld 规范仓库(spec & docs hub)的定位、目录约定、API 与 E2E 测试套件的运行机制,以及文档站的本地开发流程。读完之后,你既能把这个仓库作为子模块嵌入自己的 RealWorld 实现并跑通全部验证套件,也能理解“Hurl 是 source of truth、Bruno 是生成物”这套测试工程约定的底层原理。
一、仓库定位:这是契约中枢,不是可运行应用
CLAUDE.md 开篇即明确:本仓库是 RealWorld spec & docs hub——它定义每个 RealWorld 前端/后端实现必须遵守的契约,并托管用于验证实现的测试套件,仓库内没有任何可直接运行的应用。
顶层目录分工如下:
| 路径 | 职责 |
|---|---|
| specs/api/ | API 契约:openapi.yml + 后端必须通过的 Hurl 与 Bruno 测试套件 |
| specs/e2e/ | 验证前端的共享 Playwright 套件,外加选择器契约 SELECTORS.md 与 playwright.base.ts |
| docs/ | 用 Astro/Starlight 构建的文档站点 |
| Makefile | 所有操作入口(make help 查看) |
| CONTRIBUTING.md | 人类贡献流程 |
这个定位直接决定了后续所有协作规则:specs/ 下的文件是真相源(source of truth),实现方必须向其对齐,而不是反过来。
作为子模块 / vendored 依赖使用时的红线
CLAUDE.md 特别强调了一个高频场景:实现方会把本仓库以 submodule 或 vendored 方式嵌入自己的代码库(E2E 套件在实现方那边就是被当作 ./e2e 消费的),用规范来测试自己的实现。此时有两条硬规则:
- 修实现,永远不要为了让测试通过而编辑规范或测试本身。
specs/下的文件是失败的实现必须向其看齐的真相源; - 只有当任务本身明确是“修改 RealWorld 规范”时,才允许修改本仓库文件。
这条规则的意义在于防止“改测试迁就实现”的反模式:一旦测试套件被本地改动,契约就失去了约束力。
二、三条核心约定(Conventions)
CLAUDE.md 给出三条约定,每一条都能在仓库中找到对应的落地证据:
- 本仓库内一切操作使用
bun,而非npm/node。 Makefile 中所有目标均为bun ...命令,例如bruno-generate执行bun specs/api/hurl-to-bruno.js,documentation-setup执行cd docs && bun install。 - Hurl 是 API 套件的 source of truth;Bruno collection 由它生成。不要手改 specs/api/bruno/——改 Hurl 文件后重新生成。
specs/api/README.md 中同样声明:Bruno collection 由
make bruno-generate生成,并通过 CI(make bruno-check)保持同步。 - 文档 URL 一律带尾部斜杠(trailing slash)。
这是文档站写作规范,与 docs/astro.config.mjs 中 Starlight 的 sidebar slug(如
specifications/frontend/tests)配合,保证生成的路由 URL 风格一致。
三、API 测试套件:Hurl 主套件与 Bruno 镜像套件
CLAUDE.md 给出的运行命令为(指向一个正在运行的后端,从 specs/api/ 目录执行):
HOST=http://localhost:3000/api ./run-api-tests-hurl.sh # source of truth
HOST=http://localhost:3000/api ./run-api-tests-bruno.sh # generated mirror
下面结合两个脚本的源码,把参数与机制讲透。
3.1 Hurl 脚本:run-api-tests-hurl.sh
脚本核心逻辑只有 10 余行,但设计上有几个值得注意的点:
HOST="${HOST:-http://localhost:8000}"
UID_VAL="${UID_VAL:-$(date +%s)$$}"
HOST:被测后端地址,默认http://localhost:8000;注意默认不含/api前缀,实际使用时(如 CLAUDE.md 示例)要显式带上你的 API 前缀;UID_VAL:默认值为时间戳 + 进程 PID拼接的唯一 ID。它作为变量传入 Hurl,用于生成隔离的测试账号。以 specs/api/hurl/auth.hurl 为例,注册请求体是"username": "auth_{{uid}}"、"email": "auth_{{uid}}@test.com"——同一后端上并发或重复跑套件时,uid保证了账号不冲突;- 支持位置参数:不带参数时运行
hurl/*.hurl全部文件,带参数时只跑指定文件,便于定位单个模块(如只跑hurl/feed.hurl); - 实际执行命令为
hurl --test --jobs 1 --variable "host=$HOST" --variable "uid=$UID_VAL" "${FILES[@]}",其中--jobs 1表示串行执行,这与测试间存在“先注册、后登录、再验证持久化”的有序依赖(每个.hurl文件内请求顺序敏感,如 specs/api/hurl/auth.hurl 中的 Register → Login → Get current user → Update user → Verify update persisted)相配合。
3.2 Bruno 脚本:run-api-tests-bruno.sh
Bruno 版脚本是 Hurl 套件的“镜像”:
BRUNO_SANDBOX="${BRUNO_SANDBOX:-safe}"
bun x @usebruno/cli run "$folder" --env local --env-var "host=$HOST" --sandbox "$BRUNO_SANDBOX"
- 默认扫描
bruno/下的每个文件夹(自动跳过environments/——它只是环境定义,见 specs/api/bruno/environments/local.bru),也支持传入文件夹名只跑一部分; - 通过
--env local加载环境配置,用--env-var "host=$HOST"注入被测地址,--sandbox控制脚本沙箱级别(默认safe); - 用
bun x @usebruno/cli临时拉取 Bruno CLI,无需预先安装。
Bruno 版的所有请求文件夹(articles/、auth/、comments/、feed/、pagination/、errors-*/ 等)与 Hurl 文件一一对应,且文件名带有序号前缀(如 specs/api/bruno/auth/01-register.bru),体现了同样的顺序执行语义。[specs/api/README.md](https://gitcode.com/GitHub_Trending/re/realworld/blob/077acadfef620af681090c336c68ae754a92a797/specs/api/README.md?utm_source=gitcode_repo_files) 还补充了一点:也可以把 bruno/ 文件夹直接拖进 Bruno 桌面应用交互式地运行和检查每个请求。
3.3 生成与校验:make bruno-generate / make bruno-check
CLAUDE.md 给出的两个维护命令在 Makefile 中的定义:
bruno-generate:
bun specs/api/hurl-to-bruno.js
bruno-check:
bun specs/api/hurl-to-bruno.js --check
生成器 specs/api/hurl-to-bruno.js 的工作原理可以从源码结构看到:
- 解析:实现了一个小型状态机解析器(
IDLE→HEADERS→BODY),以#注释行作为请求分隔符并作为请求命名来源,识别GET/POST/PUT/DELETE/PATCH方法行、Key: Value头、以及用花括号深度计数定位边界的 JSON body,同时抽取状态码、[Asserts]与[Captures]区块; - 生成:将解析出的请求写入
bruno/目录,按 Hurl 文件划分为文件夹; --check模式:CI 校验模式,当bruno/目录与 Hurl 文件不同步时让检查失败,从而在 CI 中强制执行“Bruno 目录永远由 Hurl 派生”的约定。
四、E2E 测试套件:实现方如何接入 Playwright 共享套件
CLAUDE.md 对 E2E 的说明是:实现方在自己的配置中扩展 specs/e2e/playwright.base.ts(覆写 baseURL 与 webServer),并满足 specs/e2e/SELECTORS.md 的选择器契约。
4.1 基础配置提供了什么
playwright.base.ts 导出的 baseConfig 关键项:
testDir: './e2e':套件约定放在实现方仓库的./e2e目录——这正是 CLAUDE.md 所说“E2E suite is literally consumed as./e2e”的含义;fullyParallel: false+workers: 1:严格串行,避免账号/数据相互污染;retries: CI ? 2 : 1,forbidOnly: !!process.env.CI:CI 上禁止.only意外混入;timeout: 15_000、actionTimeout: 5_000、navigationTimeout: 10_000,trace: 'on-first-retry'、screenshot: 'only-on-failure':失败自动留痕;- 仅一个
chromium(Desktop Chrome)project。
文件头部的注释直接给出了实现方的接入模板:
import { defineConfig } from '@playwright/test';
import { baseConfig } from './e2e/playwright.base';
export default defineConfig({
...baseConfig,
use: { ...baseConfig.use, baseURL: 'http://localhost:3000' },
webServer: {
command: 'npm run start',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
});
即只需覆写 baseURL 与 webServer 指向自己的开发服务器,其余行为完全继承。
4.2 选择器契约(SELECTORS.md)
specs/e2e/SELECTORS.md 列出了共享 E2E 测试依赖的全部 CSS 类、HTML 属性、文本标签、路由与接口。任何想使用该套件的实现必须提供其中所有选择器,主要包括:
- 表单
name属性:username/email/password(Login、Register、Settings 页)、title/description/body(Editor 页)等; - 布局与导航类:
.navbar、.navbar-brand、.nav-link、.banner、.container; - Feed 与文章类:
.feed-toggle、.article-preview、.article-meta、.article-content、.article-page、.preview-link、.empty-feed-message等; - 标签、评论、Profile 类:
.tag-list、.tag-pill、.comment-form、.card-block、.profile-page等,测试用.card:not(.comment-form) .card-block选择已发布的评论; - 此外还约定了按钮/链接的文本内容、路由、调试接口(
window.__conduit_debug__)、JWT token 的 LocalStorage key、默认头像行为等。
套件覆盖范围包括鉴权、文章、评论、导航、设置、社交功能、错误处理,甚至基础 XSS 安全检查(对应 specs/e2e/ 下的 auth.spec.ts、articles.spec.ts、xss-security.spec.ts 等),docs/src/content/docs/specifications/frontend/tests.md 也明确该套件是“validate your frontend implementation”的共享工具。
五、文档站工作流(docs/)
CLAUDE.md 提供的文档操作命令与 Makefile 中 documentation-* 目标一一对应:
make documentation-setup # cd docs && bun install
make documentation-dev # cd docs && bun run dev(本地开发服务器)
make documentation-build # cd docs && bun run build(生产构建)
Makefile 中还有 CLAUDE.md 未逐条列出的 documentation-dev-host(带 --host 暴露到局域网)、documentation-preview(预览生产构建)与 documentation-clean(清理 docs/.astro、docs/dist、docs/node_modules)。
从 docs/astro.config.mjs 可以看到站点的技术构成:Astro + @astrojs/starlight 主题 + Tailwind(@tailwindcss/vite),站点标题为 RealWorld,sidebar 分三大板块——Implementation creation(Introduction / Features / Expectations)、Specifications(Frontend:Templates/Styles/Routing/API/Tests;Backend:Introduction/Endpoints/API response format/CORS/Error handling/Hurl/Tests;Mobile)、Community。内容源文件位于 docs/src/content/docs/ 下,与 sidebar slug 一一对应。配置里还有一个自定义 Vite 插件 removeMdExtension,用于在构建时去掉 URL 中的 .md 后缀,配合前述“文档 URL 带尾部斜杠”的约定,产出干净的路由。
六、当用户问“怎么搭建一个实现”
CLAUDE.md 的最后一条指引同样重要:实现(implementations)在各自独立的仓库中,本仓库不托管任何官方实现。正确的引导方式是:
- 后端 → 用 specs/api/ 验证:OpenAPI 规范(specs/api/openapi.yml)+ Hurl/Bruno 套件全部跑绿;
- 前端 → 使用共享 CSS 主题(assets/theme/styles.css)+ specs/e2e/(Playwright 套件 + 选择器契约);
- 完整指南 → 指向文档站的 implementation-creation 板块(docs/src/content/docs/implementation-creation/introduction.md)。
七、小结:这个仓库的工程约定为什么值得借鉴
CLAUDE.md 篇幅不长,却把一类典型“契约型仓库”的协作规则压缩得非常完整:
- 单一真相源 + 生成物:Hurl 是唯一手写源,Bruno 目录是纯派生产物,
--check模式把“不许手改生成物”变成了 CI 可执行的检查; - 不可篡改的验证基准:当仓库以 submodule 形式嵌入实现方时,测试是尺子而不是橡皮泥——修实现、永不改测试;
- 最小可继承的配置:Playwright 基础配置把重试、超时、串行、失败留痕等策略固化,实现方只覆写两三个字段即可接入;
- 统一工具链:
bun+make help作为唯一入口,降低了跨工具链的心智负担。
如果你正在为某个框架写 RealWorld 实现,最直接的起点就是:把本仓库挂到实现仓库的 specs/e2e 路径下,按 make help 与上文脚本参数跑通 Hurl 套件与 Playwright 套件,并逐条对照 specs/e2e/SELECTORS.md 补齐选择器——绿了,即代表你的实现符合 RealWorld 契约。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00