feat(mobile,trpc,auth): gate mobile behind a paid plan

Merged
SA
3mo ago
+333-5

Mobile launches as a Pro perk (user decision — limits users while we iterate, avoids clawing back free access later). Externally-billed subscription gating with no IAP, per guideline 3.1.3(b) multiplatform services — the Netflix/Slack pattern.

The gate is one wall, twice

  • Client: a new Stack.Protected tier in mobile's RootLayout — signed-in + not-pending-deletion + no paid plan → paywall screen. plan already rides the session via customSession, so no extra query.
  • Server: one protectedProcedure middleware — mobile client + no plan on the active org → FORBIDDEN, allowlisting only account self-management (user.me/deleteAccount/reactivateAccount/myOrganizations). Keyed on the x-superset-client header, which mobile now actually sends (the header parsing existed but no client ever adopted it — this also turns on the per-client API telemetry for mobile). Other clients are never gated.

No per-feature plan checks anywhere — nothing to remember as the product grows.

The paywall screen

Steering-safe copy ("Manage your plan from the Superset desktop app" — no external purchase link, valid on every storefront), plus: org switcher (a member whose active org is their free personal org but who belongs to a paid org can switch right there — otherwise real customers would hit a dead wall), Refresh, Contact support, Log out, and Delete account (grace-period flow) so guideline 5.1.1(v) survives the gate.

App Store review access

  • Credential sign-in enabled in production (emailAndPassword.enabled always; disableSignUp outside dev/preview so nobody can register)
  • Quiet "Sign in with email" link on the sign-in screen (prompt-based, same pattern as the dev options)
  • bun run db:seed-review (APP_REVIEW_EMAIL/APP_REVIEW_PASSWORD) idempotently provisions the demo account: credential login, onboarded, Pro-subscribed personal org (subscription row only, no Stripe charge)
  • store.config.json review-notes/demoRequired update rides #6408; the credentials themselves go into ASC's App Review sign-in fields by hand, never the repo

Known residuals

The relay/host path is not plan-gated (client gate covers the UX; a determined free user scripting the relay directly isn't a launch concern). Desktop/web remain ungated by design.

Testing

  • turbo typecheck (mobile, trpc, auth) + lint green
  • Full paywall→upgrade→refresh loop exercisable on TestFlight with the seeded review account

Summary by cubic

Gate Superset Mobile behind a paid plan and add a paywall screen. Previously any signed-in user could use mobile; now only sessions with a paid plan on the active org can proceed, and unpaid sessions land on the paywall. Desktop/web behavior is unchanged.

  • Client: RootLayout adds a Stack.Protected tier keyed on session.plan; unpaid sessions route to paywall (no extra query; plan is in the session).
  • Server: protectedProcedure forbids mobile without a plan except user.me, user.deleteAccount, user.reactivateAccount, and user.myOrganizations. Gating is keyed by the x-superset-client header, which the mobile client now sends as mobile/<version> (also enables per-client API telemetry).
  • Paywall: org switcher (to move to a paid org), Refresh, Contact support, Log out, and Delete account. Copy avoids external purchase links (App Store 3.1.3(b)); deletion remains accessible (5.1.1(v)).
  • Sign-in: Quiet email/password option added to the sign-in screen. Credential sign-in is enabled in production; sign-up remains disabled outside dev/preview.

Rollout

  • Create the App Review demo account in each environment: APP_REVIEW_EMAIL=… APP_REVIEW_PASSWORD=… bun run db:seed-review (idempotent), then add credentials in App Store Connect review details.
  • No schema/data migrations. Other clients are not gated.

Summary by CodeRabbit

  • New Features
    • Added a Pro subscription paywall with plan messaging, organization switching, support contact, sign-out, and account deletion.
    • Added email and password sign-in with loading states and clearer error messages.
    • Added account deletion with confirmation, progress feedback, and automatic sign-out.
  • Access & Authentication
    • Paid-plan checks now guide eligible mobile users to protected areas or the paywall.
    • Email/password sign-in is available in production.
  • Improvements
    • Mobile requests now report the app version for improved service compatibility.