Files
gen2d/docs/database.md
wonder 5100a52bca fix: 七牛云私有 bucket 下载 URL 签名支持
对私有读 bucket,通过 HMAC-SHA1 签名生成带 e(过期时间)和 token(下载凭证)
参数的临时下载 URL,前端获取的素材 URL 和下载接口均返回签名 URL。

新增配置项 GEN2D_QINIU_URL_EXPIRE,默认 3600 秒。
2026-05-25 19:05:55 +08:00

8.0 KiB
Executable File
Raw Permalink Blame History

数据存储

选型

用途 方案 说明
持久化存储 SQLite 3 工程、任务、素材元数据、风格配置全部落库,单文件部署
文件存储 七牛云对象存储 生成的图片与 spritesheet 文件上传到七牛云 Bucket,通过 CDN URL 访问
认证 JWT + Cookie 简单注册登录,httpOnly Cookie 鉴权
缓存 / 去重 应用层内存 请求去重通过应用层 sync.Map 实现短期去重窗口,无需外部依赖

选用 SQLite 的理由:gen2d 是单实例部署的工具型应用,SQLite 零配置、单文件、性能足够,无需额外数据库服务。


表结构

user — 用户

CREATE TABLE user (
    id            TEXT     NOT NULL PRIMARY KEY,  -- 用户 ID,如 user_a1B2c3
    username      TEXT     NOT NULL,
    email         TEXT     NOT NULL,
    password_hash TEXT     NOT NULL,              -- bcrypt 哈希
    created_at    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX uk_username ON user (username);
CREATE UNIQUE INDEX uk_email ON user (email);

project — 工程

CREATE TABLE project (
    id         TEXT     NOT NULL PRIMARY KEY,  -- 项目 ID,如 proj_abc123
    user_id    TEXT     NOT NULL,
    name       TEXT     NOT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
);
CREATE INDEX idx_project_user ON project (user_id, created_at);

project_style — 工程风格

工程级键值对,保证同一工程下所有素材风格一致。每个工程恰好一行。

CREATE TABLE project_style (
    id         TEXT     NOT NULL PRIMARY KEY,
    project_id TEXT     NOT NULL,
    kv_pairs   TEXT     NOT NULL,  -- JSON: {"artStyle":"pixel","palette":"warm",...}
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX uk_style_project ON project_style (project_id);

task — 生成任务

CREATE TABLE task (
    id           TEXT     NOT NULL PRIMARY KEY,  -- 任务 ID,如 task_xyz789
    project_id   TEXT     NOT NULL,
    prompt       TEXT     NOT NULL,              -- 用户原始文本
    asset_type   TEXT     NOT NULL,              -- sprite / background / ui / animation
    task_style   TEXT,                           -- JSON: 任务级风格覆盖,可为 NULL
    params       TEXT     NOT NULL DEFAULT '{}', -- JSON: {"resolution":64,"frames":{...},"format":"spritesheet"}
    status       TEXT     NOT NULL DEFAULT 'pending',  -- pending / running / completed / failed
    stage        TEXT,                           -- 当前管线阶段
    progress     INTEGER  NOT NULL DEFAULT 0,    -- 0-100
    retry_count  INTEGER  NOT NULL DEFAULT 0,
    error        TEXT,                           -- 失败原因
    created_at   DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at   DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE CASCADE
);
CREATE INDEX idx_task_project ON task (project_id, created_at);
CREATE INDEX idx_task_status ON task (status);

asset — 生成素材

CREATE TABLE asset (
    id          TEXT     NOT NULL PRIMARY KEY,  -- 素材 ID,如 asset_001
    task_id     TEXT     NOT NULL,
    url         TEXT     NOT NULL,              -- 相对路径,如 tasks/task_xyz/output/spritesheet.png
    format      TEXT     NOT NULL DEFAULT 'png', -- png / json
    width       INTEGER  NOT NULL DEFAULT 0,
    height      INTEGER  NOT NULL DEFAULT 0,
    metadata    TEXT,                           -- JSON: {"frameWidth":64,"frameHeight":64,"frameCount":4,"directions":1}
    created_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (task_id) REFERENCES task (id) ON DELETE CASCADE
);
CREATE INDEX idx_asset_task ON asset (task_id);

ER 关系

user    1 ── N project
project 1 ── 1 project_style
project 1 ── N task
task    1 ── N asset

对应 后端工程 中的关键实体定义,所有一对多关系通过外键 + CASCADE 删除维护。


ID 生成

使用前缀 + 随机字符串生成 ID,格式为 {prefix}_{random}:

实体 前缀 示例
user user user_a1B2c3
project proj proj_3kF9a2
project_style sty sty_7xM2pQ
task task task_9bN4vR
asset asset asset_2wK6tY

随机部分使用 crypto/rand 生成 6 字节 base62 编码,兼顾可读性与唯一性。


文件存储

生成的素材文件上传到七牛云对象存储,通过 CDN URL 访问。

存储结构

对象 Key 命名规则(与原有本地路径保持一致):

users/{userId}/projects/{projectId}/tasks/{taskId}/output/{filename}

示例:

users/user_a1B2c3/projects/proj_abc/tasks/task_xyz/output/spritesheet.png

访问方式

素材上传后 asset 表存储对象 Key 和基础 CDN URL。由于 bucket 为私有读,前端通过 API 获取的 url 字段为带签名参数的临时下载链接(有效期可配置,默认 3600 秒)。

格式:https://cdn.example.com/<key>?e=<deadline>&token=<downloadToken>

下载接口 GET /api/v1/assets/download?key=... 返回 302 重定向到带签名的临时 URL。

asset 表的 url 字段

存储七牛云基础 CDN URL(不含签名),如: https://cdn.example.com/users/user_a1B2c3/projects/proj_abc/tasks/task_xyz/output/spritesheet.png

注意:该字段仅在数据库中使用,API 返回给前端的 URL 会根据对象 Key 实时生成带签名的临时下载链接。


去重策略

相同 prompt + assetType + params 的并发请求,通过应用层去重避免重复生成:

  1. 请求到达时,计算 hash(prompt + assetType + params) 作为去重键。
  2. 应用内存(sync.Map)中查找该键:
    • 若存在且任务仍在运行中,直接返回已有 taskId。
    • 若不存在,写入内存并提交任务。
  3. 任务完成或失败后,从内存中清除(可设置 TTL 过期兜底)。

配置

数据库连接信息通过环境变量注入:

环境变量 默认值 说明
GEN2D_SERVER_PORT 8080 HTTP 服务监听端口
GEN2D_DB_PATH ./data/gen2d.db SQLite 数据库文件路径
GEN2D_JWT_SECRET — JWT 签名密钥(必填)
GEN2D_JWT_EXPIRE 7200 Token 过期时间(秒)
GEN2D_QINIU_ACCESS_KEY — 七牛云 AccessKey
GEN2D_QINIU_SECRET_KEY — 七牛云 SecretKey
GEN2D_QINIU_BUCKET — 七牛云 Bucket 名称
GEN2D_QINIU_CDN_HOST — CDN 域名(如 https://cdn.example.com)
GEN2D_QINIU_USE_HTTPS true 是否使用 HTTPS
GEN2D_QINIU_URL_EXPIRE 3600 私有下载签名 URL 有效期(秒)

在 config.go 中扩展字段即可,无需额外依赖。


迁移

应用启动时自动执行建表 SQL,保证 schema 与代码版本一致:

// 启动时执行
db.Exec(createUserTableSQL)
db.Exec(createProjectTableSQL)
db.Exec(createTaskTableSQL)
db.Exec(createAssetTableSQL)

使用 CREATE TABLE IF NOT EXISTS 保证幂等性。


索引说明

表 索引 用途
user uk_username (username) 用户名唯一约束
user uk_email (email) 邮箱唯一约束
project idx_project_user (user_id, created_at) 用户下工程列表分页查询
project_style uk_style_project (project_id) 一个工程一个风格,唯一约束
task idx_task_project (project_id, created_at) 工程下任务列表分页查询
task idx_task_status (status) 按状态筛选任务
asset idx_asset_task (task_id) 任务下素材列表查询