feat: expand commercial ai drama platform

This commit is contained in:
xz
2026-08-31 21:09:48 +08:00
parent f06e583c9b
commit 8caf947b80
35 changed files with 10181 additions and 188 deletions
+286
View File
@@ -463,6 +463,70 @@ CREATE TABLE IF NOT EXISTS billing_account_events (
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS subscription_plan_templates (
id TEXT PRIMARY KEY,
tier_key TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
billing_cycle TEXT NOT NULL DEFAULT 'monthly' CHECK (billing_cycle IN ('monthly', 'quarterly', 'annual')),
currency TEXT NOT NULL DEFAULT 'CNY',
base_fee REAL NOT NULL DEFAULT 0,
seat_limit INTEGER NOT NULL DEFAULT 1,
storage_gb INTEGER NOT NULL DEFAULT 1,
monthly_clip_quota INTEGER NOT NULL DEFAULT 1,
limits_json TEXT NOT NULL DEFAULT '{}',
features_json TEXT NOT NULL DEFAULT '{}',
connector_policy_json TEXT NOT NULL DEFAULT '{}',
support_sla TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'archived')),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS organization_entitlements (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
entitlement_key TEXT NOT NULL,
label TEXT NOT NULL,
category TEXT NOT NULL DEFAULT 'general',
limit_value REAL NOT NULL DEFAULT 0,
unit TEXT NOT NULL DEFAULT '项',
enabled INTEGER NOT NULL DEFAULT 1,
enforcement TEXT NOT NULL DEFAULT 'block' CHECK (enforcement IN ('block', 'warn', 'off')),
source TEXT NOT NULL DEFAULT 'plan' CHECK (source IN ('plan', 'override')),
override_reason TEXT NOT NULL DEFAULT '',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE (organization_id, entitlement_key)
);
CREATE TABLE IF NOT EXISTS commercial_approval_requests (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT REFERENCES workspaces(id) ON DELETE SET NULL,
project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
request_type TEXT NOT NULL CHECK (request_type IN ('entitlement_overage', 'feature_enablement', 'budget_increase', 'external_connector', 'compliance_review', 'delivery_exception', 'storage_retention')),
title TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'submitted' CHECK (status IN ('submitted', 'approved', 'rejected', 'cancelled')),
priority TEXT NOT NULL DEFAULT 'medium' CHECK (priority IN ('low', 'medium', 'high', 'urgent')),
target_key TEXT NOT NULL DEFAULT '',
current_value REAL NOT NULL DEFAULT 0,
requested_value REAL NOT NULL DEFAULT 0,
unit TEXT NOT NULL DEFAULT '',
business_reason TEXT NOT NULL DEFAULT '',
risk_assessment_json TEXT NOT NULL DEFAULT '{}',
evidence_json TEXT NOT NULL DEFAULT '{}',
decision_note TEXT NOT NULL DEFAULT '',
effect_json TEXT NOT NULL DEFAULT '{}',
requester_user_id TEXT NOT NULL REFERENCES users(id),
reviewer_user_id TEXT REFERENCES users(id),
reviewed_at TEXT,
expires_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
-- Local invoice ledger. This is intentionally payment-provider agnostic: the
-- platform records billing snapshots and lifecycle state, while an external
-- accounting or payment system can be connected later through an adapter.
@@ -508,6 +572,11 @@ CREATE TABLE IF NOT EXISTS invoice_lines (
CREATE INDEX IF NOT EXISTS idx_organization_invoices_org_period ON organization_invoices(organization_id, period_end DESC, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_organization_invoices_org_status ON organization_invoices(organization_id, status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_invoice_lines_invoice_sort ON invoice_lines(invoice_id, sort_order, created_at);
CREATE INDEX IF NOT EXISTS idx_subscription_plan_templates_status ON subscription_plan_templates(status, tier_key);
CREATE INDEX IF NOT EXISTS idx_organization_entitlements_org_category ON organization_entitlements(organization_id, category, entitlement_key);
CREATE INDEX IF NOT EXISTS idx_commercial_approvals_org_status ON commercial_approval_requests(organization_id, status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_commercial_approvals_requester ON commercial_approval_requests(requester_user_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_commercial_approvals_target ON commercial_approval_requests(organization_id, request_type, target_key, status);
CREATE TABLE IF NOT EXISTS cost_centers (
id TEXT PRIMARY KEY,
@@ -573,6 +642,73 @@ CREATE TABLE IF NOT EXISTS model_connectors (
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS model_catalog_entries (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT REFERENCES workspaces(id) ON DELETE CASCADE,
connector_id TEXT REFERENCES model_connectors(id) ON DELETE SET NULL,
model_key TEXT NOT NULL,
display_name TEXT NOT NULL,
family TEXT NOT NULL DEFAULT '',
capabilities_json TEXT NOT NULL DEFAULT '[]',
context_window INTEGER NOT NULL DEFAULT 0,
max_output_tokens INTEGER NOT NULL DEFAULT 0,
cost_json TEXT NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'active',
approval_status TEXT NOT NULL DEFAULT 'approved',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE (organization_id, workspace_id, connector_id, model_key)
);
CREATE TABLE IF NOT EXISTS model_routing_policies (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT REFERENCES workspaces(id) ON DELETE CASCADE,
name TEXT NOT NULL,
workflow_key TEXT NOT NULL,
operation_key TEXT NOT NULL,
primary_model_id TEXT REFERENCES model_catalog_entries(id) ON DELETE SET NULL,
fallback_model_id TEXT REFERENCES model_catalog_entries(id) ON DELETE SET NULL,
policy_mode TEXT NOT NULL DEFAULT 'prefer-local',
approval_mode TEXT NOT NULL DEFAULT 'follow-model',
budget_limit_cny REAL NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active',
policy_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS model_route_approval_requests (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT REFERENCES workspaces(id) ON DELETE CASCADE,
project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
job_id TEXT REFERENCES generation_jobs(id) ON DELETE SET NULL,
route_id TEXT REFERENCES model_routing_policies(id) ON DELETE SET NULL,
model_entry_id TEXT REFERENCES model_catalog_entries(id) ON DELETE SET NULL,
connector_id TEXT REFERENCES model_connectors(id) ON DELETE SET NULL,
requester_user_id TEXT NOT NULL REFERENCES users(id),
reviewer_user_id TEXT REFERENCES users(id),
status TEXT NOT NULL DEFAULT 'submitted' CHECK (status IN ('submitted', 'approved', 'rejected', 'cancelled', 'expired')),
approval_scope TEXT NOT NULL DEFAULT 'single-run' CHECK (approval_scope IN ('single-run', 'single-job', 'route-window', 'connector-window')),
reason TEXT NOT NULL DEFAULT '',
decision_note TEXT NOT NULL DEFAULT '',
request_json TEXT NOT NULL DEFAULT '{}',
resolution_json TEXT NOT NULL DEFAULT '{}',
guard_json TEXT NOT NULL DEFAULT '{}',
estimated_cost_cny REAL NOT NULL DEFAULT 0,
local_only INTEGER NOT NULL DEFAULT 0,
expires_at TEXT,
reviewed_at TEXT,
consumed_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS series (
id TEXT PRIMARY KEY,
project_id TEXT NOT NULL UNIQUE REFERENCES projects(id) ON DELETE CASCADE,
@@ -622,12 +758,110 @@ CREATE TABLE IF NOT EXISTS script_documents (
content TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'draft',
analysis_json TEXT NOT NULL DEFAULT '{}',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE (project_id, version_number)
);
CREATE TABLE IF NOT EXISTS knowledge_documents (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
scope_mode TEXT NOT NULL DEFAULT 'workspace',
title TEXT NOT NULL,
source_type TEXT NOT NULL DEFAULT 'novel',
language TEXT NOT NULL DEFAULT 'zh-CN',
content TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'ingested',
rights_status TEXT NOT NULL DEFAULT 'needs-evidence',
summary TEXT NOT NULL DEFAULT '',
analysis_json TEXT NOT NULL DEFAULT '{}',
provenance_json TEXT NOT NULL DEFAULT '{}',
tags_json TEXT NOT NULL DEFAULT '[]',
risk_json TEXT NOT NULL DEFAULT '{}',
metadata_json TEXT NOT NULL DEFAULT '{}',
current_version_number INTEGER NOT NULL DEFAULT 1,
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS knowledge_chunks (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES knowledge_documents(id) ON DELETE CASCADE,
chunk_index INTEGER NOT NULL,
chunk_type TEXT NOT NULL DEFAULT 'scene',
heading TEXT NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '',
token_estimate INTEGER NOT NULL DEFAULT 0,
keywords_json TEXT NOT NULL DEFAULT '[]',
entities_json TEXT NOT NULL DEFAULT '{}',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
UNIQUE (document_id, chunk_index)
);
CREATE TABLE IF NOT EXISTS knowledge_document_versions (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES knowledge_documents(id) ON DELETE CASCADE,
version_number INTEGER NOT NULL,
title TEXT NOT NULL,
source_type TEXT NOT NULL DEFAULT 'novel',
language TEXT NOT NULL DEFAULT 'zh-CN',
content TEXT NOT NULL DEFAULT '',
summary TEXT NOT NULL DEFAULT '',
analysis_json TEXT NOT NULL DEFAULT '{}',
provenance_json TEXT NOT NULL DEFAULT '{}',
tags_json TEXT NOT NULL DEFAULT '[]',
risk_json TEXT NOT NULL DEFAULT '{}',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
UNIQUE (document_id, version_number)
);
CREATE TABLE IF NOT EXISTS knowledge_governance_reviews (
id TEXT PRIMARY KEY,
document_id TEXT NOT NULL REFERENCES knowledge_documents(id) ON DELETE CASCADE,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
decision TEXT NOT NULL DEFAULT 'submitted',
rights_status TEXT NOT NULL DEFAULT 'needs-evidence',
risk_status TEXT NOT NULL DEFAULT 'review',
notes TEXT NOT NULL DEFAULT '',
evidence_ref TEXT NOT NULL DEFAULT '',
provenance_json TEXT NOT NULL DEFAULT '{}',
risk_json TEXT NOT NULL DEFAULT '{}',
reviewer_user_id TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS knowledge_context_packs (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
project_id TEXT REFERENCES projects(id) ON DELETE CASCADE,
scope_mode TEXT NOT NULL DEFAULT 'workspace',
name TEXT NOT NULL,
query TEXT NOT NULL DEFAULT '',
source_type TEXT NOT NULL DEFAULT '',
max_tokens INTEGER NOT NULL DEFAULT 1600,
token_estimate INTEGER NOT NULL DEFAULT 0,
chunk_ids_json TEXT NOT NULL DEFAULT '[]',
citations_json TEXT NOT NULL DEFAULT '[]',
chunks_json TEXT NOT NULL DEFAULT '[]',
prompt_context TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'active',
metadata_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS assets (
id TEXT PRIMARY KEY,
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
@@ -650,12 +884,35 @@ CREATE TABLE IF NOT EXISTS asset_versions (
file_size INTEGER NOT NULL DEFAULT 0,
content_sha256 TEXT NOT NULL DEFAULT '',
rights_status TEXT NOT NULL DEFAULT 'needs-evidence',
provenance_json TEXT NOT NULL DEFAULT '{}',
risk_json TEXT NOT NULL DEFAULT '{}',
tags_json TEXT NOT NULL DEFAULT '[]',
license_scope TEXT NOT NULL DEFAULT '',
expires_at TEXT,
metadata_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
UNIQUE (asset_id, version_number)
);
CREATE TABLE IF NOT EXISTS asset_governance_reviews (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
asset_id TEXT NOT NULL REFERENCES assets(id) ON DELETE CASCADE,
version_id TEXT NOT NULL REFERENCES asset_versions(id) ON DELETE CASCADE,
reviewer_user_id TEXT NOT NULL REFERENCES users(id),
decision TEXT NOT NULL,
rights_status TEXT NOT NULL,
risk_status TEXT NOT NULL DEFAULT 'review',
notes TEXT NOT NULL DEFAULT '',
evidence_ref TEXT NOT NULL DEFAULT '',
provenance_json TEXT NOT NULL DEFAULT '{}',
risk_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS shots (
id TEXT PRIMARY KEY,
episode_id TEXT NOT NULL REFERENCES episodes(id) ON DELETE CASCADE,
@@ -728,6 +985,7 @@ CREATE TABLE IF NOT EXISTS generation_jobs (
result_json TEXT NOT NULL DEFAULT '{}',
error_message TEXT NOT NULL DEFAULT '',
max_attempts INTEGER NOT NULL DEFAULT 3,
model_route_approval_id TEXT REFERENCES model_route_approval_requests(id) ON DELETE SET NULL,
next_run_at TEXT,
leased_by TEXT,
leased_at TEXT,
@@ -897,6 +1155,23 @@ CREATE TABLE IF NOT EXISTS delivery_releases (
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS delivery_clearance_reports (
id TEXT PRIMARY KEY,
organization_id TEXT NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
delivery_id TEXT NOT NULL REFERENCES deliveries(id) ON DELETE CASCADE,
batch_id TEXT REFERENCES delivery_batches(id) ON DELETE SET NULL,
release_id TEXT REFERENCES delivery_releases(id) ON DELETE SET NULL,
status TEXT NOT NULL DEFAULT 'review' CHECK (status IN ('pass', 'review', 'blocked')),
blocker_count INTEGER NOT NULL DEFAULT 0,
review_count INTEGER NOT NULL DEFAULT 0,
certificate_path TEXT NOT NULL DEFAULT '',
report_json TEXT NOT NULL DEFAULT '{}',
created_by TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL
);
-- External delivery portals are scoped to one published release. The bearer
-- token is never stored in plaintext; only its SHA-256 digest is persisted.
CREATE TABLE IF NOT EXISTS delivery_access_links (
@@ -1190,11 +1465,20 @@ CREATE INDEX IF NOT EXISTS idx_org_members_user ON organization_members(user_id,
CREATE INDEX IF NOT EXISTS idx_workspace_members_user ON workspace_members(user_id, status);
CREATE INDEX IF NOT EXISTS idx_projects_workspace ON projects(workspace_id, status);
CREATE INDEX IF NOT EXISTS idx_script_documents_project ON script_documents(project_id, version_number DESC);
CREATE INDEX IF NOT EXISTS idx_knowledge_documents_scope ON knowledge_documents(organization_id, workspace_id, project_id, scope_mode, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_knowledge_chunks_document ON knowledge_chunks(document_id, chunk_index);
CREATE INDEX IF NOT EXISTS idx_knowledge_document_versions_document ON knowledge_document_versions(document_id, version_number DESC);
CREATE INDEX IF NOT EXISTS idx_knowledge_governance_reviews_document ON knowledge_governance_reviews(document_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_knowledge_context_packs_scope ON knowledge_context_packs(organization_id, workspace_id, project_id, status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_shot_versions_shot ON shot_versions(shot_id, version_number DESC);
CREATE INDEX IF NOT EXISTS idx_voice_lines_shot ON voice_lines(shot_id, line_number);
CREATE INDEX IF NOT EXISTS idx_project_members_user ON project_members(user_id, status);
CREATE INDEX IF NOT EXISTS idx_org_role_permissions_scope ON organization_role_permissions(organization_id, role_key, permission_key);
CREATE INDEX IF NOT EXISTS idx_model_catalog_entries_scope ON model_catalog_entries(organization_id, workspace_id, connector_id, status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_model_routing_policies_scope ON model_routing_policies(organization_id, workspace_id, workflow_key, operation_key, status, updated_at DESC);
CREATE INDEX IF NOT EXISTS idx_asset_bindings_shot ON asset_bindings(shot_id, usage_role);
CREATE INDEX IF NOT EXISTS idx_asset_governance_reviews_asset ON asset_governance_reviews(asset_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_asset_governance_reviews_scope ON asset_governance_reviews(organization_id, workspace_id, project_id, risk_status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_jobs_scope ON generation_jobs(organization_id, workspace_id, project_id, status);
CREATE INDEX IF NOT EXISTS idx_usage_scope ON usage_events(organization_id, workspace_id, project_id, created_at);
CREATE INDEX IF NOT EXISTS idx_audit_scope ON audit_logs(organization_id, workspace_id, project_id, created_at);
@@ -1220,6 +1504,8 @@ CREATE INDEX IF NOT EXISTS idx_delivery_batch_items_batch ON delivery_batch_item
CREATE INDEX IF NOT EXISTS idx_delivery_channels_scope ON delivery_channels(organization_id, workspace_id, project_id, enabled, created_at);
CREATE INDEX IF NOT EXISTS idx_delivery_releases_scope ON delivery_releases(organization_id, workspace_id, project_id, delivery_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_delivery_releases_idempotency ON delivery_releases(organization_id, project_id, idempotency_key);
CREATE INDEX IF NOT EXISTS idx_delivery_clearance_reports_scope ON delivery_clearance_reports(organization_id, workspace_id, project_id, delivery_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_delivery_clearance_reports_release ON delivery_clearance_reports(release_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_delivery_access_links_token ON delivery_access_links(token_hash, status, expires_at);
CREATE INDEX IF NOT EXISTS idx_delivery_access_links_scope ON delivery_access_links(organization_id, workspace_id, project_id, release_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_delivery_access_events_link ON delivery_access_events(link_id, created_at DESC);