"""phase15 auth/multiuser: user_credential/auth_session/api_token/audit_log + user_id 백필(jiwoo) Revision ID: p15c3d4e5f6a7 Revises: p14b2c3d4e5f6 Create Date: 2026-06-15 08:00:00.000000 """ from typing import Sequence, Union import sqlalchemy as sa import sqlmodel from alembic import op revision: str = "p15c3d4e5f6a7" down_revision: Union[str, Sequence[str], None] = "p14b2c3d4e5f6" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None S = sqlmodel.sql.sqltypes.AutoString # 소유자 user_id 를 더할 기존 테이블(기본 "jiwoo" 백필 — 데모 무손상) _SCOPED = [ "task", "inbox_item", "approval", "email", "notification", "trip", "research_collection", ] def upgrade() -> None: # ── 신규 인증/감사 테이블 ── op.create_table( "user_credential", sa.Column("id", S(), nullable=False), sa.Column("user_id", S(), nullable=False), sa.Column("email", S(), nullable=False), sa.Column("password_hash", S(), nullable=False), sa.Column("is_active", sa.Boolean(), nullable=False), sa.Column("role", S(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False), sa.Column("last_login_at", sa.DateTime(), nullable=True), sa.ForeignKeyConstraint(["user_id"], ["person.id"]), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_user_credential_user_id", "user_credential", ["user_id"], unique=True) op.create_index("ix_user_credential_email", "user_credential", ["email"], unique=True) op.create_table( "auth_session", sa.Column("id", S(), nullable=False), sa.Column("user_id", S(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False), sa.Column("expires_at", sa.DateTime(), nullable=False), sa.Column("revoked", sa.Boolean(), nullable=False), sa.Column("user_agent", S(), nullable=True), sa.Column("ip", S(), nullable=True), sa.ForeignKeyConstraint(["user_id"], ["person.id"]), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_auth_session_user_id", "auth_session", ["user_id"]) op.create_table( "api_token", sa.Column("id", S(), nullable=False), sa.Column("user_id", S(), nullable=False), sa.Column("name", S(), nullable=False), sa.Column("token_hash", S(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False), sa.Column("last_used_at", sa.DateTime(), nullable=True), sa.Column("revoked", sa.Boolean(), nullable=False), sa.ForeignKeyConstraint(["user_id"], ["person.id"]), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_api_token_user_id", "api_token", ["user_id"]) op.create_table( "audit_log", sa.Column("id", S(), nullable=False), sa.Column("user_id", S(), nullable=True), sa.Column("action", S(), nullable=False), sa.Column("target", S(), nullable=True), sa.Column("ip", S(), nullable=True), sa.Column("detail", S(), nullable=True), sa.Column("created_at", sa.DateTime(), nullable=False), sa.ForeignKeyConstraint(["user_id"], ["person.id"]), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_audit_log_user_id", "audit_log", ["user_id"]) op.create_index("ix_audit_log_created_at", "audit_log", ["created_at"]) # ── 기존 테이블에 user_id 추가(백필 "jiwoo") + 인덱스 ── for tbl in _SCOPED: op.add_column( tbl, sa.Column("user_id", S(), nullable=False, server_default="jiwoo") ) op.create_index(f"ix_{tbl}_user_id", tbl, ["user_id"]) def downgrade() -> None: for tbl in reversed(_SCOPED): op.drop_index(f"ix_{tbl}_user_id", table_name=tbl) op.drop_column(tbl, "user_id") for t in ("audit_log", "api_token", "auth_session", "user_credential"): op.drop_table(t)