Improve the UX and UI of the onboarding steps

This commit is contained in:
Urtzi Alfaro
2025-08-11 07:50:24 +02:00
parent c4d4aeb449
commit 652a850d0f
4 changed files with 703 additions and 408 deletions

View File

@@ -1,107 +0,0 @@
"""Initial onboarding progress tables
Revision ID: 001_initial_onboarding_tables
Revises:
Create Date: 2024-12-20 15:30:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = '001_initial_onboarding_tables'
down_revision = None # No previous migration
branch_labels = None
depends_on = None
def upgrade() -> None:
# Create users table first (if it doesn't exist)
op.create_table(
'users',
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('email', sa.String(length=255), nullable=False, unique=True, index=True),
sa.Column('hashed_password', sa.String(length=255), nullable=False),
sa.Column('full_name', sa.String(length=255), nullable=False),
sa.Column('is_active', sa.Boolean(), nullable=False, default=True),
sa.Column('is_verified', sa.Boolean(), nullable=False, default=False),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('last_login', sa.DateTime(timezone=True), nullable=True),
sa.Column('phone', sa.String(length=20), nullable=True),
sa.Column('language', sa.String(length=10), nullable=True, default='es'),
sa.Column('timezone', sa.String(length=50), nullable=True, default='Europe/Madrid'),
sa.Column('role', sa.String(length=20), nullable=False),
)
# Create refresh_tokens table
op.create_table(
'refresh_tokens',
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('token', sa.String(length=500), nullable=False, unique=True),
sa.Column('expires_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('is_revoked', sa.Boolean(), nullable=False, default=False),
sa.Column('revoked_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
# Foreign key to users table
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
)
# Create user_onboarding_progress table
op.create_table(
'user_onboarding_progress',
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False, index=True),
sa.Column('step_name', sa.String(length=50), nullable=False),
sa.Column('completed', sa.Boolean(), nullable=False, default=False),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('step_data', sa.JSON(), nullable=True, default=dict),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
# Foreign key to users table
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
# Unique constraint to prevent duplicate steps per user
sa.UniqueConstraint('user_id', 'step_name', name='uq_user_step'),
# Indexes for performance
sa.Index('ix_user_onboarding_progress_user_id', 'user_id'),
sa.Index('ix_user_onboarding_progress_step_name', 'step_name'),
sa.Index('ix_user_onboarding_progress_completed', 'completed'),
)
# Create user_onboarding_summary table
op.create_table(
'user_onboarding_summary',
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False, primary_key=True),
sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False, unique=True, index=True),
sa.Column('current_step', sa.String(length=50), nullable=False, default='user_registered'),
sa.Column('next_step', sa.String(length=50), nullable=True),
sa.Column('completion_percentage', sa.String(length=10), nullable=True, default='0.0'),
sa.Column('fully_completed', sa.Boolean(), nullable=False, default=False),
sa.Column('steps_completed_count', sa.String(length=10), nullable=True, default='0'),
sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
sa.Column('last_activity_at', sa.DateTime(timezone=True), nullable=False),
# Foreign key to users table
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
# Indexes for performance
sa.Index('ix_user_onboarding_summary_user_id', 'user_id'),
sa.Index('ix_user_onboarding_summary_current_step', 'current_step'),
sa.Index('ix_user_onboarding_summary_fully_completed', 'fully_completed'),
)
def downgrade() -> None:
# Drop tables in reverse order
op.drop_table('user_onboarding_summary')
op.drop_table('user_onboarding_progress')
op.drop_table('refresh_tokens')
op.drop_table('users')