4.2 KiB
HANDOFF.md
Last updated: 2026-05-06 (Phase 1 backend complete on feat/self-serve-signup-spec)
Active task: Phase 1 self-serve signup backend foundation — DONE on branch. PR not yet opened.
Where this session ended
24 commits on top of main (31ca3fb). All 26 tasks from docs/superpowers/plans/2026-05-06-self-serve-signup-phase-1-backend.md complete. Full pytest run is green (1167 passed, 35 deselected). Single alembic head: c6cbfc534fad.
Phase 1 covered: schema additions (oauth_identities, plan_billing, sales_leads, stripe_events, plus 5 new columns across users/accounts/account_invites), Subscription complimentary status + has_pro_entitlement, the two new guards (require_active_subscription, require_verified_email_after_grace), full BillingService (start_trial / create_checkout_session / apply_subscription_event / get_billing_state), Stripe webhook handler, Google + Microsoft OAuth callbacks with oauth_identities linking, OAuth-only password guard, register-time verification email + invite email-match, bulk + soft-revoke invite routes, GET /billing/state, and the pilot complimentary backfill migration.
The conftest's test_user fixture was modified to seed a Pro/active Subscription post-register (delete-then-insert) so the new subscription guard doesn't 402 every existing test. Two existing tests adapted because they explicitly assumed the old free-plan default: test_subscription_limits.py (the two free-plan tests now downgrade inline) and test_kb_accelerator.py::TestQuota::test_get_quota (the kb_setup fixture downgrades to free).
Resume point — DO THIS NEXT
- Open the PR for branch
feat/self-serve-signup-spec. Usegh pr createagainstmain. Suggested title:feat: self-serve signup backend (Phase 1). Body should mention dark-launch posture (every new endpoint is gated by env config, not a feature flag — see Task 26 §3 in the plan). - Phase 2 (frontend + cutover) lives in a sibling plan:
docs/superpowers/plans/2026-05-06-self-serve-signup-phase-2-frontend.md(assumed; verify path). It's the next logical task once Phase 1 ships.
Followups deferred from this session
- OAuth callbacks don't call
_store_refresh_token. The Google/Microsoft callbacks issue a refresh JWT but never persist its hash torefresh_tokens(the password-login flow does viaauth.py:_store_refresh_token). Result: refresh-token revocation/rotation lookups won't find OAuth-issued tokens. Decide before Phase 2 dark-launch whether to backfill — likely yes, by extracting_store_refresh_tokento a shared module and calling it from_sign_in_or_register. stripe_enabledwas relaxed in Task 14 frombool(STRIPE_SECRET_KEY) and bool(STRIPE_WEBHOOK_SECRET)to just the secret key. The webhook handler in Task 16 independently checksSTRIPE_WEBHOOK_SECRETbefore callingconstruct_event, so signature verification is still safe — but if any other code readsstripe_enabledand assumes the webhook secret is set, that's a latent bug. Audit before Phase 2 cutover.backend/app/core/stripe_handlers.pyis a stub module that's no longer referenced after Task 16. Safe to delete in a follow-up; left in place to keep Phase 1 diff focused.- Pilot backfill migration
c6cbfc534fadhas not been applied to prod yet. It runs once at deploy time and is forward-only.
Environment notes (carry-forward)
- Code-server LXC has bun + docker but no native python/node/npm. Use
docker exec resolutionflow_{backend,frontend} ...for build/test commands. - Pytest WORKDIR is
/app— test paths in pytest commands aretests/<file>, NOTbackend/tests/<file>. - Backend pytest cmd:
docker exec resolutionflow_backend pytest tests/<path> -v --override-ini="addopts=". The full run takes ~25 min. - Alembic via
docker exec -w /app resolutionflow_backend alembic .... Never pass--rev-id. - No
ghCLI on this LXC — use the Gitea API ($GITEA_TOKENin.claude/settings.local.json) for PR/issue work, or runghfrom a host that has it. - Headless Chromium (
/qa,/browse) needsCONTAINER=1in the env launching the browse server (LXC namespace constraint).