Metadata-Version: 2.4
Name: dv-platform
Version: 0.1.8
Summary: Git-like dataset version management platform: FastAPI backend + dv CLI, single pip install
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: fastapi>=0.115
Requires-Dist: uvicorn[standard]>=0.30
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: pydantic>=2.7
Requires-Dist: pydantic-settings>=2.3
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: PyJWT>=2.8
Requires-Dist: python-dotenv>=1.0
Requires-Dist: boto3>=1.34
Requires-Dist: typer>=0.12
Requires-Dist: rich>=13
Requires-Dist: httpx>=0.27
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: httpx>=0.27; extra == "test"

<div align="center">

# 🗂️ dv-platform · 数据集版本管理平台

**Git for Datasets —— 面向 AI 数据集 / 标注数据 / 大文件资产的「类 Git」版本管理平台**

<br>

<img src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white" />
<img src="https://img.shields.io/badge/Backend-FastAPI-009688?logo=fastapi&logoColor=white" />
<img src="https://img.shields.io/badge/CLI-dv-blueviolet" />
<img src="https://img.shields.io/badge/Server-dv--server-8A2BE2" />
<img src="https://img.shields.io/badge/Web-React%20%2B%20AntD-61dafb?logo=react&logoColor=white" />
<img src="https://img.shields.io/badge/Storage-Local%20%2F%20MinIO%20%2F%20S3-orange" />
<img src="https://img.shields.io/badge/DB-SQLite%20%2F%20PostgreSQL-336791?logo=postgresql&logoColor=white" />

</div>

> [!NOTE]
> 一个面向 **AI 数据集 / 标注数据 / 大文件资产** 的「类 Git」版本管理平台：`dv` CLI 管数据、`dv-server` 管服务、Web 管浏览与分享。会 Git，就会用 dv。
>
> ✅ **适用场景：本地单机 / 组织内网（私有化）数据集管理系统**——`dv-server` 一条命令自托管，Web / CLI 全走内网，数据不出企业网络。

---

## 🚀 快速开始（Quick Start）

5 分钟从零到第一个云端版本：

```bash
pip install dv-platform                     # 一条命令同时安装 dv CLI 与 dv-server

# 1) 免交互初始化并启动服务（自带 Web UI，默认 http://localhost:8000）
dv-server setup --root D:/dv --non-interactive --admin-pass 'secret' --token-name ci
dv-server start --data-dir D:/dv

# 2) 登录 → 建数据集 → 提交 → 推送 → 拉取
dv login --token <上一步输出的 TOKEN> --url http://127.0.0.1:8000
dv create team/my-dataset --visibility public
dv init team/my-dataset
dv add ./images ./labels.json
dv commit -m "v1: 初版标注数据"
dv push
dv pull
```

> 📖 **安装、dv-server 与 dv CLI 的完整命令用法与示例见下文「使用文档」章节**。

---

## 简介

dv-platform 是一个「类 Git」的**数据集版本管理平台**，面向 AI 数据集、标注数据、大文件资产，
提供 `add / commit / push / pull / clone / checkout / log / tag / diff / rollback` 等命令，
思路与 Git 一致，熟悉 Git 的用户可以快速上手。

设计上的一些取舍：

- 文件以 `sha256(内容)` 寻址存储，相同内容不重复存放，版本之间只保留变化的部分；
- 服务端只存版本元数据，文件内容通过预签名 URL 直传直下对象存储，大文件不经过应用服务；
- 提交不可变、删除按引用计数清理，尽量避免共享文件被误删；
- 自带 `dv-server` 与 Web UI，适合在本地或组织内网部署使用。

> 项目仍在迭代中，功能与行为可能随版本调整，欢迎试用与反馈。

## 界面示例

本地部署后 Web UI 的「文件」页截图（数据集文件清单示例）：

<img src="static/example.png" alt="数据集文件页示例（文件清单）" width="900" />

---

## 📖 使用文档（dv-server / dv CLI 命令详解）

> 以下为 dv-server 与 dv CLI 的**逐条命令说明与示例**，以及安装、部署、存储后端、Web UI、API 等操作说明，适用于本地 / 组织内网部署后的日常使用与运维。

### 0. 命令速查

| 命令 | 用途 |
|------|------|
| `dv-server start / stop / status / restart / logs` | 后台启动 / 停止 / 查看 / 重启 / 看日志 |
| `dv-server run` | 前台运行服务（默认命令） |
| `dv-server setup` | 初始化数据目录（交互向导或免交互） |
| `dv-server bootstrap` | 在服务器上创建管理员账号 |
| `dv-server token create / list / revoke` | 服务器本地签发 / 列出 / 吊销 API Token |
| `dv-server config show / set / unset` | 查看 / 修改 / 删除服务器配置（.env） |
| `dv login / whoami` | 保存登录凭据 / 查看当前用户 |
| `dv token create / list / revoke` | 客户端方式管理自己的 API Token |
| `dv create / dv dataset delete` | 创建 / 删除数据集 |
| `dv init / add / status / commit` | 初始化工作区 / 暂存文件 / 查看状态 / 本地提交 |
| `dv push / pull` | 推送本地提交到云端 / 拉取最新版本 |
| `dv clone / fetch / checkout` | 克隆数据集 / 下载指定版本 / 检出指定版本 |
| `dv log / tag / tags / branches / diff / rollback / ls` | 版本历史 / 打标签 / 分支 / 差异 / 回滚 / 浏览文件 |

---

### 1. 安装

#### 1.1 一条命令安装（推荐）

```bash
pip install dv-platform
```

安装后获得两个命令：

| 命令 | 作用 |
|------|------|
| `dv` | 数据集版本管理 CLI（客户端） |
| `dv-server` | 启动 / 运维后端服务（含 Web UI） |

检查安装：

```bash
dv version          # 例如: dv CLI 0.1.7
dv --help           # 查看全部子命令
dv-server --help    # 查看全部子命令（含速查手册）
```

> 旧版 `dv-cli` 请先 `pip uninstall dv-cli`，避免与 `dv` 命令冲突。

#### 1.2 从源码运行（开发环境）

```bash
python -m venv .venv
.venv\Scripts\pip install -r backend/requirements.txt     # Windows
# 或  source .venv/bin/pip install -r backend/requirements.txt   # Linux/macOS
```

前端（可选，改界面时）：

```bash
cd web
npm install
npm run build        # 产物 web/dist，由后端自动挂载
npm run dev          # 开发模式热更新，代理 /api 到 :8000
```

---

### 2. dv-server 命令参考（服务端）

所有服务端可变数据（`dv.db`、对象存储 `storage/`、`.env`、PID、日志）都放在**数据目录**里：

- `run`（前台）默认用**当前目录**；
- `start / stop / restart / status / logs / bootstrap / token / config` 默认用 `~/.dvserver`（可用环境变量 `DV_SERVER_DIR` 或参数 `--data-dir` 覆盖）。

每个子命令都支持 `--help`。

#### 2.1 服务生命周期：run / start / stop / status / restart / logs

公共参数：

| 参数 | 说明 | 默认 |
|------|------|------|
| `--host` | 监听地址 | `run`：127.0.0.1；`start/restart`：0.0.0.0 |
| `--port` | 监听端口 | 8000 |
| `--workers` | uvicorn worker 数 | 1 |
| `--data-dir` | 数据目录 | `run`：当前目录；其它：`~/.dvserver` |
| `--storage-root` | 数据集文件对象存储目录（覆盖 `DV_STORAGE_ROOT`） | `<数据目录>/storage` |
| `--log-level` | uvicorn 日志级别 | info |
| `--wait` | `start/restart` 等待健康检查秒数 | 30 |
| `--non-interactive` | `start/restart` 首次启动跳过交互向导 | — |

**run（前台运行）**

```bash
dv-server run                          # 前台，默认 127.0.0.1:8000，数据目录=当前目录
dv-server run --host 0.0.0.0 --port 9000
dv-server run --data-dir D:/dv --port 8000
```

> 不带任何参数直接执行 `dv-server` 也等同于 `run`（例如 `dv-server --host 0.0.0.0 --port 8000`）。

**start（后台守护进程）**

```bash
dv-server start                        # 后台启动，默认 0.0.0.0:8000，数据目录 ~/.dvserver
dv-server start --port 9000 --data-dir D:/dv
dv-server start --storage-root D:/dataset-objects     # 大文件放到独立磁盘
dv-server start --non-interactive      # 首次启动不弹向导，直接写默认 .env
```

首次 `start` 自动生成 `.env`（含随机 `DV_JWT_SECRET`，重启后凭据保持有效）。若数据目录是全新的且处于交互终端，会先弹出初始化向导（等价于 `dv-server setup`）。

**stop / status / restart / logs**

```bash
dv-server status                        # 是否在运行 + 健康状态
dv-server status --port 9000
dv-server stop                          # 停止
dv-server stop --port 9000
dv-server restart                       # 停止后重启（参数同 start）
dv-server logs --tail 50                # 查看最近日志
dv-server logs --port 9000 --tail 200
```

需要开机自启时，把 `dv-server start` 加入 Windows 任务计划程序（开机触发）或 systemd 单元即可。

#### 2.2 setup：初始化

| 参数 | 说明 |
|------|------|
| `--root <dir>` | 单目录模式：`.env`、数据库、对象存储、日志全放这一个目录 |
| `--data-dir <dir>` | 数据目录（默认 `~/.dvserver`） |
| `--non-interactive` | 免交互（配合下面参数使用） |
| `--force` | 已存在 `.env` 也重新引导 |
| `--host` / `--port` | 监听地址 / 端口（免交互时生效，默认 0.0.0.0:8000） |
| `--storage-root <dir>` | 大文件存储目录 |
| `--admin-user <name>` | 管理员用户名（默认 admin） |
| `--admin-pass <pwd>` | 管理员密码（留空则随机生成，写入 `.env` 的 `DV_FIRST_ADMIN_PASSWORD`） |
| `--token-name <name>` | 同时签发一个初始 API Token（名字随意） |

**交互引导**

```bash
dv-server setup
```

按提示选择：安装目录 → 监听地址/端口 → 存储后端（local/s3）→ 对外访问地址 → 元数据库（sqlite/postgres）→ 管理员账号密码 → 是否立即签发初始 Token。

**单目录免交互（脚本 / CI 常用）**

```bash
dv-server setup --root D:/dv --non-interactive --admin-pass 'secret' --token-name ci
# → D:/dv 下自动生成 .env / dv.db / storage/，创建 admin，并签发名为 ci 的初始 Token
dv-server start --data-dir D:/dv
```

**重跑 / 强制重引导**

```bash
dv-server setup --force                 # 已有 .env 时需加 --force
```

#### 2.3 bootstrap：创建管理员

适用于**还没有任何用户**的全新服务器（首次创建管理员；已有用户时命令会报错，请改用 Web 注册或 `dv-server setup`）。

```bash
dv-server bootstrap --password 'secret'             # 创建 admin（默认用户名 admin）
dv-server bootstrap --username boss --password 'x'  # 指定用户名
```

不传 `--password` 时使用 `.env` 的 `DV_FIRST_ADMIN_PASSWORD`（默认 `admin123`，**建议改成自己的**）。

#### 2.4 token：服务器本地签发 / 管理 API Token

| 子命令 | 说明 |
|--------|------|
| `token create` | 签发 Token（明文**只打印一次**） |
| `token list` | 列出全部 Token（含所属用户、最近使用） |
| `token revoke <id>` | 按 id 吊销 |

```bash
dv-server token create --name ci --user admin    # 输出明文，只显示一次
dv-server token list
dv-server token revoke 3
```

适合初始化部署、CI 脚本、管理员应急（Web UI 的 Token 页等价）。客户端方式见 `dv token`（需先登录）。

#### 2.5 config：查看 / 修改服务器配置

配置实际读写数据目录里的 `.env`，不用手动编辑文件：

| 子命令 | 说明 |
|--------|------|
| `config show` | 查看全部配置（密钥自动打码）+ 生效信息 |
| `config show --json` | JSON 输出（脚本用） |
| `config show --show-secrets` | 明文显示密钥 |
| `config set KEY=VALUE [KEY=VALUE ...]` | 写入配置（可一次多个） |
| `config unset KEY [KEY...]` | 删除配置项 |

```bash
dv-server config show
dv-server config show --json
dv-server config show --show-secrets

dv-server config set DV_STORAGE_ROOT=D:/dataset-data DV_PUBLIC_BASE_URL=http://10.0.0.5:8000
dv-server config unset DV_WEB_DIST
```

规则：

- 只接受平台认识的 `DV_*` 键（未知键会报错并列出可用键）；
- 值不能为空（删除请用 `unset`）；
- 修改后需 `dv-server restart` 生效（配置在进程启动时读取）；
- 监听地址 / 端口是**启动参数**（`--host/--port`），不写在 `.env` 里。

常用配置键一览：

| 键 | 默认 | 说明 |
|----|------|------|
| `DV_DATABASE_URL` | `sqlite:///./dv.db` | 元数据库（相对路径以数据目录为基准；生产用 PostgreSQL） |
| `DV_STORAGE_BACKEND` | `local` | `local` 或 `s3` |
| `DV_STORAGE_ROOT` | `./storage` | 本地后端大文件目录（相对路径以数据目录为基准） |
| `DV_S3_ENDPOINT` / `DV_S3_BUCKET` / `DV_S3_ACCESS_KEY` / `DV_S3_SECRET_KEY` / `DV_S3_REGION` | localhost:9000 / datasets / … | S3 兼容存储（MinIO/OSS/COS/S3） |
| `DV_PUBLIC_BASE_URL` | `http://localhost:8000` | 对外访问地址，预签名 URL 以此为基准 |
| `DV_PRESIGN_TTL` | `900` | 预签名 URL 有效期（秒，15 分钟） |
| `DV_JWT_SECRET` / `DV_JWT_ALGORITHM` / `DV_JWT_EXPIRE_MINUTES` | 随机 / HS256 / 10080 | Web 登录 JWT |
| `DV_FIRST_ADMIN_PASSWORD` | `admin123` | 首次管理员初始密码 |
| `DV_WEB_DIST` | 空 | 指向构建好的 `web/dist` 可启用 Web UI |
| `DV_CHUNK_SIZE` | 8MB | 文档/分片参考大小 |

#### 2.6 指定数据集存储路径

```bash
# 方式 1：启动参数（run / start / restart 均支持）
dv-server start --storage-root D:/dataset-objects

# 方式 2：环境变量
DV_STORAGE_ROOT=D:/dataset-objects dv-server start

# 方式 3：写入配置后重启
dv-server config set DV_STORAGE_ROOT=D:/dataset-objects
dv-server restart
```

说明：

- 元数据库与对象目录分开：数据库由 `DV_DATABASE_URL` 决定，对象目录由 `DV_STORAGE_ROOT` 决定；
- `--storage-root` 相对路径以**数据目录**为基准，绝对路径完全独立，方便放到独立磁盘/挂载点；
- S3 后端对象不落本地，此选项可忽略；
- 存储路径是服务器端配置，CLI / Web 不感知，仍走预签名 URL 直传直下。

#### 2.7 健康检查

```bash
curl http://127.0.0.1:8000/api/v1/health     # 返回 HTTP 200
```

`dv-server status` 内部也使用该接口判断健康状态。

---

### 3. dv 命令参考（客户端 CLI）

#### 3.0 概念与约定

**数据集标识**：`namespace/name`。省略 namespace 时默认 `default`，例如 `dv create mydata` 等价于 `dv create default/mydata`。

**登录凭据**：`dv login` 把服务地址和 Token 保存到 `~/.dv/config.json`（可用环境变量 `DV_HOME` 改位置）。大多数命令直接用这份凭据；工作区命令使用工作区记录的服务地址。

**工作区（workspace）**：`dv init` 会在当前目录创建 `.dv/` 目录，其中：

| 文件 | 作用 |
|------|------|
| `.dv/config.json` | 绑定的数据集（namespace/name/id/branch）与远端地址 |
| `.dv/index.json` | 暂存区：`dv add` 暂存的文件清单（path → sha256/大小） |
| `.dv/pending.json` | 待推送的本地提交（`dv commit` 生成，`dv push` 消费） |
| `.dv/HEAD` | 本地记住的已推送 commit |

**版本引用 ref** 支持：标签名、分支名、`HEAD`/`latest`、版本序号 `vN`、commit 哈希（前缀），例如 `v1.0`、`main`、`HEAD`、`v3`、`a1b2c3d`。

#### 3.1 登录与会话

```bash
dv login --token <API_TOKEN> --url http://127.0.0.1:8000
dv login --token <API_TOKEN>            # 不传 --url 保留上次地址
dv whoami                               # 显示当前用户：name <email> role=...
```

`dv login` 成功后会调用 `/api/v1/auth/me` 校验并显示登录的用户名与角色。

#### 3.2 客户端 Token 管理（dv token）

```bash
dv token create --name ci                                # 创建，永不过期
dv token create --name deploy --expires 2027-01-01T00:00:00   # 带过期时间
dv token list                                            # 列出（id/名称/过期/最近使用）
dv token revoke 3                                        # 吊销 id=3 的 Token
```

注意：明文只在创建时打印一次。`dv-server token create` 则直接在服务器本地签发（不需要先登录）。

#### 3.3 数据集管理

```bash
# 创建（默认 private）
dv create team/my-dataset
dv create team/my-dataset "图像分割数据集" --visibility public
dv create mydata                              # namespace 省略则默认 default

# 删除（仅 owner；先展示影响范围并二次确认）
dv dataset delete team/my-dataset
dv dataset delete team/my-dataset --yes       # 或 -y，跳过确认
```

删除会同步清理云端存储：只物理删除「引用归零」的 blob，被其它数据集共享的文件会保留（输出里会报告释放字节数与保留的共享 blob 数）。

#### 3.4 工作区：init / add / status / commit

```bash
# 在工作目录初始化（必须已存在该数据集）
cd workdir
dv init team/my-dataset
dv init team/my-dataset --branch dev          # 指定工作分支

# 暂存文件/目录（递归扫描，跳过 .dv 与 .git，计算 sha256）
dv add ./images ./labels.csv
dv add ./images --workers 4

# 查看状态：暂存文件数、待推送提交、相对远端 HEAD 的新增/修改
dv status

# 本地提交（必须至少暂存过文件）
dv commit -m "v1: 初始标注数据"
```

`dv add` 只是把文件登记到暂存区（含哈希），不会上传；`dv commit` 生成一个**待推送提交**，真正上传在 `dv push`。

#### 3.5 传输：push / pull / clone / fetch / checkout

```bash
# 推送：只上传服务器缺失的 blob（sha256 去重），再创建云端版本
dv push
dv push --workers 16                          # 提高并发
dv push --no-progress                         # 脚本里关闭进度条

# 拉取最新版本到工作区（已存在且哈希一致的文件自动跳过=断点续传）
dv pull
dv pull -o ./latest --workers 4

# 克隆（最新版本）到新目录并自动初始化工作区
dv clone team/my-dataset -o ./data
dv clone team/my-dataset                      # 默认放到 ./<name>

# 下载指定版本（纯下载，不创建工作区）
dv fetch team/my-dataset v1.0 -o ./old
dv fetch team/my-dataset main --path images   # 只下载子路径 images/
dv fetch team/my-dataset a1b2c3d

# 在工作区内检出指定版本（把文件写回工作区并更新 HEAD）
dv checkout v1.0
dv checkout main --workers 8
```

下载均带 sha256 校验，写入先落 `.part` 临时文件、校验通过后原子改名；`--no-progress` 可关闭进度条。

#### 3.6 版本历史 / 标签 / 分支 / 差异 / 回滚 / 浏览

```bash
dv log                                # 版本历史（默认 50 条）
dv log --limit 100

dv tag v1.0                           # 给 HEAD 打标签
dv tag v1.1 --ref v3                  # 给指定版本打标签
dv tags                               # 列出标签

dv branches                           # 列出分支（* 表示当前分支）

dv diff v1 HEAD                       # 两个版本差异（base head）
dv diff v1.0 main

dv rollback v1 -m "误删恢复，回滚到 v1"  # append-only 回滚：生成新版本，历史不丢
dv rollback a1b2c3d

dv ls                                 # 浏览 HEAD 文件清单（路径/大小/hash）
dv ls --version v1.0
dv ls --version v1.0 images            # 只看 images/ 下文件
```

`dv rollback` 不是改写历史，而是在云端追加一个新提交，回滚后 `dv log` 仍能看到全部历史。

#### 3.7 其它

```bash
dv version         # CLI 版本
dv --help          # 总帮助
dv token --help    # 子命令帮助
dv dataset --help
dv push --help     # 任意命令加 --help 看参数
```

---

### 4. 端到端示例

#### 4.1 首次部署：从零创建第一个云端版本

```bash
# 1) 初始化并启动服务（自动创建 admin 并签发 ci Token）
dv-server setup --root D:/dv --non-interactive --admin-pass 'secret' --token-name ci
dv-server start --data-dir D:/dv

# 2) 客户端登录
dv login --token <上一步输出的 TOKEN> --url http://127.0.0.1:8000

# 3) 建数据集 → 初始化工作区 → 暂存 → 提交 → 推送
dv create cv/coco --visibility public
mkdir work && cd work
dv init cv/coco
dv add ./images ./annotations
dv commit -m "COCO 初始数据集"
dv push
```

#### 4.2 日常迭代

```bash
cd work
# 把新文件/改动加进下一版
dv add ./images/新增图片
dv commit -m "补充 200 张新图片"
dv push
dv log
```

#### 4.3 队友拿到最新数据 / 指定版本

```bash
# 方式一：全新拉取
dv clone cv/coco -o ./coco-latest

# 方式二：已有工作区，更新到最新
cd ./coco-latest && dv pull

# 方式三：只要某个历史版本（甚至可以只下载子目录）
dv fetch cv/coco v2.1 -o ./release-data
dv fetch cv/coco v2.1 --path labels -o ./labels-only
```

#### 4.4 回滚与核对

```bash
dv diff v3 HEAD                     # 先看 v3 和当前差了什么
dv rollback v3 -m "线上用 v3，回滚"
dv pull                             # 拿到回滚后的文件
```

#### 4.5 删除数据集

```bash
dv dataset delete cv/coco            # 会先显示：版本数/占用/共享 blob，再二次确认
```

#### 4.6 用 Docker Compose 起完整环境（Postgres + MinIO + 后端）

```bash
# 先构建前端（把 web/dist 打进镜像）
cd web && npm install && npm run build && cd ..
docker compose up -d --build
# Web/API: http://localhost:8000    MinIO 控制台: http://localhost:9001
```

---

### 5. 存储后端：本地盘 ↔ S3 兼容对象存储

默认 `DV_STORAGE_BACKEND=local`（本地盘模拟对象存储，预签名 URL 为 HMAC 签名 API URL）。
切换 S3 兼容对象存储（MinIO / 阿里云 OSS / 腾讯云 COS / AWS S3）：

```bash
DV_STORAGE_BACKEND=s3 \
DV_S3_ENDPOINT=http://localhost:9000 \
DV_S3_BUCKET=datasets \
DV_S3_ACCESS_KEY=... \
DV_S3_SECRET_KEY=... \
dv-server run
```

或者写入配置：

```bash
dv-server config set DV_STORAGE_BACKEND=s3 DV_S3_ENDPOINT=http://localhost:9000 \
  DV_S3_BUCKET=datasets DV_S3_ACCESS_KEY=xxx DV_S3_SECRET_KEY=yyy
dv-server restart
```

CLI 与 Web 代码路径完全一致，切换后端后客户端无需任何改动。

---

### 6. Web UI 使用说明

服务启动后访问 `http://localhost:8000`（需先 `npm run build` 生成 `web/dist`，或设置 `DV_WEB_DIST`）。

- **首页**：渐变 Hero 搜索区 + 数据集卡片网格（图标、描述、版本/文件/大小、可见性徽标）；
- **新建数据集**：右上角入口，填 namespace/名称/可见性；
- **详情页**：头部大图标 + 统计条 + **复制下载命令**卡片 + 删除入口（owner 可见）；
- **数据集介绍**：自动渲染数据集内的 `README.md`（GitHub 风格 Markdown、相对图片转预签名 URL、支持 HTML），无 README 时显示引导空态；
- **文件**：左侧目录树 + 文件表 + 单文件下载；
- **版本历史 / 标签 / 分支 / 版本差异**：各占一个标签页，diff 展示文件级增删改；
- **下载全部（ZIP）**：弹窗实时进度，完成后打包为 `<数据集名>.zip`；
- **登录 / 注册**：登录页有「立即注册」入口，第一个注册用户自动成为管理员；
- **Token 管理**：导航栏创建 Token（名称 + 过期时间：永不过期 / 7 / 30 / 90 / 365 天）、列表、吊销；明文只在创建弹窗显示一次。

UI 冒烟测试脚本：`scripts/ui_check*.py`（Playwright），截图输出到 `.shots/`。

---

### 7. 开发环境与测试

#### 后端

```bash
cd backend
..\.venv\Scripts\python -m uvicorn app.main:app --port 8000
```

首次启动自动建库。访问：
- Web UI: http://localhost:8000
- API 文档: http://localhost:8000/docs
- 健康检查: http://localhost:8000/api/v1/health

默认管理员由 `POST /api/v1/auth/bootstrap` 创建（用户名 `admin`，密码来自 `DV_FIRST_ADMIN_PASSWORD`，默认 `admin123`）；也可以注册新用户（第一个注册用户为 admin）。

#### 演示数据（可选）

```bash
.venv\Scripts\python scripts\demo_seed.py
```

#### 测试

```bash
.venv\Scripts\python -m pytest backend/tests -q
```

覆盖：认证/Token、数据集 CRUD、上传去重、提交/标签/diff/回滚、下载校验、RBAC（非 owner 删除返回 403）、跨数据集共享 blob 的引用计数与删除 GC、物理对象释放。

---

### 8. API 一览（节选）

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/v1/auth/login · register · bootstrap | 认证 |
| POST/GET/DELETE | /api/v1/tokens | API Token 管理 |
| POST | /api/v1/datasets | 创建数据集 |
| GET | /api/v1/datasets | 数据集列表（搜索/分页） |
| GET | /api/v1/datasets/{id} | 数据集详情 |
| **DELETE** | **/api/v1/datasets/{id}** | **删除数据集：元数据 + 引用计数归零对象的物理删除，返回释放字节** |
| GET | /api/v1/datasets/{id}/storage-info | 删除前影响范围（版本数/占用/共享 blob） |
| POST | /api/v1/datasets/{id}/presign/upload | 上传意向：哈希清单 → 仅返回缺失 blob 的预签名 URL（去重） |
| POST | /api/v1/datasets/{id}/commits | 创建版本（校验声明哈希均已存在） |
| GET | /api/v1/datasets/{id}/commits | 版本历史 |
| GET | /api/v1/datasets/{id}/versions/{ref}/manifest | 版本文件清单 |
| GET | /api/v1/datasets/{id}/versions/{ref}/presign/download | 版本下载预签名 URL 列表 |
| GET | /api/v1/datasets/{id}/versions/{ref}/download-command | 下载命令（Web 展示用） |
| GET | /api/v1/datasets/{id}/tree/{ref} | 目录树浏览 |
| GET | /api/v1/datasets/{id}/diff?base=&head= | 版本差异 |
| POST | /api/v1/datasets/{id}/rollback | 回滚（append-only 新提交） |
| POST/GET/DELETE | /api/v1/datasets/{id}/tags · branches | 标签 / 分支 |
| GET | /api/v1/datasets/{id}/stats | 存储统计 |
| GET | /api/v1/audit/logs | 审计日志（admin） |

`ref` 支持：tag 名、分支名、`HEAD`/`latest`、`vN` 序号、commit 哈希（前缀）。

---

### 9. 并发与性能提示

- 上传/下载走预签名 URL：S3 后端直连对象存储，完全不经过应用进程；
- 本地后端 PUT/GET 为**流式收发**：上传边收边写临时文件并校验 sha256 后原子改名，下载流式返回，大文件不整体载入内存；
- SQLite（开发默认）开启 WAL + `busy_timeout=30000`，事务以 `BEGIN IMMEDIATE` 开始：多客户端同时上传相同 blob（去重竞态）或同时 push 不会出现 "database is locked" / 重复版本号 / 丢更新；
- 同一台机器多客户端并行传输建议 `--workers 1`；要横向扩容请切 PostgreSQL + S3 后加大 workers。

---

## 📚 更多

- **产品简介**：见本文件开头；
- **Web UI**：服务启动后访问 `http://localhost:8000`；
- **API 文档**：服务启动后访问 `http://localhost:8000/docs`（Swagger UI）。
