Skip to content

P3: Defer paid billing and SMS product acceptance #270

Description

@tomqwu

Current Priority Decision

The Church/Basketball business milestone is complete, but the owner explicitly lowered billing priority. This commercial track remains deferred.

Execution lane: phase: billing-later. Status: deferred by owner.

Existing billing/SMS routers remain unregistered and provider credentials are not required for the working core flow. Preserve the already-merged tenant and financial security protections. Do not expose checkout, subscriptions, trial enforcement, invoices, SMS credits or provider delivery.

Resume only after the owner explicitly reactivates commercial work and authorizes the sandbox accounts and recipients. Complete security and sandbox/product acceptance before enabling any route, task or provider. All tests and code review remain local; GitHub Actions does not run tests, and Ollama is not a code-review provider.


Current Implementation Handoff

Prepared 2026-09-13 for a lower-cost builder at source 21a4a804aa57580451edded04736b1f51aef7e48.
No CI checks. All implementation validation and code review run locally.
Use the shared builder contract and this issue's work packages; no xhigh model or automatic model upgrade is required. This is a detailed recommendation, not a claim that a smaller model cannot make mistakes or that tests have passed.

Risk/review focus: High: optional paid features and external delivery.
Start condition: DEFERRED BY OWNER. Do not run provider sandboxes or expose paid features until the owner explicitly reactivates this track and authorizes accounts and recipients.

Source of Truth and Current State

Mounted routes are not evidence that paid entitlement, provider callbacks or delivery are ready. Do not let a checkout return URL activate a paid plan.

This handoff supersedes stale implementation statements in the background below. Preserve existing successful behavior and tests. Recheck the current branch before editing; the baseline is a source pointer, not permission to discard newer changes.

Dependencies and Ownership

Recommended Decisions

  1. Keep billing/SMS delivery disabled in core pilot until this issue passes. Review/auth fixes remain required even when delivery is disabled.
  2. Validated provider events are the source of payment state. Bind each event to a trusted customer/subscription/tenant, persist a unique provider event ID, and process duplicate/out-of-order events deterministically.
  3. Implement plan/entitlement transitions as an explicit state table: free/trial/active/past_due/cancelled and permitted actions; owner approves price/quotas/refund/cancellation policy before UI promises.
  4. SMS requires consent/verified ownership, opt-out, quiet hours, rate/cost bounds and idempotent event handling. Urgent flags must not silently bypass consent or safety limits.

Small Work Packages

Each item is one reviewable slice, not permission for one giant PR. Add the failing regression first; finish code, tests and affected docs for that slice together. Leave this issue open until all packages and original acceptance criteria are satisfied or explicitly revised by the owner.

  • 270.1: Write state/ownership/replay tests with provider fakes and correct auth contracts; align optional feature status in UI.
  • 270.2: Implement payment/SMS transition handlers and deduplication with durable tasks; do not mount callbacks before signature/tenant tests exist.
  • 270.3: Validate cancellation/reactivation/trial expiry/payment failures and invoice/export formats against the actual implementation.
  • 270.4: Run explicitly authorized sandbox provider acceptance, record test identifiers/status/delivery evidence, then request separate owner enablement approval.

Required Regression Cases

These are specifications for tests to add/retain, not claimed execution results. Each new negative case must assert unchanged unauthorized state and zero forbidden side effects.

  • T270-01: Invalid signature/foreign mapping -> zero entitlement/message mutation; duplicate/out-of-order event -> consistent single transition.
  • T270-02: Checkout pending/failed -> no paid capability; cancellation/refund/failed renewal -> exactly documented limits and recovery.
  • T270-03: SMS opted-out/unverified/quiet-hours recipient -> no send unless an explicitly approved valid exception exists.
  • T270-04: Provider timeout after uncertain success -> reconcilable state, not blind retry charges/messages or fabricated delivered status.

Local Commands and Evidence

Existing targeted commands (paths checked against the audit source; run only after the stated safe preflight):

poetry run pytest tests/api/test_billing_authorization.py tests/api/test_billing_registered.py tests/api/test_sms_registered.py tests/web/test_billing.py tests/web/test_pricing.py -q

Also run the shared formatting/lint/touched-type/unit/full-suite and local review protocol from #252 for the final pushed revision. Add new targeted tests to these commands when implemented. Run API and browser tiers in separate processes. Native, PostgreSQL, image, provider and operator drills require their explicit environment; an unavailable tool/target is blocked/not run, never a pass.

Schema and Compatibility

Event deduplication/state fields may require Alembic migrations; reuse #266 outbox semantics and serialize schema changes. Do not hand-edit generated native clients.

Stop Conditions

Pricing, quotas, refunds, consent policy, sandbox credentials and real enablement are owner inputs. No charges, public sales or real SMS from this planning authorization.

After two failed focused repair attempts without new diagnostic evidence, stop the affected package and post the exact failure, commands, suspected boundary and needed decision. Do not silently broaden scope, weaken tests or upgrade models. A fresh local reviewer checks: Inspect signed event provenance, financial state transitions, idempotency/crash recovery and consent/entitlement invariants.

Completion Receipt

  • Work-package and regression IDs above map to changed files and actual results.
  • Commands, versions, dates, pass/fail/skip/not-run counts, logs/screenshots and tested head/base SHAs are linked.
  • A separate local review records findings and resolution; self-review is labeled if used and is not misrepresented as independent review.
  • Affected docs/README/playbooks/screenshots and dependency/roadmap status are reconciled, not left as unnamed follow-ups.
  • If implementation is authorized through PR/merge, GitHub reports mergeable and the shared local-evidence requirements are met; reviewer agents never merge.
  • No hosted CI check, status attestation, Ollama reviewer, live provider action, deployment, real-data purge or store submission was introduced by implication.

Copyable Builder Prompt

First read this issue's Current Priority Decision and #289. Run only its NOW slice.
If this issue is deferred, report that state instead of starting the older package list.
Implement the next ready work package in tomqwu/SignUpFlow issue #270.
Read its Current Implementation Handoff and #252 Builder Handoff Contract first.
Inspect current source and preserve newer/unrelated changes. Start with the
package's failing regression, then complete code, local tests, local review and
affected docs/assets together. Do not skip acceptance or invent passing evidence.
No CI checks or Ollama code review. Do not deploy, activate providers, purge real
data or submit to stores. Stop and report unmet prerequisites or policy decisions.
Record the package/test IDs and exact reviewed/tested source SHAs before claiming done.

Earlier Audit and Acceptance Context

Current policy (2026-09-13)

No CI checks. Everything is validated locally. This includes code review,
formatting, lint, type checks, migrations, all test tiers, security scans,
artifact checks and mobile validation. Do not add hosted jobs, required CI
statuses, synthetic success checks or an Ollama reviewer. GitHub is for source,
PRs, issues and publication, not validation.

Record commands, environment, results, limitations and reviewed head/base SHAs.
Builders merge only with completed local evidence and GitHub mergeability;
reviewer agents never merge. Real staging/provider/device acceptance remains
required where applicable, driven by authorized local operator tools.
Historical evidence and older comments do not override this policy.

Parent roadmap: #252

Priority: P2, blocks paid/SMS launch; not the core pilot once routes are safely disabled. Phase: E. Suggested owner: Backend/integrations plus product owner. Original estimate (superseded; re-estimate remaining work): 6-10 engineering days; external setup additional.

Historical audit evidence (recheck against current source)

Billing and SMS routers are mounted despite AGENTS/CLAUDE disabled-feature descriptions. api/routers/billing.py constructs placeholder Stripe price IDs and hard-coded return URLs; checkout-success does not verify the checkout session. api/routers/organizations.py:31 claims free-subscription creation but only inserts Organization. Stripe webhook routing remains unmounted in api/main.py; api/services/webhook_service.py:70 parses unsigned events if the secret is absent. SMS schemas contain integer/string mismatches. Passing registration/status-page tests is not provider acceptance.

Source baseline: GitHub main 214e3f3f17a582d5f9b2063be6872ea2b1d25714, audited 2026-09-09. Infrastructure/provider claims marked unverified require actual staging evidence.

Implementation plan

  1. Keep paid billing and live SMS unavailable to the core pilot until all criteria here pass. Document the visible feature state and remove misleading success affordances.
  2. Provision the free entitlement consistently with organization creation. Map actual configured test/live price IDs and public return URLs; verify checkout/payment-method/customer ownership.
  3. Make Stripe webhook validation fail closed and processing durable/idempotent before mounting it. Handle duplicate/out-of-order events, failed payment, cancellation/reactivation and reconciliation against the provider.
  4. Complete canonical-ID SMS verification/preferences, signed inbound/delivery callbacks, opt-out, quiet-hours, budget limits and failed-send accounting; reuse the security fixes rather than reimplementing them.
  5. Run approved sandbox journeys and establish explicit production enablement criteria, customer support paths, monitoring and a disable switch.
  6. Synchronize web/API documentation and generated client only after contracts stabilize.

Acceptance criteria

  • Sandbox signup -> free entitlement -> checkout -> verified webhook -> entitlement change -> cancellation/reactivation works without manual database edits.
  • Provider failures do not grant paid entitlements, double-charge, or silently lose subscription updates.
  • Unknown/unsigned/mismatched/replayed provider events cannot mutate another tenant.
  • SMS delivery/opt-out/quiet-hours/budget behavior works with canonical IDs and verified callbacks.
  • Live mode is a deliberate owner-approved rollout with test evidence and rollback/disable procedure.

Dependencies

#256, #257, #258, #266, #265

Validation

Use Stripe test mode and Twilio test/sandbox fixtures with approved test identities; exercise retries and reconciliation. Run affected API/web/worker tests, review cost/entitlement invariants, and record no live transaction as part of testing.

Whole-repository audit scope (2026-09-13)

Baseline: 21a4a804aa57580451edded04736b1f51aef7e48. This addendum assigns full-scope follow-through; it is not a new test pass or production sign-off. No CI checks; all review and validation runs locally.

Review billing/SMS service/router/task/template/schema code and provider flags even while optional release is disabled. Include prices/quotas, entitlement enforcement, consent/opt-out/quiet-hours, trial/subscription lifecycle, payment failures/refunds, idempotent signed webhook handling and delivery retry behavior. Match API/web/public pricing (#278/#285) and accurate feature status (#284). Require zero real side effects in default local tests (#281). Sandbox/live provider and store acceptance need explicit owner approval and a separate evidence record; mounted routes must satisfy #256/#257 before the core pilot.

Keep evidence and disposition synchronized with master roadmap #252 and documentation ledger #277. Close only after the remaining acceptance criteria have linked local results; a planning/audit note is not completion.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestphase: billing-laterBilling and paid SMS deferred; security is still mandatory before exposure or enablement.tests

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions