TradeForce migration docs

#ADR-002: Auth provider cutover and signup activation (ACC-AUTH-SURFACE)

status: open item_id: AUTH-FOUNDATION module_id: MOD-AUTH

#Context

#In plain terms

Today people sign up, sign in and reset their password with Bubble's own built-in accounts. The rebuild runs on Supabase, and neither the logged-in sessions nor the stored passwords can be carried across: Bubble keeps the password hashes and never exports them. So before anyone writes the sign-in screen, two product decisions are needed.

First: how do the people who already have an account get back in? Either everybody is forced through "set a new password" once, or both systems run side by side for a while, or accounts move to an external identity provider. There is no silent option — any claim that passwords "just migrate" is wrong.

Second: what turns a new account on? Bubble does it in an unusual way today. Signup does not send Bubble's own confirmation email; instead the app sends its own email titled "Verify" whose link points at the onboarding page with active=yes in the address, and the onboarding page is what flips the account to active. The target can keep that exact chain, or drop it for Supabase's standard confirm-email — but then the document must say at which moment profiles.active becomes true, because several screens gate on it.

A third, smaller choice rides along: those links are already in people's inboxes, and they spell the mode with a capital letter (?nav=Contractor, ?nav=Verify), because Bubble puts the option's display text in the URL rather than its stored value. Whatever this ADR picks, the new app should read that parameter case-insensitively so old links keep working.

Until this is decided, the auth foundation slice is blocked; every other module's login-required behaviour depends on it.

#IR evidence

Ref Pointer Finding
bTGYf /pages/bTGbC index page — sign-in / sign-up / reset / verify modes on one surface
AAL /pages/AAW reset_pw page — ResetPassword then ChangePage to onboarding
bTHpx1 /pages/bTGbC/workflows/bTHjk1/actions/0 SignUp with send_confirm_email: false; writes role_option_role and approve1_boolean false; never writes active__boolean
bTHqT1 /pages/bTGbC/workflows/bTHjk1/actions/2 SendEmail subject "Verify", sender "TradeForce", body links onboarding?nav= + current user's role display + &active=yes
bTHqJ1 /pages/bTGbC/workflows/bTHjk1/actions/3 ChangePage back to index with nav / tab interpolated from option displays
bTHsZ1 / bTHse1 /pages/bTHDr0/workflows/bTHsd1 (+ /actions/1) onboarding PageLoaded: when URL active=yes and the user is still inactive → ChangeThing active__boolean true
bTHop1, bTHqz1, bTHrP1 index / reset_pw workflows native LogIn, SendPasswordResetEmail, ResetPassword — no portable credential material
navigationindex /option_sets/navigationindex db_values signin/signup/reset/verify; displays SignIn/SignUp/Reset/Verify; index conditions compare the display

#Decision

open — no choice yet. Implement may build the Supabase session client, the profiles row and RLS, but must not wire an activation path or a credential-cutover story until this ADR is accepted.

#Options

#A — Preserve the Bubble activation chain on Supabase Auth

Plain: people get the same "Verify" email they get today; clicking it lands them on onboarding and switches the account on there.

Confirm-email stays off in Supabase; an Edge Function sends the Verify template; the onboarding route keeps the active=yes branch, now as a server-checked RPC rather than a browser write.

Trade-offs: highest fidelity and existing links keep working; but "email verified" is then an app convention rather than an Auth-enforced fact, and the activation write needs its own authorization.

#B — Replace with Supabase confirm-email

Plain: people get Supabase's standard confirmation email, and the account is on once they confirm.

profiles.active is set from the confirmation event (trigger or callback); onboarding drops its activation branch and the custom Verify template is retired.

Trade-offs: identity semantics are owned by the platform and the deep-link branch disappears; but in-flight Bubble links break unless a redirect is kept, and the exact moment active flips must be written down because gates read it.

#C — Credential cutover: forced reset (pairs with A or B)

Plain: everyone signs in once via "forgot password".

Trade-offs: simplest and safest; one-time friction for every existing user, and the reset mail must reach addresses that may be stale.

#D — Credential cutover: time-boxed dual run (pairs with A or B)

Plain: both systems accept logins for a window; accounts move as people sign in.

Trade-offs: no user-visible break; two identity stores to reconcile, and a hard end date that someone must enforce.

#E — Credential cutover: external IdP bridge (pairs with A or B)

Plain: sign-in moves to an external provider (e.g. social or SSO) instead of email/password.

Trade-offs: removes password handling entirely; changes the product's sign-in surface, which the export does not evidence, and needs its own onboarding for people without such an account.

#Consequences

Generated from the repository at 2026-09-22 15:55 UTC · source of truth is docs/ in the workspace, not this site.