feat(billing): plan taxonomy reconciliation + Stripe sync + internal-tester allowlist (#164)
All checks were successful
CI / frontend (push) Successful in 6m40s
Mirror to GitHub / mirror (push) Successful in 7s
CI / e2e (push) Successful in 10m7s
CI / backend (push) Successful in 10m34s

Co-authored-by: Michael Chihlas <michael@resolutionflow.com>
Co-committed-by: Michael Chihlas <michael@resolutionflow.com>
This commit was merged in pull request #164.
This commit is contained in:
2026-05-11 05:07:07 +00:00
committed by chihlasm
parent dad5e1f546
commit 3f04911070
38 changed files with 745 additions and 110 deletions

View File

@@ -97,6 +97,40 @@ class Settings(BaseSettings):
STRIPE_WEBHOOK_SECRET: Optional[str] = None
SELF_SERVE_ENABLED: bool = False
# Internal tester allowlist for soft cutover. Comma-separated emails;
# when SELF_SERVE_ENABLED is False, listed users still see the self-serve
# surfaces (pricing page, invite-code-optional registration, etc.) so the
# full flow can be exercised in prod test mode before public flip.
INTERNAL_TESTER_EMAILS: list[str] = []
@field_validator("INTERNAL_TESTER_EMAILS", mode="before")
@classmethod
def split_internal_tester_emails(cls, v) -> list[str]:
"""Parse a comma-separated string into a normalized lowercase list."""
if v is None or v == "":
return []
if isinstance(v, list):
return [e.strip().lower() for e in v if e and e.strip()]
if isinstance(v, str):
return [e.strip().lower() for e in v.split(",") if e.strip()]
return []
def is_internal_tester(self, email: Optional[str]) -> bool:
"""Case-insensitive allowlist check. None/empty email is never a tester."""
if not email:
return False
return email.lower() in self.INTERNAL_TESTER_EMAILS
def is_self_serve_active_for(self, email: Optional[str]) -> bool:
"""True if self-serve surfaces should render for this user.
Either the global flag is on, or the user is on the internal-tester
allowlist. Anonymous calls (email is None) only see the global flag.
"""
if self.SELF_SERVE_ENABLED:
return True
return self.is_internal_tester(email)
@property
def stripe_enabled(self) -> bool:
"""Check if Stripe is configured."""