Files
dbtool-cli-v1/TUI_BACKEND_CONTRACT.md
Paperclip CTO a28dab4cd9
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): package gui-host validation snapshot
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-31 10:21:36 +00:00

250 lines
6.5 KiB
Markdown
Raw 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.

# TUI Backend Contract
日期2026-03-27
作者Senior Backend Engineer
## 1. 当前后端边界
- `crates/db-core`:数据库无关的领域对象与基础校验。
- `crates/db-config`:连接 profile、密码环境变量注入与脱敏摘要。
- `crates/db-drivers`PostgreSQL / MySQL / SQLite 驱动实现与差异收敛。
- `crates/db-app``connect` / `inspect` / `query` / `export` 共享应用编排、结构化结果、统一错误对象,以及 TUI worker 可复用的执行状态。
- `apps/cli`参数解析、stdout/stderr 渲染、退出码。
## 2. 持久化边界
- 当前产品仍是单次命令执行模型,没有连接配置持久化、历史记录持久化或后台状态存储。
- 当前写路径只有:
- `export` 明确指定的输出文件
- SQLite 目标数据库本身(由用户选择)
- TUI 第二阶段 live integration 仍不引入新的数据库、本地缓存库或后台 daemon 存储契约。
## 3. 共享请求对象
TUI worker 应直接构造共享 Rust 对象,不要拼接 CLI flags更不要解析 CLI 文本。
### Connect
- 输入:`db_config::ConnectionProfile`
- 说明:
- `name` 用于当前会话内的目标标识
- `target` 复用 `db_core::ConnectionTarget`
- `password_env_var` 只作为脱敏标签保留secret 仍通过环境变量注入,不进入持久化
### Inspect
- 输入:`db_core::InspectRequest`
- 字段:
- `schema: Option<String>`
- `table: Option<String>`
- 约束:
- `table.is_some()` 时必须同时提供 `schema`
### Query
- 输入:`db_core::QueryRequest`
- 字段:
- `sql`
- `source`
- `parameters`
- `source` 语义:
- `QuerySource::Inline`
- `QuerySource::File`
### Export
- 输入:
- `db_core::QueryRequest`
- `db_core::ExportRequest`
- `ExportRequest` 字段:
- `format`
- `output_path`
- `overwrite`
- 约束:
- 只允许导出返回结果集的查询
- 不静默覆盖已有文件
- 不为 TUI 增加新的导出元数据存储
## 4. 共享结构化结果
TUI 应优先直接调用 `crates/db-app`,不要解析 CLI 的人类可读文本。
### Connect
- 返回 `ConnectResponse`
- 字段:
- `target.profile_name`
- `target.driver`
- `target.endpoint`
- `target.password_env_var`
- `status`
- 当前 `status` 固定为 `connected`
### Inspect
- 返回 `InspectResponse`
- 字段:
- `target`
- `scope.schema`
- `scope.table`
- `payload`
- `payload.kind` 为:
- `schemas`
- `tables`
- `columns`
- `payload.items` 允许为空;空数组不是错误
### Query
- 返回 `QueryResponse`
- 字段:
- `target`
- `source.kind``inline` / `file`
- `source.label`
- `source.path`
- `result.columns`
- `result.rows`
- `result.rows_affected`
- `result.row_count`
- `rows_affected != null` 表示 command-style 执行成功但没有结果集
### Export
- 返回 `ExportResponse`
- 字段:
- `target`
- `source`
- `export.format`
- `export.output_path`
- `export.overwrite`
- `row_count`
## 5. 错误模型
`db-app::AppError.kind` 当前分为:
- `validation`
- `connection`
- `authentication`
- `inspect`
- `query`
- `export`
这组分类是 TUI banner、QA 断言和未来 GUI 状态映射的当前稳定基础。
`AppError.target` 为可选字段:
- 有目标上下文时返回脱敏后的 `ConnectionSummary`
- 参数校验在目标尚未构成时可为 `null`
## 6. Worker / Channel 状态契约
`crates/db-app` 现提供:
- `AppOperation``connect | inspect | query | export`
- `OperationState``running | success | empty | error`
- `AppEvent<T>`worker / channel 推荐 envelope
推荐发送顺序:
1. 先发 `AppEvent::running(operation)`
2. 成功后发送 `response.into_event()`
3. 失败时发送 `error.into_event()`
状态语义固定如下:
- `connect`
- `running`:正在测试连接
- `success`:连接成功
- `error`:连接失败
- `inspect`
- `success`:返回非空 schema / table / column 集合
- `empty`:返回空集合,但请求本身成功
- `error`inspect 失败
- `query`
- `success`:返回至少一行,或 `rows_affected` 非空
- `empty`:返回零行且 `rows_affected == null`
- `error`:执行失败
- `export`
- `success`:文件写入成功;`row_count == 0` 仍算成功
- `error`:导出校验、查询或文件写入失败
示例:
```rust
use db_app::{AppEvent, AppOperation};
sender.send(AppEvent::<()>::running(AppOperation::Query))?;
match db_app::query(&profile, &request) {
Ok(response) => sender.send(response.into_event())?,
Err(error) => sender.send(error.into_event())?,
}
```
## 7. CLI 结构化输出
CLI 继续保留默认文本输出,同时新增:
- `--result-format text`
- `--result-format json`
JSON 返回 envelope
```json
{
"status": "success",
"operation": "query",
"state": "success",
"data": {}
}
```
- `status` 继续只区分 envelope 级成功/失败
- `state` 对齐共享应用层状态:
- `connect``success`
- `inspect``success | empty`
- `query``success | empty`
- `export``success`
错误返回 envelope
```json
{
"status": "error",
"operation": "query",
"state": "error",
"error": {
"operation": "query",
"kind": "query",
"message": "..."
}
}
```
CLI JSON envelope 继续作为跨入口回归样本,但 TUI live path 不应以调用 CLI 二进制作为主集成方式。
## 8. Frontend 接入约束
- TUI 直接依赖 `crates/db-app``db-core`,不解析 CLI stdout/stderr
- UI 状态映射应优先使用 `OperationState`,不要自行发明另一套 success/empty/error 语义
- `ConnectionSummary.endpoint``password_env_var` 仅用于展示脱敏上下文,不应用作 secret 来源
- `AppError.kind` 必须原样进入状态区 / inspector避免把 `validation``connection``query` 混成统一“失败”
- 若未来引入异步 worker 池,仍以共享 response/error 对象作为唯一 UI 数据源
## 9. 当前回归边界
- `crates/db-app` 回归需覆盖:
- response -> `OperationState` 映射
- `AppEvent<T>` / `AppError` 序列化
- 空 inspect / 空 query / command query 语义
- `apps/cli` 回归继续覆盖:
- `--result-format json` envelope
- text/json 输出在相同 `db-app` 结果上的一致性
## 10. 演进规则
- CLI 文本文案可小幅演进,但 `db-app` 结构化对象字段应保持兼容。
- 新增数据库驱动时,优先扩展 `db-drivers``db-app`,不要在 TUI/CLI 内复制数据库语义。
- 若未来引入本地持久化(例如连接历史),应先新增独立文档定义存储边界,再进入实现。