"""协作空间:成员、邀请、项目与评审 Revision ID: bd36c0a63816 Revises: b7f1a0032451 Create Date: 2026-09-12 09:31:43.277430 """ from collections.abc import Sequence import sqlalchemy as sa from sqlalchemy.dialects import postgresql from alembic import op # revision identifiers, used by Alembic. revision: str = 'bd36c0a63816' down_revision: str | Sequence[str] | None = 'b7f1a0032451' branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: """Upgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### op.create_table('follow', sa.Column('id', sa.String(), nullable=False), sa.Column('follower_domain_id', sa.String(), nullable=False), sa.Column('followee_domain_id', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.ForeignKeyConstraint(['followee_domain_id'], ['personal_domain.id'], name='fk_follow_followee_domain', ondelete='cascade'), sa.ForeignKeyConstraint(['follower_domain_id'], ['personal_domain.id'], name='fk_follow_follower_domain', ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_follow')) ) op.create_index(op.f('ix_follow_followee_domain_id'), 'follow', ['followee_domain_id'], unique=False) op.create_index(op.f('ix_follow_follower_domain_id'), 'follow', ['follower_domain_id'], unique=False) op.create_index('uq_follow_pair', 'follow', ['follower_domain_id', 'followee_domain_id'], unique=True) op.create_table('report', sa.Column('id', sa.String(), nullable=False), sa.Column('reporter_domain_id', sa.String(), nullable=False), sa.Column('target_type', sa.String(), nullable=False), sa.Column('target_id', sa.String(), nullable=False), sa.Column('reason', sa.String(), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("status IN ('pending', 'reviewed', 'actioned')", name=op.f('ck_report_status_values')), sa.CheckConstraint("target_type IN ('content', 'comment')", name=op.f('ck_report_target_type_values')), sa.ForeignKeyConstraint(['reporter_domain_id'], ['personal_domain.id'], name=op.f('fk_report_personal_domain'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_report')) ) op.create_index(op.f('ix_report_reporter_domain_id'), 'report', ['reporter_domain_id'], unique=False) op.create_table('workspace', sa.Column('id', sa.String(), nullable=False), sa.Column('name', sa.String(), nullable=False), sa.Column('owner_domain_id', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.ForeignKeyConstraint(['owner_domain_id'], ['personal_domain.id'], name=op.f('fk_workspace_personal_domain'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_workspace')) ) op.create_index(op.f('ix_workspace_owner_domain_id'), 'workspace', ['owner_domain_id'], unique=False) op.create_table('community_content', sa.Column('id', sa.String(), nullable=False), sa.Column('author_domain_id', sa.String(), nullable=False), sa.Column('kind', sa.String(), nullable=False), sa.Column('title', sa.String(), nullable=False), sa.Column('body', postgresql.JSONB(astext_type=sa.Text()), nullable=False), sa.Column('character_id', sa.String(), nullable=True), sa.Column('visibility', sa.String(), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("kind IN ('post', 'character_release')", name=op.f('ck_community_content_kind_values')), sa.CheckConstraint("status IN ('draft', 'submitted', 'published', 'limited', 'suspended', 'removed')", name=op.f('ck_community_content_status_values')), sa.CheckConstraint("visibility IN ('public', 'followers')", name=op.f('ck_community_content_visibility_values')), sa.ForeignKeyConstraint(['author_domain_id'], ['personal_domain.id'], name=op.f('fk_community_content_personal_domain'), ondelete='cascade'), sa.ForeignKeyConstraint(['character_id'], ['character.id'], name=op.f('fk_community_content_character'), ondelete='set null'), sa.PrimaryKeyConstraint('id', name=op.f('pk_community_content')) ) op.create_index(op.f('ix_community_content_author_domain_id'), 'community_content', ['author_domain_id'], unique=False) op.create_table('moderation_case', sa.Column('id', sa.String(), nullable=False), sa.Column('report_id', sa.String(), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('action_taken', sa.String(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("status IN ('pending', 'resolved')", name=op.f('ck_moderation_case_status_values')), sa.ForeignKeyConstraint(['report_id'], ['report.id'], name=op.f('fk_moderation_case_report'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_moderation_case')) ) op.create_index(op.f('ix_moderation_case_report_id'), 'moderation_case', ['report_id'], unique=False) op.create_table('project', sa.Column('id', sa.String(), nullable=False), sa.Column('workspace_id', sa.String(), nullable=False), sa.Column('name', sa.String(), nullable=False), sa.Column('kind', sa.String(), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('current_version_id', sa.String(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("status IN ('draft', 'published')", name=op.f('ck_project_status_values')), sa.ForeignKeyConstraint(['current_version_id'], ['project_version.id'], name=op.f('fk_project_project_version'), ondelete='set null', use_alter=True), sa.ForeignKeyConstraint(['workspace_id'], ['workspace.id'], name=op.f('fk_project_workspace'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_project')) ) op.create_index(op.f('ix_project_workspace_id'), 'project', ['workspace_id'], unique=False) op.create_table('workspace_invitation', sa.Column('id', sa.String(), nullable=False), sa.Column('workspace_id', sa.String(), nullable=False), sa.Column('invitee_domain_id', sa.String(), nullable=False), sa.Column('role', sa.String(), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("role IN ('editor', 'reviewer', 'viewer')", name=op.f('ck_workspace_invitation_role_values')), sa.CheckConstraint("status IN ('pending', 'accepted', 'declined', 'expired')", name=op.f('ck_workspace_invitation_status_values')), sa.ForeignKeyConstraint(['invitee_domain_id'], ['personal_domain.id'], name=op.f('fk_workspace_invitation_personal_domain'), ondelete='cascade'), sa.ForeignKeyConstraint(['workspace_id'], ['workspace.id'], name=op.f('fk_workspace_invitation_workspace'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_workspace_invitation')) ) op.create_index(op.f('ix_workspace_invitation_workspace_id'), 'workspace_invitation', ['workspace_id'], unique=False) op.create_table('workspace_member', sa.Column('id', sa.String(), nullable=False), sa.Column('workspace_id', sa.String(), nullable=False), sa.Column('member_domain_id', sa.String(), nullable=False), sa.Column('role', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("role IN ('owner', 'editor', 'reviewer', 'viewer')", name=op.f('ck_workspace_member_role_values')), sa.ForeignKeyConstraint(['member_domain_id'], ['personal_domain.id'], name=op.f('fk_workspace_member_personal_domain'), ondelete='cascade'), sa.ForeignKeyConstraint(['workspace_id'], ['workspace.id'], name=op.f('fk_workspace_member_workspace'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_workspace_member')) ) op.create_index(op.f('ix_workspace_member_workspace_id'), 'workspace_member', ['workspace_id'], unique=False) op.create_index('uq_workspace_member', 'workspace_member', ['workspace_id', 'member_domain_id'], unique=True) op.create_table('comment', sa.Column('id', sa.String(), nullable=False), sa.Column('content_id', sa.String(), nullable=False), sa.Column('author_domain_id', sa.String(), nullable=False), sa.Column('parent_comment_id', sa.String(), nullable=True), sa.Column('body', sa.String(), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("status IN ('visible', 'removed')", name=op.f('ck_comment_status_values')), sa.ForeignKeyConstraint(['author_domain_id'], ['personal_domain.id'], name=op.f('fk_comment_personal_domain'), ondelete='cascade'), sa.ForeignKeyConstraint(['content_id'], ['community_content.id'], name=op.f('fk_comment_community_content'), ondelete='cascade'), sa.ForeignKeyConstraint(['parent_comment_id'], ['comment.id'], name=op.f('fk_comment_comment'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_comment')) ) op.create_index(op.f('ix_comment_content_id'), 'comment', ['content_id'], unique=False) op.create_table('project_version', sa.Column('id', sa.String(), nullable=False), sa.Column('project_id', sa.String(), nullable=False), sa.Column('version', sa.Integer(), nullable=False), sa.Column('payload', postgresql.JSONB(astext_type=sa.Text()), nullable=False), sa.Column('status', sa.String(), nullable=False), sa.Column('submitted_by', sa.String(), nullable=True), sa.Column('reviewed_by', sa.String(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("status IN ('draft', 'submitted', 'approved', 'rejected')", name=op.f('ck_project_version_status_values')), sa.ForeignKeyConstraint(['project_id'], ['project.id'], name=op.f('fk_project_version_project'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_project_version')) ) op.create_index(op.f('ix_project_version_project_id'), 'project_version', ['project_id'], unique=False) op.create_index('uq_project_version_number', 'project_version', ['project_id', 'version'], unique=True) op.create_table('reaction', sa.Column('id', sa.String(), nullable=False), sa.Column('content_id', sa.String(), nullable=False), sa.Column('actor_domain_id', sa.String(), nullable=False), sa.Column('kind', sa.String(), nullable=False), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.CheckConstraint("kind IN ('like', 'save')", name=op.f('ck_reaction_kind_values')), sa.ForeignKeyConstraint(['actor_domain_id'], ['personal_domain.id'], name=op.f('fk_reaction_personal_domain'), ondelete='cascade'), sa.ForeignKeyConstraint(['content_id'], ['community_content.id'], name=op.f('fk_reaction_community_content'), ondelete='cascade'), sa.PrimaryKeyConstraint('id', name=op.f('pk_reaction')) ) op.create_index(op.f('ix_reaction_content_id'), 'reaction', ['content_id'], unique=False) op.create_index('uq_reaction_content_actor_kind', 'reaction', ['content_id', 'actor_domain_id', 'kind'], unique=True) # ### end Alembic commands ### def downgrade() -> None: """Downgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### op.drop_index('uq_reaction_content_actor_kind', table_name='reaction') op.drop_index(op.f('ix_reaction_content_id'), table_name='reaction') op.drop_table('reaction') op.drop_index('uq_project_version_number', table_name='project_version') op.drop_index(op.f('ix_project_version_project_id'), table_name='project_version') op.drop_table('project_version') op.drop_index(op.f('ix_comment_content_id'), table_name='comment') op.drop_table('comment') op.drop_index('uq_workspace_member', table_name='workspace_member') op.drop_index(op.f('ix_workspace_member_workspace_id'), table_name='workspace_member') op.drop_table('workspace_member') op.drop_index(op.f('ix_workspace_invitation_workspace_id'), table_name='workspace_invitation') op.drop_table('workspace_invitation') op.drop_index(op.f('ix_project_workspace_id'), table_name='project') op.drop_table('project') op.drop_index(op.f('ix_moderation_case_report_id'), table_name='moderation_case') op.drop_table('moderation_case') op.drop_index(op.f('ix_community_content_author_domain_id'), table_name='community_content') op.drop_table('community_content') op.drop_index(op.f('ix_workspace_owner_domain_id'), table_name='workspace') op.drop_table('workspace') op.drop_index(op.f('ix_report_reporter_domain_id'), table_name='report') op.drop_table('report') op.drop_index('uq_follow_pair', table_name='follow') op.drop_index(op.f('ix_follow_follower_domain_id'), table_name='follow') op.drop_index(op.f('ix_follow_followee_domain_id'), table_name='follow') op.drop_table('follow') # ### end Alembic commands ###