Skip to content

Persist quick-start onboarding state in the API#297

Open
DannyMac180 wants to merge 1 commit intomainfrom
dan-100-v2-persist-onboarding-state-across-devices-and-harden
Open

Persist quick-start onboarding state in the API#297
DannyMac180 wants to merge 1 commit intomainfrom
dan-100-v2-persist-onboarding-state-across-devices-and-harden

Conversation

@DannyMac180
Copy link
Copy Markdown
Owner

Summary

  • add server-persisted quick-start onboarding state on users.onboarding_state with a migration and normalized API payload helpers
  • expose backend-owned quick-start media config on /auth/me and /v1/me, and add PATCH /account/onboarding for authenticated state updates
  • cover the persisted contract with backend route tests, including the JSON-safe state write path discovered during runtime validation

Coordinated change

Test plan

  • source venv/bin/activate && pytest tests/test_account_routes.py -v
  • source venv/bin/activate && pytest tests/test_auth_routes.py -v
  • source venv/bin/activate && ruff check ace_platform/ tests/
  • source venv/bin/activate && ruff format ace_platform/ tests/
  • source venv/bin/activate && pytest tests/ -v
  • runtime proof via isolated local stack: PATCH /account/onboarding and GET /v1/me returned matching minimized state plus backend-owned embed config

Summary:
- add user onboarding JSONB state plus a migration and shared payload
  helpers for the authenticated quick-start contract
- expose backend-owned quick-start media config on `/auth/me` and
  `/v1/me`, and add `/account/onboarding` to persist state updates
- cover the new response shape and persisted state writes in backend
  route tests

Rationale:
- onboarding state has to live server-side to stay consistent across
  sessions and devices instead of depending on browser-local storage
- the embed target needs a backend-owned config path so the video can
  be changed without coupling every change to a dashboard redeploy
- normalizing and JSON-encoding the payload before storage preserves
  compatibility with legacy local state while avoiding JSONB datetime
  serialization failures

Tests:
- `source venv/bin/activate && pytest tests/test_account_routes.py -v`
- `source venv/bin/activate && pytest tests/test_auth_routes.py -v`
- `source venv/bin/activate && ruff check ace_platform/ tests/`
- `source venv/bin/activate && ruff format ace_platform/ tests/`
- `source venv/bin/activate && pytest tests/ -v`

Co-authored-by: Codex <codex@openai.com>
@DannyMac180 DannyMac180 added the symphony Symphony-managed pull requests label Mar 27, 2026
@DannyMac180
Copy link
Copy Markdown
Owner Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b27e3c934e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +76 to +78
if status == "dismissed":
normalized["status"] = "minimized"
normalized.setdefault("minimized_at", normalized.get("dismissed_at"))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove legacy dismissed_at before state validation

The legacy conversion path sets status from dismissed to minimized, but it keeps dismissed_at in the payload; because QuickStartOnboardingState has extra="forbid", validation then fails and the except path silently resets the user to the default active state. Any user record carrying legacy dismissed fields will lose its intended minimized state and see onboarding reopen.

Useful? React with 👍 / 👎.

Comment on lines +246 to +247
normalized_state = normalize_quick_start_state(body.model_dump(exclude_none=True))
current_user.onboarding_state = normalized_state.model_dump(mode="json", exclude_none=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve existing onboarding fields on PATCH updates

This PATCH handler replaces current_user.onboarding_state with a dump of only the request model, but the request model gives status a default of active; when a client sends a partial update (for example only last_seen_at, which the schema allows), the dump can overwrite prior minimized/completed state and drop stored timestamps. This causes unintended state regressions even though the endpoint is declared as a partial update.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

symphony Symphony-managed pull requests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant