Files
ai-gateway-go/migrations/000023_minio_file_objects.sql
T
superidou 6708c226a5 feat(m8): P1 MinIO 对象存储与文件管理
- 迁移 000023 gateway.file_objects(personal/system 归属隔离 + 部分索引)
- internal/platform/storage:minio-go 适配(端点 scheme 剥离、流式 PutObject/Open/Delete)
- internal/workbench/files.go:FileService(sha256 校验、PutObject-then-insert 回滚、delete 先删行再删对象)
- admin /api/v1/admin/files + portal /api/v1/portal/files 处理器(流式上传下载、Content-Disposition)
- RBAC file:read/file:manage;菜单加文件管理 + 门户文件仓库
- compose 增 minio 服务(S3_* anchor、不暴露端口);nginx client_max_body_size 32m→256m
- 管理端文件管理页 + 门户个人文件仓;集成测试 TestFileObjectLifecycle 连真 MinIO 通过
- healthz object_storage:true;README/PRODUCTION/进展文档同步

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-12 14:08:38 +08:00

33 lines
1.6 KiB
SQL

-- M8 基础设施:对象存储文件管理
-- 元数据行落 PostgreSQL,文件体存 MinIO(S3 兼容)。对象键即桶内路径,body 永不经数据库。
-- file_objects:文件元数据索引 + 访问控制
-- scope='personal' 绑定 portal 用户(个人文件仓);scope='system' 为平台文件(admin 文件管理)。
CREATE TABLE IF NOT EXISTS gateway.file_objects (
id uuid PRIMARY KEY,
object_key text NOT NULL UNIQUE,
original_name text NOT NULL CHECK (length(original_name) BETWEEN 1 AND 255),
content_type text NOT NULL DEFAULT 'application/octet-stream',
size_bytes bigint NOT NULL DEFAULT 0 CHECK (size_bytes BETWEEN 0 AND 536870912),
content_sha256 char(64) NOT NULL,
scope text NOT NULL CHECK (scope IN ('personal', 'system')),
owner_user_id uuid REFERENCES gateway.portal_users(id) ON DELETE CASCADE,
created_by uuid NOT NULL,
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
CONSTRAINT file_objects_personal_owner CHECK (
(scope = 'personal' AND owner_user_id IS NOT NULL)
OR (scope = 'system' AND owner_user_id IS NULL)
)
);
-- 部分索引:个人文件按用户倒序,系统文件按时间倒序,sha256 去重查找
CREATE INDEX IF NOT EXISTS file_objects_personal_idx
ON gateway.file_objects (owner_user_id, created_at DESC)
WHERE scope = 'personal';
CREATE INDEX IF NOT EXISTS file_objects_system_idx
ON gateway.file_objects (created_at DESC)
WHERE scope = 'system';
CREATE INDEX IF NOT EXISTS file_objects_sha256_idx
ON gateway.file_objects (content_sha256);