Files
resolutionflow/backend/alembic/versions/002_add_invite_codes.py
Michael Chihlas 20c4c40a1f Add invite code registration system for beta
Backend:
- Add InviteCode model with single-use codes
- Add invite API endpoints (create, list, revoke, validate)
- Modify registration to require invite code when enabled
- Add REQUIRE_INVITE_CODE config toggle (default: true)
- Add Alembic migration for invite_codes table

Frontend:
- Add invite code field to registration page
- Validate invite code on blur with visual feedback
- Pass invite code to registration API

Admins can generate invite codes via /api/docs (Swagger UI).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 00:08:06 -05:00

53 lines
1.7 KiB
Python

"""Add invite codes
Revision ID: 002
Revises: 7e00fa3c75c9
Create Date: 2026-02-01
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision: str = '002'
down_revision: Union[str, None] = '7e00fa3c75c9'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# Create invite_codes table
op.create_table(
'invite_codes',
sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True),
sa.Column('code', sa.String(16), nullable=False, unique=True, index=True),
sa.Column('created_by_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id'), nullable=False),
sa.Column('used_by_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id'), nullable=True),
sa.Column('expires_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('note', sa.String(255), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
sa.Column('used_at', sa.DateTime(timezone=True), nullable=True),
)
# Add invite_code_id FK to users table
op.add_column('users', sa.Column('invite_code_id', postgresql.UUID(as_uuid=True), nullable=True))
op.create_foreign_key(
'fk_users_invite_code_id',
'users',
'invite_codes',
['invite_code_id'],
['id']
)
def downgrade() -> None:
# Remove FK and column from users
op.drop_constraint('fk_users_invite_code_id', 'users', type_='foreignkey')
op.drop_column('users', 'invite_code_id')
# Drop invite_codes table
op.drop_table('invite_codes')