NCT_backend 是一个独立的 Cloudflare Workers + D1 + Hono 服务。
建议将它作为与 NCT_database 同级的单独项目运行与部署。
服务运行时只读取当前项目目录内的 package.json、node_modules、wrangler.toml、.dev.vars 和 migrations,不会依赖 NCT_database 目录中的其他文件。
核心能力:
nct_form与nct_databack两张 D1 表- 表字段按传入 JSON 顶层字段自动扩列
- 作为
No-Torsion的后端服务,承接表单、机构修正、翻译与前端运行时保护 token - 直接输出
Hono + JSX的独立表单、确认页与结果页 - 接收母库
nct-api-sql推送的公开 secure records 并写入nct_databack - 按母库请求把
nct_databack导出成附件文件并回传给母库 - 服务首次执行时向母库报告一次
- 之后每 30 分钟向母库上报自身状态,每分钟尝试回传待同步表单记录
用于接收原始写入数据,保留完整 payload_json,并按 payload 顶层字段自动新增动态列。
固定系统列:
idrecord_keypayload_jsoncreated_atupdated_at
作为子库对外请求的数据表,保留完整 payload_json,并维护版本号。
固定系统列:
idrecord_keypayload_jsonversionfingerprintcreated_atupdated_at
版本规则:
- 新记录写入时,
version = 当前最大版本 + 1 - 相同
record_key再次写入且 payload 未变化时,版本不变 - 相同
record_key再次写入且 payload 变化时,版本递增
当 payload 出现新的顶层字段时,服务会对对应表自动执行 ALTER TABLE ... ADD COLUMN。
例如:
{
"name": "Sub School",
"province": "河南",
"age": 18
}可能会生成类似列:
name_136nuuprovince_71r0hxage_ca1uak
说明:
- 列名会做安全规整并带短哈希,避免冲突
- 标量会以字符串形式写入动态列
- 对象和数组会序列化成 JSON 字符串写入动态列
- 原始完整 JSON 仍保留在
payload_json
直接输出独立 Hono JSX 表单页。 适合本地启动后直接打开 Worker 根地址填写问卷。
健康检查,包含两张表记录数与当前 nct_databack 版本号。
nct-api-sql-sub 不再公开通用的 /api/write、/api/data/*、/api/report-now。
正常数据流改为:
No-Torsion前端通过/api/no-torsion/*走业务接口- 母库把公开的 secure records 推送到子库
POST /api/push/secure-records - 母库只在灾备时访问
GET /api/export/nct_databack
供 No-Torsion 前端获取最新表单保护 token。
直接输出独立 Hono JSX 表单页。 适合把前端“填写入口”直接跳到这个页面。
兼容旧路径:
GET /no-torsion/form
处理独立表单页提交,返回 Hono JSX 预览页或确认页。
兼容旧路径:
POST /no-torsion/form
处理独立表单页的最终确认提交流程,并返回 Hono JSX 结果页。
兼容旧路径:
POST /no-torsion/form/confirm
仅当 DEBUG_MOD=true 时开放,提供独立表单页、预览页、确认页、成功页和错误页的调试入口。
POST /debug/submit-confirm 会返回模拟成功页,不会把调试 payload 投递到真实表单或 D1。
供 No-Torsion 主表单在真正提交前执行:
- 防刷 token 校验
- 表单字段校验与规范化
- 预览模式 / 确认模式分流
供 No-Torsion 主表单确认页执行最终投递。
根据配置可投递到:
- Google Form
- 本地 D1
- 两者同时
供 No-Torsion 机构信息补充 / 修正表单提交。
供 No-Torsion 详情页调用明细翻译能力。
母库使用的导出接口。
会把 nct_databack 中 version > afterVersion 的记录按 limit 导出为 JSON 附件文件返回。
说明:
- 如果记录本身已经是母库推送来的 secure payload,会原样回传
- 如果记录是子库本地写入的普通 JSON,会原样回传;母库收到后再按自己的
ENCRYPTION_KEY重新生成 t2 - 这个导出接口要求母库带
Authorization: Bearer <30秒HMAC>;双方用子库serviceUrl派生短期 token,导出包本身明文返回 - 子库会对这个接口做频次限制,默认
DATABACK_EXPORT_MIN_INTERVAL_MS=60000
上报内容格式:
{
"service": "NCT API SQL Sub",
"serviceWatermark": "nct-api-sql-sub:v1",
"serviceUrl": "https://sub.example.com",
"databackVersion": 12,
"reportCount": 7,
"reportedAt": "2026-04-20T13:30:00.000Z"
}其中 reportCount 表示该子服务累计执行上报的次数。
这个计数持久化在 nct_form 中的一条系统保留记录里,不会额外新增第三张业务表。
系统记录使用保留 record_key 前缀 __system__:,并且不会出现在正常的数据列表和业务计数中。
环境变量模板:
cp .env.example .dev.vars./.env.example 已按修改必要性排序列出当前项目的全部环境变量。
本地 Wrangler 读取 .dev.vars;线上部署时,把同名键写入 Cloudflare Variables / Secrets。
这些运行变量不会写入 wrangler.toml;部署脚本使用 wrangler deploy --keep-vars,避免 Git 中的配置覆盖 Dashboard 里的生产变量。
完整 mother/sub 同步与灾备链路至少需要先确认这些值:
- 平台绑定必填但不写进
.env:DB,在wrangler.toml中绑定 D1 SERVICE_PUBLIC_URLMOTHER_REPORT_URL
生产部署还需要确认这些前提:
- 子库现在不再要求额外配置母库公钥、旧 token 或本地导出加密密钥
- 子库和母库之间所有请求都用
SERVICE_PUBLIC_URL/serviceUrl派生的 30 秒 HMAC Bearer token 验证
如果同时作为 No-Torsion 后端并希望真实落库,而不是只停留在预览页,建议明确设置:
NO_TORSION_FORM_DRY_RUN=false
默认行为:
NO_TORSION_FORM_DRY_RUN=trueNO_TORSION_FORM_SUBMIT_TARGET=bothNO_TORSION_CORRECTION_SUBMIT_TARGET=both
按功能必填:
GOOGLE_CLOUD_TRANSLATION_API_KEY仅在你要启用/api/no-torsion/translate-text时需要
其他常用但可选变量:
APP_NAMEMOTHER_REPORT_TIMEOUT_MSDATABACK_EXPORT_MIN_INTERVAL_MSDEBUG_MODNO_TORSION_FORM_IDNO_TORSION_CORRECTION_FORM_IDNO_TORSION_SITE_URLNO_TORSION_FORM_PROTECTION_MIN_FILL_MSNO_TORSION_FORM_PROTECTION_MAX_AGE_MS
其中:
APP_NAME不填时默认使用NCT API SQL Sub- 子库上报时会带上
serviceWatermark: "nct-api-sql-sub:v1";母库用它确认协议类型,但真正认证靠 30 秒 HMAC MOTHER_REPORT_URL填母库基础 URL;子库会固定请求/api/sub/report,并用/api/sub/form-records回传表单记录SERVICE_PUBLIC_URL必须稳定;它既是子库登记 URL,也是上报、表单回传、母库推送和灾备回拉的 HMAC seedDEBUG_MOD=true会开放/debug调试页面,只建议临时测试环境使用nct_databack传输本身不再加密;请求身份通过 HMAC Bearer token 验证- 子库本地普通 JSON 回传给母库时不再额外做字段加密,也不再需要
DEFAULT_ENCRYPT_FIELDS、ENCRYPTION_KEY、ENCRYPTION_KEY_VERSION No-Torsion现在只支持NO_TORSION_*变量名;旧FORM_*/CORRECTION_*兼容别名已删除NO_TORSION_FORM_ID/NO_TORSION_CORRECTION_FORM_ID只填写 Google Form ID,不再支持完整 Google Form 链接变量- 表单保护 secret 不再通过环境变量输入;服务首次发放表单 token 时会自动生成并保存到 D1 的
__system__:form_protection_secret
当 No-Torsion 接入本服务时:
No-Torsion侧将NCT_BACKEND_SERVICE_URL指向这个服务/api/no-torsion/*现已作为浏览器侧业务接口公开,若需要更严格控制,建议在前面放同域代理或可信 BFF,而不是把 secret 下发到前端
注意:
- Cloudflare Workers 没有真正的“部署后立即启动钩子”
- 因此这里的“第一次启动报告”实现为“首次实际执行时报告一次”
- 之后通过 Cron
*/30 * * * *每 30 分钟向母库报告自身状态,并通过* * * * *每分钟尝试回传待同步表单记录
本地开发默认在 .dev.vars 中把 MOTHER_REPORT_URL 设为空,因此手动或定时上报会返回:
{
"delivered": false,
"skipped": true,
"reason": "MOTHER_REPORT_URL is not configured."
}cd NCT_backend
npm install
cp .env.example .dev.vars
npm run dev如果你当前位于 nct 根目录,上面的命令表示进入同级项目 ./NCT_backend 后单独启动它,不需要进入 NCT_database 目录。
本地默认地址:
- Worker:
http://127.0.0.1:8791 - 健康检查:
http://127.0.0.1:8791/api/health
仅推荐使用 Cloudflare Dashboard 的 Workers Builds 网页部署。本项目的 Worker 项目名使用目录名的 Workers 兼容形式:nct-backend。
网页部署会读取 wrangler.toml。部署命令里的 npm run cf:ensure 会自动创建 D1 数据库 nct-backend、把真实 database_id 写入当前构建环境中的 wrangler.toml,并执行远端 D1 migrations;不需要再手动创建 D1 或手动填写 database_id。
wrangler.toml 不包含 [vars],生产变量和密钥以 Cloudflare Dashboard 为准。
| Cloudflare 页面字段 | 填写值 |
|---|---|
| Project name | nct-backend |
| Production branch | 你的生产分支,例如 main |
| Path / Root directory | 在本仓库部署填 NCT_backend;如果本项目单独成库填 / |
| Build command | npm run check |
| Deploy command | npm run deploy |
| Non-production branch deploy command | npm run deploy:preview |
- 进入 Cloudflare Dashboard ->
Workers & Pages->Create->Import a repository。 - 选择 Git 仓库后,按上表填写
Project name、Path、Build command、Deploy command和Non-production branch deploy command。 - 在
Settings->Variables and Secrets配置生产变量:- Variables:
APP_NAME、SERVICE_PUBLIC_URL、MOTHER_REPORT_URL、MOTHER_REPORT_TIMEOUT_MS、DATABACK_EXPORT_MIN_INTERVAL_MS、DEBUG_MOD、NO_TORSION_FORM_DRY_RUN、NO_TORSION_FORM_SUBMIT_TARGET、NO_TORSION_CORRECTION_SUBMIT_TARGET - Secrets:
GOOGLE_CLOUD_TRANSLATION_API_KEY等不应公开的密钥
- Variables:
- 在
Settings->Triggers确认 Cron 来自wrangler.toml:*/30 * * * *和* * * * *。 - 在
Settings->Domains & Routes->Add->Custom Domain绑定sub.example.com。 - 推送生产分支触发部署。首次部署时会自动创建 D1、执行 migrations,然后发布 Worker。
建议生产变量:
APP_NAME=NCT API SQL Sub
SERVICE_PUBLIC_URL=https://sub.example.com
MOTHER_REPORT_URL=https://api.example.com
MOTHER_REPORT_TIMEOUT_MS=10000
DATABACK_EXPORT_MIN_INTERVAL_MS=60000
DEBUG_MOD=false
NO_TORSION_FORM_DRY_RUN=false
NO_TORSION_FORM_SUBMIT_TARGET=d1
NO_TORSION_CORRECTION_SUBMIT_TARGET=d1
部署后检查:
https://sub.example.com/api/health
https://sub.example.com/form
Workers 没有部署后启动钩子,所以首次 report 会在第一次实际请求或后续 Cron 中发生。回到母库 https://api.example.com/Console,确认子库上报已经被记录。
npm run typecheck
npm run test如果你只想验证独立 Hono JSX 页面:
npm run test:jsx当前 JSX 验证会直接覆盖:
NoTorsionStandaloneFormPageNoTorsionStandalonePreviewPageNoTorsionStandaloneResultPage
这些测试会在 Node 环境里直接调用 renderToString(...),确认 hono/jsx 产物可以正常服务端渲染,而不是只测路由字符串拼接。
首次本地开发前会自动执行 migration:
npm run predev手动执行:
npm run db:migrate远端执行:
npm run db:migrate:remote已经本地验证通过:
npm run typechecknpm run testnpm run test:jsxnpm run checknpm run predevGET /api/no-torsion/frontend-runtimePOST /api/no-torsion/form/preparePOST /api/no-torsion/form/confirmPOST /api/no-torsion/correction/submitPOST /api/no-torsion/translate-textGET /api/export/nct_databackGET /cdn-cgi/handler/scheduled