Files
beige/backend/alembic/versions/002_multitenant_workspace.py
yangqianqian 6a2632da70 baseline: Clover 独立仓库首次基线提交
将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。
当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包),
M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:30:22 +08:00

72 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""002_multitenant_workspace
Revision ID: 002
Revises: 001
Create Date: 2026-06-09
Alembic 002: 多租户基础workspaces/workspace_members/user_api_keys
matrix_accounts 二期预留,一期不建。
user_api_keys 不存 url 字段token站固定自家站基石B
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
revision: str = "002"
down_revision: Union[str, None] = "001"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table(
"workspaces",
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
sa.Column("name", sa.String(128), nullable=False),
sa.Column("slug", sa.String(64), nullable=False),
sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"),
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("slug"),
)
op.create_table(
"workspace_members",
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
sa.Column("workspace_id", sa.BigInteger(), nullable=False),
sa.Column("user_id", sa.BigInteger(), nullable=False),
sa.Column("role", sa.Enum("admin", "supervisor", "operator", name="userrole"), nullable=False),
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
sa.ForeignKeyConstraint(["workspace_id"], ["workspaces.id"], ondelete="CASCADE"),
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("workspace_id", "user_id", name="uq_workspace_member"),
)
op.create_index("idx_workspace_members_workspace_id", "workspace_members", ["workspace_id"])
op.create_table(
"user_api_keys",
sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
sa.Column("user_id", sa.BigInteger(), nullable=False),
sa.Column("workspace_id", sa.BigInteger(), nullable=False),
sa.Column("provider", sa.String(32), nullable=False),
sa.Column("encrypted_key", sa.String(512), nullable=False),
sa.Column("key_last4", sa.String(4), nullable=False),
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
sa.ForeignKeyConstraint(["workspace_id"], ["workspaces.id"], ondelete="CASCADE"),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("user_id", "workspace_id", "provider", name="uq_user_workspace_provider"),
)
op.create_index("idx_user_api_keys_workspace_id", "user_api_keys", ["workspace_id"])
def downgrade() -> None:
op.drop_index("idx_user_api_keys_workspace_id", "user_api_keys")
op.drop_table("user_api_keys")
op.drop_index("idx_workspace_members_workspace_id", "workspace_members")
op.drop_table("workspace_members")
op.drop_table("workspaces")
op.execute("DROP TYPE IF EXISTS userrole")