Initial commit: VoIdeaAI - voice-first AI idea assistant
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
"""v2.0: Add role system, feedback, tariffs, backlog category
|
||||
|
||||
Revision ID: 002
|
||||
Revises: 001
|
||||
Create Date: 2026-05-11
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
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:
|
||||
# ── users: add v2.0 role system ──
|
||||
op.add_column("users", sa.Column("role", sa.String(20),
|
||||
server_default=sa.text("'user'"), nullable=False, index=True))
|
||||
op.add_column("users", sa.Column("is_owner", sa.Boolean(),
|
||||
server_default=sa.text("false"), nullable=False))
|
||||
op.add_column("users", sa.Column("permissions", postgresql.JSONB,
|
||||
nullable=True))
|
||||
op.add_column("users", sa.Column("accepted_terms_at",
|
||||
sa.DateTime(timezone=True), nullable=True))
|
||||
op.add_column("users", sa.Column("accepted_terms_version",
|
||||
sa.String(20), nullable=True))
|
||||
|
||||
# ── agent_configs: add description ──
|
||||
op.add_column("agent_configs", sa.Column("description", sa.Text(),
|
||||
nullable=True, server_default=sa.text("''")))
|
||||
|
||||
# ── backlog_tasks: add category ──
|
||||
op.add_column("backlog_tasks", sa.Column("category", sa.String(50),
|
||||
server_default=sa.text("'general'"), nullable=False, index=True))
|
||||
|
||||
# ── feedback ──
|
||||
op.create_table(
|
||||
"feedback",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
|
||||
sa.Column("user_id", postgresql.UUID(as_uuid=True), nullable=True, index=True),
|
||||
sa.Column("text", sa.Text(), nullable=False),
|
||||
sa.Column("page_url", sa.String(512), nullable=True),
|
||||
sa.Column("status", sa.String(20), nullable=False,
|
||||
server_default=sa.text("'new'"), index=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True),
|
||||
server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True),
|
||||
server_default=sa.func.now()),
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"fk_feedback_user_id", "feedback", "users",
|
||||
["user_id"], ["id"], ondelete="SET NULL",
|
||||
)
|
||||
|
||||
# ── tariff_plans ──
|
||||
op.create_table(
|
||||
"tariff_plans",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
|
||||
sa.Column("name", sa.String(100), nullable=False),
|
||||
sa.Column("code", sa.String(50), unique=True, nullable=False, index=True),
|
||||
sa.Column("description", sa.Text(), nullable=True),
|
||||
sa.Column("price_monthly", sa.Numeric(10, 2), nullable=False,
|
||||
server_default=sa.text("0")),
|
||||
sa.Column("price_yearly", sa.Numeric(10, 2), nullable=True),
|
||||
sa.Column("features", postgresql.JSONB, nullable=True),
|
||||
sa.Column("is_active", sa.Boolean(), nullable=False,
|
||||
server_default=sa.text("true")),
|
||||
sa.Column("sort_order", sa.Integer(), nullable=False,
|
||||
server_default=sa.text("0")),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True),
|
||||
server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True),
|
||||
server_default=sa.func.now()),
|
||||
)
|
||||
|
||||
# ── user_subscriptions ──
|
||||
op.create_table(
|
||||
"user_subscriptions",
|
||||
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
|
||||
sa.Column("user_id", postgresql.UUID(as_uuid=True), unique=True,
|
||||
nullable=False, index=True),
|
||||
sa.Column("plan_id", postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column("status", sa.String(20), nullable=False,
|
||||
server_default=sa.text("'active'"), index=True),
|
||||
sa.Column("current_period_start", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("current_period_end", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("canceled_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True),
|
||||
server_default=sa.func.now()),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True),
|
||||
server_default=sa.func.now()),
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"fk_user_subscriptions_user_id", "user_subscriptions", "users",
|
||||
["user_id"], ["id"], ondelete="CASCADE",
|
||||
)
|
||||
op.create_foreign_key(
|
||||
"fk_user_subscriptions_plan_id", "user_subscriptions", "tariff_plans",
|
||||
["plan_id"], ["id"], ondelete="RESTRICT",
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_table("user_subscriptions")
|
||||
op.drop_table("tariff_plans")
|
||||
op.drop_table("feedback")
|
||||
op.drop_column("backlog_tasks", "category")
|
||||
op.drop_column("agent_configs", "description")
|
||||
op.drop_column("users", "accepted_terms_version")
|
||||
op.drop_column("users", "accepted_terms_at")
|
||||
op.drop_column("users", "permissions")
|
||||
op.drop_column("users", "is_owner")
|
||||
op.drop_column("users", "role")
|
||||
Reference in New Issue
Block a user