Files
resolutionflow/.ai/HANDOFF.md
Michael Chihlas fbb41e789c
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
CI / frontend (pull_request) Successful in 6m0s
CI / backend (pull_request) Successful in 11m15s
CI / e2e (pull_request) Successful in 10m4s
docs(handoff): capture Phase 1 backend completion + followups
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 19:14:30 -04:00

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

  1. Open the PR for branch feat/self-serve-signup-spec. Use gh pr create against main. 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).
  2. 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 to refresh_tokens (the password-login flow does via auth.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_token to a shared module and calling it from _sign_in_or_register.
  • stripe_enabled was relaxed in Task 14 from bool(STRIPE_SECRET_KEY) and bool(STRIPE_WEBHOOK_SECRET) to just the secret key. The webhook handler in Task 16 independently checks STRIPE_WEBHOOK_SECRET before calling construct_event, so signature verification is still safe — but if any other code reads stripe_enabled and assumes the webhook secret is set, that's a latent bug. Audit before Phase 2 cutover.
  • backend/app/core/stripe_handlers.py is 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 c6cbfc534fad has 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 are tests/<file>, NOT backend/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 gh CLI on this LXC — use the Gitea API ($GITEA_TOKEN in .claude/settings.local.json) for PR/issue work, or run gh from a host that has it.
  • Headless Chromium (/qa, /browse) needs CONTAINER=1 in the env launching the browse server (LXC namespace constraint).