控制面改版 · commit 9036a17

控制面换成 WebUI + 内嵌数据库,yaml 降级为导入导出

同步是长期存在的系统,不是一次性脚本;配置不该躺在文件里被人手改

为什么这个方向是对的

旧(YAML-first)问题
任务写在 `job.yaml`用户要手写字段名——这正是我们说要避免的「让用户理解实现细节」
连接串在文件里明文密码可能进 git / 备份 / 聊天记录;改一次要编辑文件
看进度靠 `status`长期运行的系统,用户要的是「现在到哪、卡在哪」,不是一屏文本
多任务多文件没有统一视图:哪些在跑、哪些失败

关键:两个数据库,分工不能混

控制库(本地 SQLite)运行时库(目标端 `_jl_*`)
存什么连接、任务定义、运行历史、设置、凭证密文阶段、权威位点、块断点、租约、冲突、死信、审计
权威性「应该做什么」「已经到哪了」
丢了会怎样任务定义丢失(可从 yaml/备份恢复)位点丢失 → 必须重新初始化
红线:位点永远不放进控制库。它必须与数据同事务提交在目标库——这是幂等的根基。

数据模型(控制库)

connections(id, name, kind, host, port, database, username,
            secret_enc BLOB,      -- AES-256-GCM,永不回传
            params_json, last_test_*)
jobs(id, job_key UNIQUE, name, source_id, target_id,
     spec_json,               -- 与 job.schema.json 同构,便于导入导出
     enabled)
runs(id, job_id, phase, started_at, ended_at, rows_done, lag_*, last_error)
settings(k, v)                -- instance_id / schema_version
audit(id, at, actor, action, detail_json)

连接密码:每条独立 nonce 的 AES-256-GCM;密钥来自 `--key-file`(0600) / `JINLIANG_KEY` / 首启生成。导出 yaml 时省略密码。

UI 页面按「用户一天怎么用」排

  1. 总览:在跑的任务卡(阶段/延迟/吞吐/最近错误)、今日成败、书签占用
  2. 任务详情:SSE 实时流 + 阶段时间线 + 「系统为你做了什么」可 undo
  3. 新建任务向导(核心):选连接 → 勾表(带行数/主键)→ 频次/方向/内容 → 预览类型映射与风险 → 预检 → 确认
  4. 连接管理 · 运行历史 · 诊断(doctor/gc/冲突/死信)· 设置

全程不出现 WAL / slot / LSN危险操作二次确认 + 可撤销移动端优先

技术选择(保持单二进制)

项选择理由
UIGo html/template + htmx(单文件 vendored)+ 手写 CSS,embed 进二进制不引入 Node 构建链;可被 AI 助手直接读
SQLitemodernc.org/sqlite(纯 Go)守住 CGO_ENABLED=0 与交叉编译
实时SSE(原生 EventSource)比 WebSocket 简单,够用
认证单管理员 + argon2id;HttpOnly cookie + CSRFv1 不做多租户
体积UI 资源 <1 MB,驱动约 +3 MB仍守 <25 MB

CLI 退位但不消失

命令用途
jinliang serve起控制面(默认 127.0.0.1:8080),首启建管理员
import / export与控制库交换 yaml(GitOps、迁移、备份)
run --job <id>headless 执行(容器/CI 必需)
doctor/version基础运维
plan / preview已并入 UI;CLI 只留 --json 给自动化

对今晚的影响

批次表新增 B0 控制面骨架,排在 B1 引擎之前;团队加了一个人。

批次内容主导
B0(今晚)SQLite 模型 + 凭证加密 + REST/SSE + UI 骨架(总览/连接/新建向导/详情)+ serve/import/export/run --jobPanel 02HTWS(新)
B1(明晚)PG→PG 引擎闭环(任务来源改为控制库记录)Core 9Q8FEQ
B2–B6MySQL 源 / 异构与目标端 / 运维面 / 五档频次 / 性能与门禁Data / Gate

B0 验收serve → 建连接 → 建任务 → 预检 → run(桩)→ SSE 看到阶段不经浏览器也能用 API 走完

改了什么(仓库)