From 102e00f323969395e32af1baf2843826e0ae096a Mon Sep 17 00:00:00 2001 From: jlightner Date: Sat, 4 Apr 2026 13:13:05 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Added=20onboarding=5Fcompleted=20flag?= =?UTF-8?q?=20to=20User=20model,=20UserResponse=20schem=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - "backend/models.py" - "backend/schemas.py" - "backend/routers/auth.py" - "alembic/versions/030_add_onboarding_completed.py" GSD-Task: S03/T01 --- .../versions/030_add_onboarding_completed.py | 31 +++++++++++++++++++ backend/models.py | 3 ++ backend/routers/auth.py | 16 ++++++++++ backend/schemas.py | 1 + 4 files changed, 51 insertions(+) create mode 100644 alembic/versions/030_add_onboarding_completed.py diff --git a/alembic/versions/030_add_onboarding_completed.py b/alembic/versions/030_add_onboarding_completed.py new file mode 100644 index 0000000..96f7eb4 --- /dev/null +++ b/alembic/versions/030_add_onboarding_completed.py @@ -0,0 +1,31 @@ +"""add_onboarding_completed + +Revision ID: 030_onboarding +Revises: 029 +Create Date: 2026-04-04 +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers +revision = "030_onboarding" +down_revision = "029_add_email_digest" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column( + "users", + sa.Column( + "onboarding_completed", + sa.Boolean(), + server_default="false", + nullable=False, + ), + ) + + +def downgrade() -> None: + op.drop_column("users", "onboarding_completed") diff --git a/backend/models.py b/backend/models.py index 4c6ffc1..4fbd236 100644 --- a/backend/models.py +++ b/backend/models.py @@ -169,6 +169,9 @@ class User(Base): is_active: Mapped[bool] = mapped_column( Boolean, default=True, server_default="true" ) + onboarding_completed: Mapped[bool] = mapped_column( + Boolean, default=False, server_default="false" + ) notification_preferences: Mapped[dict] = mapped_column( JSONB, nullable=False, server_default='{"email_digests": true, "digest_frequency": "daily"}', diff --git a/backend/routers/auth.py b/backend/routers/auth.py index 7380bc7..5727d9d 100644 --- a/backend/routers/auth.py +++ b/backend/routers/auth.py @@ -171,3 +171,19 @@ async def seed_invite_codes(session: AsyncSession) -> None: )) await session.commit() logger.info("Seeded default invite code: CHRYSOPEDIA-ALPHA-2026") + + +# ── Onboarding ─────────────────────────────────────────────────────────────── + + +@router.post("/onboarding-complete", response_model=UserResponse) +async def complete_onboarding( + current_user: Annotated[User, Depends(get_current_user)], + session: Annotated[AsyncSession, Depends(get_session)], +): + """Mark the current user's onboarding as completed.""" + current_user.onboarding_completed = True + await session.commit() + await session.refresh(current_user) + logger.info("Onboarding completed: %s", current_user.id) + return UserResponse.model_validate(current_user) diff --git a/backend/schemas.py b/backend/schemas.py index b4a57e2..96fd908 100644 --- a/backend/schemas.py +++ b/backend/schemas.py @@ -568,6 +568,7 @@ class UserResponse(BaseModel): role: str creator_id: uuid.UUID | None = None is_active: bool = True + onboarding_completed: bool = False created_at: datetime impersonating: bool = False