@@ -0,0 +1,161 @@
""" create core tables: tenants users companies reports health_scores risks audit_logs
Revision ID: 278c8cfa6042
Revises:
Create Date: 2026-07-18 21:49:38.409216
"""
from typing import Sequence , Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy . dialects import postgresql
# revision identifiers, used by Alembic.
revision : str = ' 278c8cfa6042 '
down_revision : Union [ str , Sequence [ str ] , None ] = None
branch_labels : Union [ str , Sequence [ str ] , None ] = None
depends_on : Union [ str , Sequence [ str ] , None ] = None
def upgrade ( ) - > None :
""" Upgrade schema. """
# ### commands auto generated by Alembic - please adjust! ###
op . create_table ( ' tenants ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' name ' , sa . String ( length = 200 ) , nullable = False , comment = ' 租户名称 ' ) ,
sa . Column ( ' type ' , sa . String ( length = 50 ) , nullable = False , comment = ' 租户类型:vc/cvc/gov/holdings ' ) ,
sa . Column ( ' config_json ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 租户配置 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_table ( ' companies ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' tenant_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' name ' , sa . String ( length = 200 ) , nullable = False , comment = ' 企业名称 ' ) ,
sa . Column ( ' industry ' , sa . String ( length = 100 ) , nullable = True , comment = ' 行业 ' ) ,
sa . Column ( ' stage ' , sa . String ( length = 50 ) , nullable = True , comment = ' 融资阶段:seed/a/b/c/ipo ' ) ,
sa . Column ( ' logo_url ' , sa . String ( length = 500 ) , nullable = True ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True , comment = ' 业务描述 ' ) ,
sa . Column ( ' founded_at ' , sa . DateTime ( timezone = True ) , nullable = True ) ,
sa . Column ( ' total_funding ' , sa . String ( length = 50 ) , nullable = True , comment = ' 累计融资额 ' ) ,
sa . Column ( ' website ' , sa . String ( length = 500 ) , nullable = True ) ,
sa . Column ( ' extra_json ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 扩展字段 ' ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . ForeignKeyConstraint ( [ ' tenant_id ' ] , [ ' tenants.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_index ( op . f ( ' ix_companies_tenant_id ' ) , ' companies ' , [ ' tenant_id ' ] , unique = False )
op . create_table ( ' users ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' tenant_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' email ' , sa . String ( length = 255 ) , nullable = False ) ,
sa . Column ( ' password_hash ' , sa . String ( length = 255 ) , nullable = False ) ,
sa . Column ( ' name ' , sa . String ( length = 100 ) , nullable = False ) ,
sa . Column ( ' role ' , sa . String ( length = 50 ) , nullable = False , comment = ' 角色:gp/partner/post_invest_lead/investor/founder/admin ' ) ,
sa . Column ( ' phone ' , sa . String ( length = 20 ) , nullable = True ) ,
sa . Column ( ' is_active ' , sa . Boolean ( ) , nullable = False ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . ForeignKeyConstraint ( [ ' tenant_id ' ] , [ ' tenants.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_index ( op . f ( ' ix_users_email ' ) , ' users ' , [ ' email ' ] , unique = True )
op . create_index ( op . f ( ' ix_users_tenant_id ' ) , ' users ' , [ ' tenant_id ' ] , unique = False )
op . create_table ( ' audit_logs ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' tenant_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' user_id ' , sa . String ( length = 36 ) , nullable = True ) ,
sa . Column ( ' action ' , sa . String ( length = 100 ) , nullable = False , comment = ' 操作类型:login/view/create/update/delete/export/ai_call ' ) ,
sa . Column ( ' resource_type ' , sa . String ( length = 50 ) , nullable = True , comment = ' 资源类型 ' ) ,
sa . Column ( ' resource_id ' , sa . String ( length = 36 ) , nullable = True , comment = ' 资源 ID ' ) ,
sa . Column ( ' detail_json ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 操作详情 ' ) ,
sa . Column ( ' ip ' , postgresql . INET ( ) , nullable = True ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . ForeignKeyConstraint ( [ ' tenant_id ' ] , [ ' tenants.id ' ] , ) ,
sa . ForeignKeyConstraint ( [ ' user_id ' ] , [ ' users.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_index ( op . f ( ' ix_audit_logs_tenant_id ' ) , ' audit_logs ' , [ ' tenant_id ' ] , unique = False )
op . create_table ( ' health_scores ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' company_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' total_score ' , sa . Float ( ) , nullable = False , comment = ' 总分(0-100) ' ) ,
sa . Column ( ' financial_score ' , sa . Float ( ) , nullable = True , comment = ' 财务健康度 ' ) ,
sa . Column ( ' operational_score ' , sa . Float ( ) , nullable = True , comment = ' 经营健康度 ' ) ,
sa . Column ( ' ai_commercial_score ' , sa . Float ( ) , nullable = True , comment = ' AI+ 商业化健康度 ' ) ,
sa . Column ( ' ai_cost_score ' , sa . Float ( ) , nullable = True , comment = ' AI+ 成本健康度 ' ) ,
sa . Column ( ' trend ' , sa . String ( length = 20 ) , nullable = True , comment = ' 趋势:up/stable/down ' ) ,
sa . Column ( ' evidence_json ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 评分依据 ' ) ,
sa . Column ( ' recommendations_json ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 建议动作 ' ) ,
sa . Column ( ' calculated_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . ForeignKeyConstraint ( [ ' company_id ' ] , [ ' companies.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_index ( op . f ( ' ix_health_scores_company_id ' ) , ' health_scores ' , [ ' company_id ' ] , unique = False )
op . create_table ( ' monthly_reports ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' company_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' period_year ' , sa . Integer ( ) , nullable = False , comment = ' 报告年份 ' ) ,
sa . Column ( ' period_month ' , sa . Integer ( ) , nullable = False , comment = ' 报告月份(1-12) ' ) ,
sa . Column ( ' status ' , sa . String ( length = 50 ) , nullable = False , comment = ' 状态:draft/submitted/ai_parsed/reviewed ' ) ,
sa . Column ( ' raw_content ' , sa . Text ( ) , nullable = True , comment = ' 原始内容 ' ) ,
sa . Column ( ' structured_data ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 结构化指标数据 ' ) ,
sa . Column ( ' ai_summary ' , sa . Text ( ) , nullable = True , comment = ' AI 生成的摘要 ' ) ,
sa . Column ( ' ai_concerns ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' AI 关注点列表 ' ) ,
sa . Column ( ' submitted_by ' , sa . String ( length = 36 ) , nullable = True ) ,
sa . Column ( ' submitted_at ' , sa . DateTime ( timezone = True ) , nullable = True ) ,
sa . Column ( ' reviewed_by ' , sa . String ( length = 36 ) , nullable = True ) ,
sa . Column ( ' reviewed_at ' , sa . DateTime ( timezone = True ) , nullable = True ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . ForeignKeyConstraint ( [ ' company_id ' ] , [ ' companies.id ' ] , ) ,
sa . ForeignKeyConstraint ( [ ' reviewed_by ' ] , [ ' users.id ' ] , ) ,
sa . ForeignKeyConstraint ( [ ' submitted_by ' ] , [ ' users.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_index ( op . f ( ' ix_monthly_reports_company_id ' ) , ' monthly_reports ' , [ ' company_id ' ] , unique = False )
op . create_table ( ' risk_events ' ,
sa . Column ( ' id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' company_id ' , sa . String ( length = 36 ) , nullable = False ) ,
sa . Column ( ' type ' , sa . String ( length = 50 ) , nullable = False , comment = ' 风险类型:financial/operational/org/ai_specific ' ) ,
sa . Column ( ' severity ' , sa . String ( length = 20 ) , nullable = False , comment = ' 严重程度:low/medium/high/critical ' ) ,
sa . Column ( ' status ' , sa . String ( length = 20 ) , nullable = False , comment = ' 状态:open/assigned/in_progress/resolved/closed ' ) ,
sa . Column ( ' title ' , sa . String ( length = 200 ) , nullable = False ) ,
sa . Column ( ' description ' , sa . Text ( ) , nullable = True ) ,
sa . Column ( ' evidence_json ' , postgresql . JSONB ( astext_type = sa . Text ( ) ) , nullable = True , comment = ' 证据链 ' ) ,
sa . Column ( ' suggested_action ' , sa . Text ( ) , nullable = True , comment = ' 建议动作 ' ) ,
sa . Column ( ' assigned_to ' , sa . String ( length = 36 ) , nullable = True ) ,
sa . Column ( ' due_at ' , sa . DateTime ( timezone = True ) , nullable = True ) ,
sa . Column ( ' identified_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . Column ( ' closed_at ' , sa . DateTime ( timezone = True ) , nullable = True ) ,
sa . Column ( ' created_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . Column ( ' updated_at ' , sa . DateTime ( timezone = True ) , nullable = False ) ,
sa . ForeignKeyConstraint ( [ ' assigned_to ' ] , [ ' users.id ' ] , ) ,
sa . ForeignKeyConstraint ( [ ' company_id ' ] , [ ' companies.id ' ] , ) ,
sa . PrimaryKeyConstraint ( ' id ' )
)
op . create_index ( op . f ( ' ix_risk_events_company_id ' ) , ' risk_events ' , [ ' company_id ' ] , unique = False )
# ### end Alembic commands ###
def downgrade ( ) - > None :
""" Downgrade schema. """
# ### commands auto generated by Alembic - please adjust! ###
op . drop_index ( op . f ( ' ix_risk_events_company_id ' ) , table_name = ' risk_events ' )
op . drop_table ( ' risk_events ' )
op . drop_index ( op . f ( ' ix_monthly_reports_company_id ' ) , table_name = ' monthly_reports ' )
op . drop_table ( ' monthly_reports ' )
op . drop_index ( op . f ( ' ix_health_scores_company_id ' ) , table_name = ' health_scores ' )
op . drop_table ( ' health_scores ' )
op . drop_index ( op . f ( ' ix_audit_logs_tenant_id ' ) , table_name = ' audit_logs ' )
op . drop_table ( ' audit_logs ' )
op . drop_index ( op . f ( ' ix_users_tenant_id ' ) , table_name = ' users ' )
op . drop_index ( op . f ( ' ix_users_email ' ) , table_name = ' users ' )
op . drop_table ( ' users ' )
op . drop_index ( op . f ( ' ix_companies_tenant_id ' ) , table_name = ' companies ' )
op . drop_table ( ' companies ' )
op . drop_table ( ' tenants ' )
# ### end Alembic commands ###