Files
SnapOtter/apps/docs/zh-CN/guide/database.md
T
SnapOtterandGitHub 4963ab3bbd feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
2026-07-11 13:52:47 +08:00

186 lines
6.4 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.
---
description: "SnapOtter 的 PostgreSQL 数据库架构、表、迁移和备份流程。"
i18n_source_hash: b37398ae91a3
i18n_provenance: human
i18n_output_hash: 3289d2d06514
---
# 数据库 {#database}
SnapOtter 使用 PostgreSQL 17 配合 [Drizzle ORM](https://orm.drizzle.team/)pg-core / node-postgres)进行数据持久化。架构定义在 `apps/api/src/db/schema.ts`
连接通过 `DATABASE_URL` 环境变量配置(默认为 `postgres://snapotter:snapotter@postgres:5432/snapotter`)。在 Docker Compose 中,Postgres 容器将其数据存储在名为 `SnapOtter-pgdata` 的卷中。
## 表 {#tables}
### users {#users}
存储用户账户。首次运行时会根据 `DEFAULT_USERNAME``DEFAULT_PASSWORD` 自动创建。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | uuid | 主键 |
| `username` | varchar | 唯一,必填 |
| `passwordHash` | varchar | scrypt 哈希 |
| `role` | varchar | `admin``editor``user` |
| `mustChangePassword` | boolean | 强制重置密码标志 |
| `createdAt` | timestamp | 创建时间 |
| `updatedAt` | timestamp | 上次更新时间 |
### sessions {#sessions}
活动登录会话。每一行将一个会话令牌与一个用户关联。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | varchar | 主键(会话令牌) |
| `userId` | uuid | 指向 `users.id` 的外键 |
| `expiresAt` | timestamp | 过期时间 |
| `createdAt` | timestamp | 创建时间 |
### teams {#teams}
用于组织用户的分组。管理员可以将用户分配到团队。
| 列 | 类型 | 描述 |
|--------|------|-------------|
| `id` | uuid | 主键 |
| `name` | varchar(唯一,最多 50 个字符) | 团队名称 |
| `createdAt` | timestamp | 创建时间 |
### api_keys {#api-keys}
用于程序化访问的 API 密钥。原始密钥仅在创建时显示一次;仅存储其哈希。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | uuid | 主键 |
| `userId` | uuid | 指向 `users.id` 的外键 |
| `keyHash` | varchar | 密钥的 scrypt 哈希 |
| `name` | varchar | 用户提供的标签 |
| `createdAt` | timestamp | 创建时间 |
| `lastUsedAt` | timestamp | 每次经过身份验证的请求时更新 |
密钥以 `si_` 为前缀,后跟 96 个十六进制字符(48 个随机字节)。
### pipelines {#pipelines}
用户在 UI 中创建的已保存工具链。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | uuid | 主键 |
| `name` | varchar | 流水线名称 |
| `description` | varchar | 可选描述 |
| `steps` | jsonb | `{ toolId, settings }` 对象数组 |
| `createdAt` | timestamp | 创建时间 |
### user_files {#user-files}
带版本链跟踪的持久化文件库。每个保存结果的处理步骤都会创建一个新行,并通过 `parentId` 链接到其父行,从而形成一棵版本树。
| 列 | 类型 | 描述 |
|--------|------|-------------|
| `id` | uuid | 主键 |
| `userId` | uuid | 指向 users 的外键(CASCADE DELETE |
| `originalName` | varchar | 原始上传文件名 |
| `storedName` | varchar | 磁盘上的文件名 |
| `mimeType` | varchar | MIME 类型 |
| `size` | integer | 文件大小(字节) |
| `width` | integer | 图像宽度(像素) |
| `height` | integer | 图像高度(像素) |
| `version` | integer | 版本号(1 = 原始版本) |
| `parentId` | uuid 或 null | 指向 user_files 的外键(父版本) |
| `toolChain` | jsonb | 按顺序应用以生成此版本的工具 ID |
| `createdAt` | timestamp | 创建时间 |
### jobs {#jobs}
跟踪处理作业,用于进度报告和清理。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | uuid | 主键 |
| `type` | varchar | 工具或流水线标识符 |
| `status` | varchar | `queued``processing``completed``failed` |
| `progress` | real | 0.0-1.0 的分数 |
| `inputFiles` | jsonb | 输入文件路径数组 |
| `outputPath` | varchar | 结果文件的路径 |
| `settings` | jsonb | 所用的工具设置 |
| `error` | varchar | 失败时的错误消息 |
| `createdAt` | timestamp | 创建时间 |
| `completedAt` | timestamp | 完成时间 |
### settings {#settings}
用于存储全服务器范围设置的键值存储,管理员可从 UI 更改这些设置。
| 列 | 类型 | 备注 |
|---|---|---|
| `key` | varchar | 主键 |
| `value` | varchar | 设置值 |
| `updatedAt` | timestamp | 上次更新时间 |
### roles {#roles}
具有细粒度权限的自定义角色。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | uuid | 主键 |
| `name` | varchar | 唯一的角色名称 |
| `description` | varchar | 可选描述 |
| `permissions` | jsonb | 权限字符串数组 |
| `createdAt` | timestamp | 创建时间 |
### audit_log {#audit-log}
安全相关的操作日志。
| 列 | 类型 | 备注 |
|---|---|---|
| `id` | uuid | 主键 |
| `userId` | uuid | 指向 users 的外键 |
| `action` | varchar | 操作类型 |
| `details` | jsonb | 特定于操作的数据 |
| `createdAt` | timestamp | 操作时间 |
## 迁移 {#migrations}
Drizzle 负责处理架构迁移。迁移文件位于 `apps/api/drizzle/`。开发期间:
```bash
cd apps/api
npx drizzle-kit generate # generate a migration from schema changes
npx drizzle-kit migrate # apply pending migrations
```
在生产环境中,待处理的迁移会在启动时自动应用。
## 备份与恢复 {#backup-and-restore}
关系数据库位于 Postgres 容器的 `SnapOtter-pgdata` 卷中,而不是应用的 `/data` 卷中。
**方案 1pg_dump(推荐)**
```bash
# Dump the database while the stack is running
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
# Restore into a fresh database
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
```
**方案 2:卷快照**
```bash
# Stop the stack, then snapshot the pgdata volume
docker compose down
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
```
### 从 1.xSQLite)迁移 {#migrating-from-1-x-sqlite}
从 SnapOtter 1.x 升级有专门的指南:参见 [从 1.x 升级到 2.0](./upgrading)。简而言之,复用你现有的 `/data` 卷,2.0 会在首次启动时自动检测并导入 `/data/snapotter.db`(或设置 `SQLITE_MIGRATE_PATH` 明确指向它)。请先备份整个 `/data` 卷,而不仅仅是 `snapotter.db`1.x 使用 SQLite WAL 模式,因此一个已停止的容器往往会把大部分数据留在 `snapotter.db-wal` 中,旁边则是一个几乎为空的 `snapotter.db`