Skip to content

Activation checklist + MCP OAuth authorize UX (#239) - #250

Open
paulocastellano wants to merge 45 commits into
mainfrom
feature/onboarding-activation-checklist
Open

Activation checklist + MCP OAuth authorize UX (#239)#250
paulocastellano wants to merge 45 commits into
mainfrom
feature/onboarding-activation-checklist

Conversation

@paulocastellano

@paulocastellano paulocastellano commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Closes #239.

Intentional mixed scope — this PR ships the post-checkout activation checklist and the MCP OAuth authorize UX that landed on the same branch. Review surface is larger on purpose; treat both as in-scope.

Last split from #204. After Stripe, owners land on a single-page activation checklist (MCP → social → first post), with a residual sidebar banner until done, realtime progress, and owner-only completion/skip. Also includes MCP OAuth authorize UX (guest → login before invalid_client, Inertia error page for browser failures, prompt=none redirects preserved) plus small settings polish from QA.

Summary

Activation checklist

  • Account schema: onboarding_completed_at, onboarding_dismissed_at, onboarding_skipped_steps + backfill for accounts that already have app access (no residual banner for existing customers)
  • ResolveOnboardingStatus + OnboardingController (index / skip MCP / complete)
  • Checklist UI; MCP optional/skippable; social + first post required
  • Observers + OnboardingStatusUpdated Echo broadcasts (+ poll fallback)
  • Residual banner in the app sidebar linking back to /onboarding (owners only)
  • Sidebar progress shared via Inertia::defer for mid-activation owners (cheap negatives resolve inline)
  • /billing/processing redirects unfinished owners to /onboarding (members stay on processing)
  • Completion stamp is owner-only (HTTP skip/complete + syncProgress); teammates still unlock steps / analytics
  • MCP step requires a workspace-bound usable grant + createPost (aligned with Scope MCP OAuth tokens to user + workspace (#222) #245 — no current-workspace fallback)
  • onboarding.viewed captured once per account (deduped)

MCP OAuth authorize UX

  • Guests are sent to login before unknown-client rejection
  • Browser OAuth failures render Inertia AuthorizeError (JSON clients unchanged)
  • prompt=none still returns login_required / consent_required redirects (not Inertia)
  • SetLocale attaches cookies on raw Symfony OAuth responses
  • Shared AuthorizeLayout for consent + error pages

Settings polish (same branch)

  • Cancel invite dialog requires typing the invite email to confirm (same pattern as remove member)
  • MCP connected apps list styled like Active sessions

Out of scope

Test plan

  • Owner after checkout → processing → /onboarding when residual should show
  • Member on processing → redirectToOnboarding: false
  • Checklist steps / MCP skip / deferred residual share props
  • Existing app-access accounts backfilled as dismissed
  • Bound MCP unlocks step; unbound / viewer / unscoped grants do not
  • Teammate actions do not stamp account completion
  • Echo + observer broadcast paths; terminal states stop residual
  • OAuth: guest → login; browser invalid_client → Inertia; prompt=none redirects
  • Related Pest suites (onboarding, billing processing, OAuth)
  • Manual: skip MCP; mobile sidebar residual; social + first post completes
  • Manual: viewers/members do not see residual / are not forced through onboarding

paulocastellano and others added 14 commits August 6, 2026 22:09
…a data

Add onboarding casts/hasFinishedOnboarding, AccessToken ObservedBy,
Platform::connectableOptions, Post/SocialAccount onboarding broadcast hooks,
and lazy onboardingResidual share + SharedData types.
Wire billing processing and the sidebar checklist so owners land on
activation after subscribe, with locale sidebar/uk onboarding strings.
Unbound MCP tokens fall back to the user's current workspace and require
createPost so viewer/unscoped grants neither unlock the checklist nor
broadcast onboarding status.
Drop current-workspace fallback from usable MCP grants so checklist
detection and broadcasts match Passport token scoping; viewers still
cannot unlock the MCP step.

Co-authored-by: Cursor <cursoragent@cursor.com>
Fix Welcome/Persona/TrackPost suites broken by the activation route reuse
and PostObserver analytics side effects, restore Echo poll fallbacks,
reject unbound MCP grants in tests, and drop unused onboarding.mcp keys.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop dead sidebar menu/theme strings (including the overwritten
workspace label and api_keys nav entry) and unused MCP authorize
app_title/approving copy across all locales.

Co-authored-by: Cursor <cursoragent@cursor.com>
OAuth errors return a raw Symfony Response without withCookie(); attach
the default locale cookie via headers so authorize no longer 500s.

Co-authored-by: Cursor <cursoragent@cursor.com>
MCP Inspector often reuses a stale client_id; validateAuthorizationRequest
was returning invalid_client JSON before the login redirect. Guests now
hit /login first, then client validation runs after authentication.

Co-authored-by: Cursor <cursoragent@cursor.com>
After login, Inertia follows the intended authorize URL; raw invalid_client
JSON broke that visit. HTML/Inertia requests now get mcp/AuthorizeError
while API JSON clients still receive the OAuth error payload.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use the framework helper so post-login authorize failures keep returning
an Inertia page instead of raw OAuth JSON.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the X-Inertia header sniff; browser and Inertia visits already do
not expectsJson, while API clients still receive the OAuth JSON payload.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep authorize and authorize-error on the same centered card shell instead of the auth split layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use an exists-based MCP check, keep GETs read-only, move sync into
syncAndNotify, clear MCP skips on connect, restrict complete to owners,
and share Echo/poll via one composable.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the activation checklist focused; OAuth guest/error-page work now
lives on fix/mcp-oauth-authorize-ux.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@paulocastellano

Copy link
Copy Markdown
Contributor Author

Review follow-ups landed

  • Simplified MCP step detection (exists query), GETs are read-only, syncAndNotify owns observer sync, MCP skip clears on real connect, complete is owner-only.
  • Shared Echo/poll via useOnboardingLiveReload.
  • MCP OAuth authorize UX moved to Fix MCP OAuth authorize UX for browser/Inspector #251 so this PR stays focused on the activation checklist.

Keep authorize error page, guest login-before-client validation, and
SetLocale Symfony cookie fix in #250.

Co-authored-by: Cursor <cursoragent@cursor.com>
@paulocastellano

Copy link
Copy Markdown
Contributor Author

OAuth authorize UX is back on this PR (reverted the split to #251).

Keep login_required/consent_required as redirects instead of Inertia,
add regression coverage for owner-only activation, require invite email
confirmation, and align MCP connected apps with the sessions list UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
@paulocastellano
paulocastellano marked this pull request as ready for review August 7, 2026 12:54
@paulocastellano paulocastellano changed the title Onboarding: post-subscription activation checklist (#239) Onboarding activation checklist + MCP OAuth authorize UX (#239) Aug 7, 2026
paulocastellano and others added 8 commits August 7, 2026 10:20
Introduce isOnboardingOpen / belongsToAccount helpers, collapse
duplicated sync/dispatch paths, and capture onboarding.viewed once
per account.

Co-authored-by: Cursor <cursoragent@cursor.com>
Tighten Account onboarding predicates, drop nullable broadcast/dispatch
APIs, and collapse repeated observer/controller guards.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add resolveAccount(), tighten belongsToAccount to string ids, and fold
guest residual handling into ResolveOnboardingStatus.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Use accountOrFail, extract MCP onboarding scope, auto-leave the ready
screen, and send non-onboarding checkout back to accounts.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move account helpers off User, drop nullable sidebarProgress, and
read OAuth/onboarding payloads with data_get.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use Eloquent + policies for MCP/backfill paths, and move account
onboarding helpers into a dedicated trait.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover HasAccount and HasOnboarding under Models/Traits, prefer filled() for checkout session ids, and import Throwable instead of FQCN.

Co-authored-by: Cursor <cursoragent@cursor.com>
paulocastellano and others added 5 commits August 7, 2026 11:53
Read session_id via request->string(), and take OAuth error details from the League exception instead of decoding the response body.

Co-authored-by: Cursor <cursoragent@cursor.com>
Share one otherPosts check for first-create and last-delete instead of separate callbacks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop Auth::user() preference in PostObserver; checklist sync attributes to $post->user.

Co-authored-by: Cursor <cursoragent@cursor.com>
Share create/delete onboarding notify, drop Auth actor fallback to owner, and inline Passport Inertia error handling.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop partial-header branching; wrap page props in closures and always redirect completed/dismissed accounts to the calendar.

Co-authored-by: Cursor <cursoragent@cursor.com>
@paulocastellano paulocastellano changed the title Onboarding activation checklist + MCP OAuth authorize UX (#239) Activation checklist + MCP OAuth authorize UX (#239) Aug 7, 2026
paulocastellano and others added 15 commits August 7, 2026 13:07
Skip the MCP checklist work on full Inertia visits via deferred shared props,
early-exit token scans, and keep account completion stamps owner-gated.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…cks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Skip deferred onboardingProgress on Passport authorize so Inertia does not
rotate the session authToken, cover happy and stale-token paths in tests,
and polish MCP setup copy plus sidebar/onboarding layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
Stamp completion and re-render the finished checklist instead of
redirecting to the calendar so owners can review the done state.

Co-authored-by: Cursor <cursoragent@cursor.com>
Rename the authorize-only route check and assert onboardingProgress still
defers on calendar, onboarding, and MCP settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reject OAuth approve without a workspace, retry auto-complete until
stamped, send dismissed complete straight to calendar, and cover the
device consent defer opt-out.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove the self-hosted onboarding redirects, keep the SaaS-only dismiss backfill, and cover subscription-less owners plus skip/complete destinations.

Co-authored-by: Cursor <cursoragent@cursor.com>
Expand the welcome referral step with open-source and directory discovery channels.

Co-authored-by: Cursor <cursoragent@cursor.com>
Split Instagram/Threads, add Founder, and shorten Google, GitHub, AI, and blog option labels.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Onboarding: post-subscription activation checklist, residual banner, and processing redirect

1 participant