Phase 8 Task 1: 多租户 SaaS 架构
- 创建 tenant_manager.py 多租户管理模块
- 租户管理(CRUD、slug、状态管理)
- 自定义域名绑定(DNS/文件验证)
- 品牌白标(Logo、主题色、自定义 CSS/JS)
- 成员管理(邀请、角色、权限)
- 资源使用统计和限制检查
- 租户上下文管理器
- 更新 schema.sql 添加租户相关表
- tenants, tenant_domains, tenant_branding
- tenant_members, tenant_permissions, tenant_usage
- 更新 main.py 添加租户 API 端点
- /api/v1/tenants/* 租户管理
- /api/v1/tenants/{id}/domains 域名管理
- /api/v1/tenants/{id}/branding 品牌配置
- /api/v1/tenants/{id}/members 成员管理
- /api/v1/tenants/{id}/usage 使用统计
- /api/v1/resolve-tenant 域名解析
- 创建 test_phase8_task1.py 测试脚本
This commit is contained in:
@@ -433,7 +433,106 @@ CREATE INDEX IF NOT EXISTS idx_webdav_syncs_project ON webdav_syncs(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chrome_tokens_project ON chrome_extension_tokens(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chrome_tokens_hash ON chrome_extension_tokens(token_hash);
|
||||
|
||||
-- ============================================
|
||||
-- Phase 7 Task 6: 高级搜索与发现
|
||||
-- ============================================
|
||||
|
||||
-- 搜索索引表
|
||||
CREATE TABLE IF NOT EXISTS search_indexes (
|
||||
id TEXT PRIMARY KEY,
|
||||
content_id TEXT NOT NULL,
|
||||
content_type TEXT NOT NULL, -- transcript, entity, relation
|
||||
project_id TEXT NOT NULL,
|
||||
tokens TEXT, -- JSON 数组
|
||||
token_positions TEXT, -- JSON 对象
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(content_id, content_type)
|
||||
);
|
||||
|
||||
-- 搜索词频统计表
|
||||
CREATE TABLE IF NOT EXISTS search_term_freq (
|
||||
term TEXT NOT NULL,
|
||||
content_id TEXT NOT NULL,
|
||||
content_type TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
frequency INTEGER DEFAULT 1,
|
||||
positions TEXT, -- JSON 数组
|
||||
PRIMARY KEY (term, content_id, content_type)
|
||||
);
|
||||
|
||||
-- 文本 Embedding 表
|
||||
CREATE TABLE IF NOT EXISTS embeddings (
|
||||
id TEXT PRIMARY KEY,
|
||||
content_id TEXT NOT NULL,
|
||||
content_type TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
embedding TEXT, -- JSON 数组
|
||||
model_name TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(content_id, content_type)
|
||||
);
|
||||
|
||||
-- 搜索相关索引
|
||||
CREATE INDEX IF NOT EXISTS idx_search_content ON search_indexes(content_id, content_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_search_project ON search_indexes(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_term_freq_term ON search_term_freq(term);
|
||||
CREATE INDEX IF NOT EXISTS idx_term_freq_project ON search_term_freq(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_embedding_content ON embeddings(content_id, content_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_embedding_project ON embeddings(project_id);
|
||||
|
||||
-- ============================================
|
||||
-- Phase 7 Task 8: 性能优化与扩展
|
||||
-- ============================================
|
||||
|
||||
-- 缓存统计表
|
||||
CREATE TABLE IF NOT EXISTS cache_stats (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
total_requests INTEGER DEFAULT 0,
|
||||
hits INTEGER DEFAULT 0,
|
||||
misses INTEGER DEFAULT 0,
|
||||
hit_rate REAL DEFAULT 0.0,
|
||||
memory_usage INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
-- 任务队列表
|
||||
CREATE TABLE IF NOT EXISTS task_queue (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_type TEXT NOT NULL,
|
||||
status TEXT DEFAULT 'pending', -- pending, running, success, failed, retrying, cancelled
|
||||
payload TEXT, -- JSON
|
||||
result TEXT, -- JSON
|
||||
error_message TEXT,
|
||||
retry_count INTEGER DEFAULT 0,
|
||||
max_retries INTEGER DEFAULT 3,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
started_at TIMESTAMP,
|
||||
completed_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- 性能指标表
|
||||
CREATE TABLE IF NOT EXISTS performance_metrics (
|
||||
id TEXT PRIMARY KEY,
|
||||
metric_type TEXT NOT NULL, -- api_response, db_query, cache_operation
|
||||
endpoint TEXT,
|
||||
duration_ms REAL,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
metadata TEXT -- JSON
|
||||
);
|
||||
|
||||
-- 性能相关索引
|
||||
CREATE INDEX IF NOT EXISTS idx_cache_stats_time ON cache_stats(timestamp);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_status ON task_queue(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_type ON task_queue(task_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_created ON task_queue(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_metrics_type ON performance_metrics(metric_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_metrics_endpoint ON performance_metrics(endpoint);
|
||||
CREATE INDEX IF NOT EXISTS idx_metrics_time ON performance_metrics(timestamp);
|
||||
|
||||
-- ============================================
|
||||
-- Phase 7: 插件与集成相关表
|
||||
-- ============================================
|
||||
|
||||
-- 插件表
|
||||
CREATE TABLE IF NOT EXISTS plugins (
|
||||
@@ -845,3 +944,241 @@ CREATE INDEX IF NOT EXISTS idx_metrics_endpoint ON performance_metrics(endpoint)
|
||||
CREATE INDEX IF NOT EXISTS idx_metrics_timestamp ON performance_metrics(timestamp);
|
||||
CREATE INDEX IF NOT EXISTS idx_shard_mappings_project ON shard_mappings(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_shard_mappings_shard ON shard_mappings(shard_id);
|
||||
|
||||
-- ============================================
|
||||
-- Phase 8 Task 1: 多租户 SaaS 架构
|
||||
-- ============================================
|
||||
|
||||
-- 租户主表
|
||||
CREATE TABLE IF NOT EXISTS tenants (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
tier TEXT DEFAULT 'free',
|
||||
status TEXT DEFAULT 'pending',
|
||||
owner_id TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
settings TEXT DEFAULT '{}',
|
||||
resource_limits TEXT DEFAULT '{}',
|
||||
metadata TEXT DEFAULT '{}'
|
||||
);
|
||||
|
||||
-- 租户域名表
|
||||
CREATE TABLE IF NOT EXISTS tenant_domains (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
domain TEXT UNIQUE NOT NULL,
|
||||
status TEXT DEFAULT 'pending',
|
||||
verification_token TEXT NOT NULL,
|
||||
verification_method TEXT DEFAULT 'dns',
|
||||
verified_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
is_primary INTEGER DEFAULT 0,
|
||||
ssl_enabled INTEGER DEFAULT 0,
|
||||
ssl_expires_at TIMESTAMP,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户品牌配置表
|
||||
CREATE TABLE IF NOT EXISTS tenant_branding (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT UNIQUE NOT NULL,
|
||||
logo_url TEXT,
|
||||
favicon_url TEXT,
|
||||
primary_color TEXT,
|
||||
secondary_color TEXT,
|
||||
custom_css TEXT,
|
||||
custom_js TEXT,
|
||||
login_page_bg TEXT,
|
||||
email_template TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户成员表
|
||||
CREATE TABLE IF NOT EXISTS tenant_members (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
user_id TEXT, -- NULL for pending invitations
|
||||
email TEXT NOT NULL,
|
||||
role TEXT DEFAULT 'member',
|
||||
permissions TEXT DEFAULT '[]',
|
||||
invited_by TEXT,
|
||||
invited_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
joined_at TIMESTAMP,
|
||||
last_active_at TIMESTAMP,
|
||||
status TEXT DEFAULT 'pending',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户权限定义表
|
||||
CREATE TABLE IF NOT EXISTS tenant_permissions (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
code TEXT NOT NULL,
|
||||
description TEXT,
|
||||
resource_type TEXT NOT NULL,
|
||||
actions TEXT NOT NULL,
|
||||
conditions TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
|
||||
UNIQUE(tenant_id, code)
|
||||
);
|
||||
|
||||
-- 租户资源使用统计表
|
||||
CREATE TABLE IF NOT EXISTS tenant_usage (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
date DATE NOT NULL,
|
||||
storage_bytes INTEGER DEFAULT 0,
|
||||
transcription_seconds INTEGER DEFAULT 0,
|
||||
api_calls INTEGER DEFAULT 0,
|
||||
projects_count INTEGER DEFAULT 0,
|
||||
entities_count INTEGER DEFAULT 0,
|
||||
members_count INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
|
||||
UNIQUE(tenant_id, date)
|
||||
);
|
||||
|
||||
-- 租户相关索引
|
||||
CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_tenants_owner ON tenants(owner_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_tenant ON tenant_domains(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_domain ON tenant_domains(domain);
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_status ON tenant_domains(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_tenant ON tenant_members(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_user ON tenant_members(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_tenant ON tenant_usage(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_usage_date ON tenant_usage(date);
|
||||
|
||||
-- ============================================
|
||||
-- Phase 8: Multi-Tenant SaaS Architecture
|
||||
-- ============================================
|
||||
|
||||
-- 租户主表
|
||||
CREATE TABLE IF NOT EXISTS tenants (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT UNIQUE NOT NULL, -- URL 友好的唯一标识
|
||||
description TEXT DEFAULT '',
|
||||
status TEXT DEFAULT 'active', -- active, suspended, trial, expired, pending
|
||||
plan TEXT DEFAULT 'free', -- free, starter, professional, enterprise
|
||||
max_projects INTEGER DEFAULT 5,
|
||||
max_members INTEGER DEFAULT 10,
|
||||
max_storage_gb REAL DEFAULT 1.0,
|
||||
max_api_calls_per_day INTEGER DEFAULT 1000,
|
||||
billing_email TEXT DEFAULT '',
|
||||
subscription_start TEXT,
|
||||
subscription_end TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by TEXT DEFAULT '', -- 创建者用户ID
|
||||
db_schema TEXT DEFAULT '', -- 数据库 schema 名称
|
||||
table_prefix TEXT DEFAULT '' -- 表前缀
|
||||
);
|
||||
|
||||
-- 租户域名绑定表
|
||||
CREATE TABLE IF NOT EXISTS tenant_domains (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
domain TEXT NOT NULL, -- 自定义域名
|
||||
status TEXT DEFAULT 'pending', -- pending, verified, active, failed, expired
|
||||
verification_record TEXT DEFAULT '', -- DNS TXT 记录值
|
||||
verification_expires_at TEXT,
|
||||
ssl_enabled INTEGER DEFAULT 0,
|
||||
ssl_cert_path TEXT,
|
||||
ssl_key_path TEXT,
|
||||
ssl_expires_at TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
verified_at TEXT,
|
||||
UNIQUE(tenant_id, domain),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户品牌配置表(白标)
|
||||
CREATE TABLE IF NOT EXISTS tenant_branding (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT UNIQUE NOT NULL,
|
||||
logo_url TEXT,
|
||||
logo_dark_url TEXT, -- 深色模式 Logo
|
||||
favicon_url TEXT,
|
||||
primary_color TEXT DEFAULT '#3B82F6',
|
||||
secondary_color TEXT DEFAULT '#10B981',
|
||||
accent_color TEXT DEFAULT '#F59E0B',
|
||||
background_color TEXT DEFAULT '#FFFFFF',
|
||||
text_color TEXT DEFAULT '#1F2937',
|
||||
dark_primary_color TEXT DEFAULT '#60A5FA',
|
||||
dark_background_color TEXT DEFAULT '#111827',
|
||||
dark_text_color TEXT DEFAULT '#F9FAFB',
|
||||
font_family TEXT DEFAULT 'Inter, system-ui, sans-serif',
|
||||
heading_font_family TEXT,
|
||||
custom_css TEXT DEFAULT '',
|
||||
custom_js TEXT DEFAULT '',
|
||||
app_name TEXT DEFAULT 'InsightFlow',
|
||||
login_page_title TEXT DEFAULT '登录到 InsightFlow',
|
||||
login_page_description TEXT DEFAULT '',
|
||||
footer_text TEXT DEFAULT '© 2024 InsightFlow',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户成员表
|
||||
CREATE TABLE IF NOT EXISTS tenant_members (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
name TEXT DEFAULT '',
|
||||
role TEXT DEFAULT 'viewer', -- owner, admin, editor, viewer, guest
|
||||
status TEXT DEFAULT 'invited', -- active, invited, suspended, removed
|
||||
invited_by TEXT,
|
||||
invited_at TEXT,
|
||||
invitation_token TEXT,
|
||||
invitation_expires_at TEXT,
|
||||
joined_at TEXT,
|
||||
last_active_at TEXT,
|
||||
custom_permissions TEXT DEFAULT '[]', -- JSON 数组
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(tenant_id, user_id),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户角色表
|
||||
CREATE TABLE IF NOT EXISTS tenant_roles (
|
||||
id TEXT PRIMARY KEY,
|
||||
tenant_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT DEFAULT '',
|
||||
permissions TEXT DEFAULT '[]', -- JSON 数组
|
||||
is_system INTEGER DEFAULT 0, -- 1=系统预设, 0=自定义
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 租户相关索引
|
||||
CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_tenant ON tenant_domains(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_domain ON tenant_domains(domain);
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_status ON tenant_domains(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_tenant ON tenant_members(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_user ON tenant_members(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_role ON tenant_members(role);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_status ON tenant_members(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_members_token ON tenant_members(invitation_token);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_tenant ON tenant_roles(tenant_id);
|
||||
|
||||
-- 更新项目表,添加租户关联(可选,支持租户隔离)
|
||||
ALTER TABLE projects ADD COLUMN tenant_id TEXT;
|
||||
CREATE INDEX IF NOT EXISTS idx_projects_tenant ON projects(tenant_id);
|
||||
|
||||
Reference in New Issue
Block a user