You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Organizations are currently 1:1 with brands — a shim kept by #419 and made explicit (but still 1:1) by #370's brands.organization_id FK. The billing plan (#345) attaches subscriptions to "the organization" via referenceId, and checkout-first onboarding (#346) needs an org to exist before any brand — both assume the org is the customer, not a per-brand shadow. Decided direction (see the discussion on #345): one umbrella customer org containing many brands, with membership and billing at the org level.
This must land before the first paying customer — re-anchoring live Stripe subscriptions to different orgs later is the migration to avoid. Migrating memberships now is cheap by comparison.
Scope
Provisioning: create the customer org at signup or checkout (named during onboarding); create-brand attaches the brand to the caller's existing org instead of minting an org per brand; org id/slug decoupled from brand names. Resolve Unify brand creation between API and UI (org provisioning; enable non-admin keys) #405's API/UI unification on these semantics ("attach to org"), not the old ones.
Access: replace requireOrgAccess(userId, brandId) call sites with a brand→org lookup through brands.organizationId (e.g. a requireBrandAccess helper). Nothing may rely on the brand.id === organization.id backfill artifact.
Session/UX: activeOrganizationId becomes the real org context; the brand switcher lists the active org's brands; the Team settings page from Self-serve signup, Google OAuth, and Resend transactional email #343 moves from per-brand settings to org level, and invitations grant org membership.
Data migration: collapse each existing cloud user's per-brand orgs into one umbrella org — brands keep their ids (URLs stay stable), member rows merge, in-flight invitations lapse naturally (48h expiry). Local/demo/whitelabel modes are untouched.
Out of scope
Brand-scoped guest grants (agency invites a client who sees only their own brand) — follow-up gated on Plan definitions and entitlement system #344's entitlement system, as a higher-tier plan feature.
Part of #8.
Context
Organizations are currently 1:1 with brands — a shim kept by #419 and made explicit (but still 1:1) by #370's
brands.organization_idFK. The billing plan (#345) attaches subscriptions to "the organization" viareferenceId, and checkout-first onboarding (#346) needs an org to exist before any brand — both assume the org is the customer, not a per-brand shadow. Decided direction (see the discussion on #345): one umbrella customer org containing many brands, with membership and billing at the org level.This must land before the first paying customer — re-anchoring live Stripe subscriptions to different orgs later is the migration to avoid. Migrating memberships now is cheap by comparison.
Scope
requireOrgAccess(userId, brandId)call sites with a brand→org lookup throughbrands.organizationId(e.g. arequireBrandAccesshelper). Nothing may rely on thebrand.id === organization.idbackfill artifact.activeOrganizationIdbecomes the real org context; the brand switcher lists the active org's brands; the Team settings page from Self-serve signup, Google OAuth, and Resend transactional email #343 moves from per-brand settings to org level, and invitations grant org membership.Out of scope
Acceptance
brands.organizationId; no new code depends on org/brand id equality.Dependencies
referenceId= the umbrella org), Checkout-first cloud onboarding flow #346 (org must exist at checkout), Unify brand creation between API and UI (org provisioning; enable non-admin keys) #405 (brand-creation unification should adopt the new semantics).