105 lines
5.1 KiB
Python
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")
|