cc-dashboard/alembic/versions/0001_initial.py
Vadym Samoilenko 8edf31edff fix: simplify migration — let create_table handle user_role enum
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 13:06:22 +00:00

105 lines
5.1 KiB
Python

"""initial schema
Revision ID: 0001
Revises:
Create Date: 2026-03-26
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import JSONB, UUID
revision = "0001"
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"users",
sa.Column("id", UUID(as_uuid=False), primary_key=True),
sa.Column("email", sa.String(255), nullable=False, unique=True),
sa.Column("username", sa.String(100), nullable=False, unique=True),
sa.Column("password_hash", sa.String(255), nullable=False),
sa.Column("role", sa.Enum("admin", "user", name="user_role"), nullable=False, server_default="user"),
sa.Column("is_active", sa.Boolean, nullable=False, server_default="true"),
sa.Column("daily_overhead_hours", sa.Float, nullable=False, server_default="2.0"),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
)
op.create_index("ix_users_email", "users", ["email"])
op.create_table(
"api_keys",
sa.Column("id", UUID(as_uuid=False), primary_key=True),
sa.Column("user_id", UUID(as_uuid=False), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
sa.Column("key_hash", sa.String(255), nullable=False),
sa.Column("key_prefix", sa.String(12), nullable=False),
sa.Column("label", sa.String(100), server_default="My Machine"),
sa.Column("is_active", sa.Boolean, nullable=False, server_default="true"),
sa.Column("last_used_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
)
op.create_index("ix_api_keys_user_id", "api_keys", ["user_id"])
op.create_index("ix_api_keys_prefix", "api_keys", ["key_prefix"])
op.create_table(
"projects",
sa.Column("id", UUID(as_uuid=False), primary_key=True),
sa.Column("user_id", UUID(as_uuid=False), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
sa.Column("slug", sa.String(255), nullable=False),
sa.Column("display_name", sa.String(255), nullable=False),
sa.Column("root_path", sa.String(500), server_default=""),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
sa.UniqueConstraint("user_id", "slug", name="uq_project_user_slug"),
)
op.create_index("ix_projects_user_id", "projects", ["user_id"])
op.create_table(
"sessions",
sa.Column("id", UUID(as_uuid=False), primary_key=True),
sa.Column("user_id", UUID(as_uuid=False), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
sa.Column("project_id", UUID(as_uuid=False), sa.ForeignKey("projects.id", ondelete="CASCADE"), nullable=False),
sa.Column("session_id", sa.String(100), nullable=False),
sa.Column("date", sa.Date, nullable=False),
sa.Column("start_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("end_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("active_hours", sa.Float, server_default="0"),
sa.Column("message_count", sa.Integer, server_default="0"),
sa.Column("work_summary", sa.Text, server_default=""),
sa.Column("commits", JSONB, server_default="[]"),
sa.Column("tools_used", JSONB, server_default="{}"),
sa.Column("files_changed", JSONB, server_default="[]"),
sa.Column("raw_stats", JSONB, server_default="{}"),
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
sa.UniqueConstraint("user_id", "session_id", "date", name="uq_session_user_date"),
)
op.create_index("ix_sessions_user_id", "sessions", ["user_id"])
op.create_index("ix_sessions_project_id", "sessions", ["project_id"])
op.create_index("ix_sessions_date", "sessions", ["date"])
op.create_table(
"daily_stats",
sa.Column("id", UUID(as_uuid=False), primary_key=True),
sa.Column("user_id", UUID(as_uuid=False), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False),
sa.Column("project_id", UUID(as_uuid=False), sa.ForeignKey("projects.id", ondelete="CASCADE"), nullable=False),
sa.Column("date", sa.Date, nullable=False),
sa.Column("total_hours", sa.Float, server_default="0"),
sa.Column("session_count", sa.Integer, server_default="0"),
sa.Column("message_count", sa.Integer, server_default="0"),
sa.Column("commit_count", sa.Integer, server_default="0"),
sa.Column("files_changed_count", sa.Integer, server_default="0"),
sa.Column("top_tools", JSONB, server_default="{}"),
sa.UniqueConstraint("user_id", "project_id", "date", name="uq_daily_stat"),
)
op.create_index("ix_daily_stats_user_id", "daily_stats", ["user_id"])
op.create_index("ix_daily_stats_date", "daily_stats", ["date"])
op.create_index("ix_daily_stats_project_id", "daily_stats", ["project_id"])
def downgrade():
op.drop_table("daily_stats")
op.drop_table("sessions")
op.drop_table("projects")
op.drop_table("api_keys")
op.drop_table("users")
op.execute("DROP TYPE user_role")