Files
dbtool-cli-v1/USABLE_APP_CLI_CONTRACT_SNAPSHOT.md
Paperclip CTO d5f69462b0
Some checks failed
release-smoke / macos-13 / x86_64-apple-darwin (push) Has been cancelled
release-smoke / ubuntu-latest / x86_64-unknown-linux-gnu (push) Has been cancelled
release-smoke / windows-latest / x86_64-pc-windows-msvc (push) Has been cancelled
feat(usable): integrate current dbtool implementation snapshot
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-02 08:26:18 +00:00

263 lines
7.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `dbtool-usable-v1` Shared App / CLI Contract Snapshot
日期2026-03-27
作者Senior Backend Engineer
对应 issue`CMP-46`
## 1. 目标
本文从 `dbtool-usable-v1` 视角冻结当前 `crates/db-app``apps/cli` 的共享契约、错误边界与当前 gap。
本文不是新的架构提案,只记录当前代码与当前阶段可承诺的 backend 行为边界,供 CTO、Frontend、QA 和 PM 直接引用。
## 2. 当前后端分层
- `crates/db-core`
- 定义数据库无关的领域对象与基础校验:
- `ConnectionTarget`
- `InspectRequest`
- `QueryRequest`
- `ExportRequest`
- `InspectResult`
- `QueryResult`
- `crates/db-config`
- 定义 `ConnectionProfile`
- 负责 password env 注入与脱敏展示
- `crates/db-drivers`
- 收敛 PostgreSQL / MySQL / SQLite 的 connect / inspect / query 差异
- `crates/db-app`
- 是当前唯一共享应用编排入口
- 对 connect / inspect / query / export 暴露统一结构化结果与统一错误对象
- `apps/cli`
- 只负责参数解析、stdout/stderr 渲染、退出码
- 当前不应重新定义 shared app 语义
## 3. 领域模型与持久化边界
### 3.1 当前领域对象
- 连接目标:`ConnectionTarget`
- 连接 profile`ConnectionProfile`
- inspect 请求:`InspectRequest`
- query 请求:`QueryRequest`
- export 请求:`ExportRequest`
- 共享错误:`db_app::AppError`
- 共享状态:
- `AppOperation`
- `OperationState`
- `AppEvent<T>`
### 3.2 当前持久化边界
- 当前产品仍是单次命令执行模型
- backend 当前不引入:
- profile 持久化库
- 历史记录库
- 本地状态库
- 后台 daemon / session 存储
- 当前可见写路径只有:
- 用户显式指定的 export 输出文件
- 用户显式选择的 SQLite 数据库文件
### 3.3 迁移结论
- 当前阶段没有 backend 自身的持久化 schema因此没有迁移脚本或迁移兼容问题
- usable-v1 当前不需要新增 migration 策略
- 若未来引入本地状态存储,必须先单独定义存储边界与兼容策略,再进入实现
## 4. `db-app` 当前稳定契约
### 4.1 Connect
- 输入:`ConnectionProfile`
- 成功结果:`ConnectResponse`
- 当前状态语义:
- `success`
- 不存在 `empty`
### 4.2 Inspect
- 输入:`InspectRequest`
- 成功结果:`InspectResponse`
- `payload.kind`
- `schemas`
- `tables`
- `columns`
-`payload.kind=schemas`schema item 额外包含:
- `name`
- `availability``ready | restricted`
- `note`:可选 restricted 说明
- 当前状态语义:
- 非空集合 => `success`
- 空集合 => `empty`
- 执行失败 => `error`
- PostgreSQL root inspect 现会保留 restricted schema 名称,并通过 schema item 暴露权限可见性
- 显式 inspect 某个存在但当前连接无权访问的 PostgreSQL schema 时,当前返回 `error`,不再把 restricted schema 误判为 `empty`
### 4.3 Query
- 输入:`QueryRequest`
- 成功结果:`QueryResponse`
- `result` 字段固定包含:
- `columns`
- `rows`
- `rows_affected`
- `row_count`
- 当前状态语义:
- `rows_affected != null` => command-style success
- 返回至少一行 => `success`
- 零行且 `rows_affected == null` => `empty`
- 执行失败 => `error`
### 4.4 Export
- 输入:
- `QueryRequest`
- `ExportRequest`
- 成功结果:`ExportResponse`
- 成功结果固定包含:
- `target`
- `source`
- `export`
- `row_count`
- 当前状态语义:
- 文件写入成功 => `success`
- `row_count == 0` 仍算 success
## 5. CLI 当前契约
### 5.1 命令面
- `connect`
- `inspect`
- `query`
- `export`
### 5.2 输出模式
- `--result-format text`
- `--result-format json`
### 5.3 成功输出
- text面向人工阅读
- json返回 envelope
```json
{
"status": "success",
"operation": "query",
"state": "success",
"data": {}
}
```
### 5.4 当前退出码约定
- 成功:`0`
- 当前 CLI 错误统一返回:`2`
## 6. 错误边界矩阵
### 6.1 共享应用层已统一的错误
当请求已经进入 `db-app` 后,当前错误会统一收敛为 `AppError`
- `validation`
- `connection`
- `authentication`
- `inspect`
- `query`
- `export`
这些错误在 CLI `--result-format json` 下当前会输出结构化 error envelope并显式带出 `state: error`
### 6.2 当前实际存在的 CLI 前置错误层
在进入 `db-app` 之前,`apps/cli` 仍有一层前置错误来源:
- CLI 参数缺失 / 非法
- `ConnectionTarget` 组装失败
- `ConnectionProfile` 组装失败
- `InspectRequest` 构造失败
- `QueryRequest` 构造失败
- `ExportRequest` 构造失败
- SQL 文件读取失败
- password env 缺失
但在当前源码下,只要用户显式传入 `--result-format json`,这组前置错误也会统一包裹成 JSON `error` envelope`kind` 固定为 `validation``state` 固定为 `error`
这些错误当前仍是字符串错误,不是 `AppError`,因此不完全受 shared error contract 保护。
## 7. 当前 gap / blocker 清单
### 7.1 当前 CLI JSON 状态映射
- CLI JSON envelope 当前固定包含:
- `status`
- `operation`
- `state`
- 当前映射规则:
- envelope 级成功仍返回 `status: success`
- envelope 级失败仍返回 `status: error`
- 共享应用层状态通过 `state` 暴露:
- `connect``success`
- `inspect``success | empty`
- `query``success | empty`
- `export``success`
- 所有错误:`error`
当前判断:
- 这让 CLI JSON 回归样本能显式区分 `empty`
- 同时不破坏既有 `status=success/error` 的 envelope 语义
### 7.2 运行环境说明
- 当前 runner 默认缺少 `cargo` / `rustc` / `cc`
- 本轮通过用户态 Rust toolchain 与 `zig cc` / `zig ar` 包装器完成了源码重建与测试
- 这属于运行环境债务,不是 backend contract defect
### 7.3 Blocker 判断
- 当前没有新的持久化 blocker
- 当前没有 migration blocker
- 当前没有新的 shared contract blocker
- 当前没有新的 backend contract blocker
- 当前 restricted-schema 剩余缺口已收敛为:
- TUI / GUI consumer 侧消费 schema item `availability`
- live fixture 权限模型仍需 QA 与 demo 环境配合验证
## 8. 本轮验证证据
静态核对:
- `crates/db-core/src/lib.rs`
- `crates/db-config/src/lib.rs`
- `crates/db-drivers/src/lib.rs`
- `crates/db-app/src/lib.rs`
- `apps/cli/src/main.rs`
- `TUI_BACKEND_CONTRACT.md`
命令复核:
- `cargo run -q -p dbtool-cli -- inspect --driver sqlite --path /tmp/notfound.sqlite --table accounts --result-format json`
- 实际返回 JSON error envelope`kind=validation``state=error`
- `cargo run -q -p dbtool-cli -- query --driver sqlite --path /tmp/notfound.sqlite --sql '' --result-format json`
- 实际返回 JSON error envelope`kind=validation``state=error`
- `cargo run -q -p dbtool-cli -- connect --driver postgres --host 127.0.0.1 --port 5432 --database demo --username demo --password-env MISSING_ENV --result-format json`
- 实际返回 JSON error envelope`kind=validation``state=error`
- `cargo run -q -p dbtool-cli -- query --driver sqlite --path <seeded-db> --sql 'SELECT ticket_id FROM tickets WHERE status = ?1' --param missing --result-format json`
- 实际返回 `status=success``state=empty`
- `cargo test --workspace`
- 当前 runner 经过用户态 Rust + `zig cc` 补齐后,全工作区测试通过
## 9. 当前结论
- usable-v1 当前 shared app 主契约可继续冻结在 `db-app`
- 当前 CLI 主体没有重新发明 shared domain 语义
- 当前源码已经补齐 CLI JSON 模式下的前置 validation error 一致性
- 当前源码已经补齐 CLI JSON 对共享 `empty` 状态的显式映射
- 当前 backend 这条 contract snapshot 主线没有新增 open blocker
- 当前 backend 更像进入“保持 snapshot 与源码一致 + 发现 defect 就单独拆单”的阶段