Repository navigation
MEMBERS-DUES-001 — Build server-authoritative annual membership checkout and renewal #114
Description
Officer impact: The website becomes the authoritative place to see whether a person has paid membership for the current annual term; officers stop treating a role toggle, email match, redirect, or spreadsheet checkbox as proof of membership.
Officer documentation: Implementation children must update OFFICER_START_HERE.md, docs/officers/EVENTS_SHOP_MEMBERS.md, docs/officers/SYSTEM_MAPS.md and its text alternative, and the glossary for any unavoidable payment/membership terms.
Deployment evidence: None at issue creation. Each child must separately prove source changed, tests passed, merged, website published, runmprc.com verified, Firebase deployed, payment/provider configuration completed, and production behavior verified. Until then this capability is NOT AVAILABLE YET.
Product decision
- Full membership records live on the MPRC website/backend.
- Membership is renewed annually and current access depends on approved payment evidence for the applicable term.
- Historical Google Forms/Sheets import is deferred; it is not part of this tracker unless BACKEND-001 — Audit the Firebase cutover and approve legacy data disposition #113 later approves a separate migration.
- A membership record may exist before the person creates a website account. Account association is a separate, audited action under MEMBERS-ADMIN-001.
- The first online dues flow is a one-time annual payment, not an automatically recurring subscription. Any future subscription design requires a separate owner decision and issue.
Problem
Current source represents membership only as an Auth custom claim and a mirrored members/{uid}.role value (unverified, member, or admin). It has no membership term, dues/payment evidence, renewal history, plan/household state, expiry, grace, refund/dispute behavior, source/provenance, or account-independent membership record. Direct role changes can therefore outlive dues and cannot explain why access was granted.
Stripe is not currently live. Existing payment work covers race and merchandise correctness, not annual membership entitlement.
Target invariants
- Firestore is authoritative for club membership operations; verified Stripe state is authoritative for Stripe money.
- A browser, redirect, email, payment screenshot, client field, spreadsheet checkbox, or Auth provider never activates membership.
- Online activation requires a verified server-side payment transition for the exact annual term and approved plan/amount/currency.
- An approved off-platform payment may be recorded only through a separately authorized, audited manual command. It must never fabricate Stripe state.
- Each renewal creates a new immutable term/evidence relationship; it does not overwrite prior membership history.
- Member custom claims and UI access are derived projections of one active membership term, not the membership source of truth.
- Membership and payment state remain separate. Pending, failed, expired, refunded, disputed, waived/comped, and manually confirmed states are explicit.
- A membership can be unlinked from an Auth UID until an officer completes the controlled association workflow.
Tracker scope
This is a size-L tracker, not one coding assignment. Split implementation into dependency-ordered children with one observable outcome each, normally:
- Annual term, membership, plan, payment-evidence reference, source/provenance, and pure transition contract with additive compatibility mapping.
- Idempotent annual dues command/Checkout creation using server-approved plan and amount snapshots.
- Verified payment-event reduction into membership activation/renewal, including duplicate, out-of-order, delayed, failed, expired, refunded, and disputed cases.
- Expiry/reconciliation job and derived Auth-claim/access refresh/revocation without deleting membership history.
- Approved manual/off-platform payment evidence command, only if owner policy permits it, kept separate from account association.
- Minimum member/account status projection and renewal UX after the server contract is proven.
Owner decisions required before relevant children
Do not invent:
- calendar-year versus anniversary terms, effective/start/end dates, or grace period;
- individual, household, non-resident, sponsored/comped, or other plan eligibility;
- prices, early-bird windows, currency, accepted offline methods, or who may confirm them;
- refund, dispute, chargeback, cancellation, transfer, lapse, reactivation, or hardship policy;
- waiver/insurance evidence relationship, accounting retention, tax, or member communications.
Record approved values as versioned server configuration rather than hardcoded UI copy.
Acceptance criteria
- Every membership has a stable non-email ID, versioned plan/term, explicit status, source/provenance, created/updated actors, and payment-evidence relationship appropriate to its source.
- A membership may exist without an account; creating an Auth account does not activate or silently associate it.
- Unpaid, failed, cancelled, mismatched, replayed, wrong-term, wrong-plan, wrong-amount/currency, test/live-mismatch, or client-forged payment data cannot activate membership.
- Repeated checkout/renewal requests and duplicate/out-of-order provider events produce one coherent term and no duplicate entitlement.
- Renewal preserves earlier terms; overlapping/duplicate household or individual records enter a review state rather than granting twice.
- Expiry, approved refund/chargeback/dispute outcomes, suspension, and offboarding deterministically update the current entitlement projection and force safe token refresh/revocation.
- Admin/browser clients cannot write canonical membership, payment evidence, current entitlement, or audit records directly.
- Member pricing and protected content consume the server-derived active-membership projection rather than Auth provider or raw profile fields.
- Tests use synthetic identities, payment fixtures/test mode, and Firebase emulators only; production projects/providers are blocked.
- Additive migration/dry-run reports are idempotent, but no historical roster import runs until BACKEND-001 — Audit the Firebase cutover and approve legacy data disposition #113 approves a separate scope.
- Backup-officer review proves the documented current procedure requires no terminal, source edit, secret handling, or direct Firestore mutation.
Dependencies and coordination
- MEMBERS-IDENTITY-001 — Define authoritative membership and external-account state #81 owns the provider-neutral membership lifecycle, household/non-resident cases, collisions, and target authority contract; amend and complete it first.
- BACKEND-001 — Audit the Firebase cutover and approve legacy data disposition #113 owns legacy Firebase/Forms/Sheets disposition. User direction is to import later, so do not create or execute
BACKEND-002now. - DATA-001B — Inventory personal data and approve a minimization/retention matrix #110 owns permitted personal fields, purpose, retention, deletion/export behavior, and vendor treatment.
- Generic payment foundations PAY-001/PAY-002/PAY-003 (PAY-003 — Build idempotent asynchronous Stripe event processing #106), CONFIG, ABUSE/App Check, TEST, and protected release CI-001 — Establish trustworthy quality gates and protected deployment #105 must be ready before payment children.
- AUTH-001/verified-email behavior, AUTH-002 retirement/replacement, AUTH-003 capabilities/MFA/recent-auth, ADMIN-001 command/audit infrastructure, and SEC-001 — Replace the Firestore admin catch-all with resource-specific rules #100 Rules boundaries must be consumed rather than reimplemented.
- AUTH-006 — Offer simple email/password and Google sign-in #109 remains identity entry only and must not activate membership. CHANNEL-QUEUE-001 — Build an audited membership-to-channel reconciliation queue #90 projects established membership to external channels only.
Explicitly out of scope
- Bulk import of historical Sheets/Forms or data from the inaccessible Firebase project.
- Silent account association by matching email.
- Recurring subscriptions, automatic bank/Venmo reconciliation, or storing bank/payment credentials.
- Race/merchandise checkout, refunds, taxes, shipping, discounts, or waiver-policy decisions.
- Direct production writes, live Stripe objects, provider-console changes, or shared-account credentials.
Claim protocol
Creation is not a claim, and this size-L tracker must not be claimed as one implementation. Publish/assign one dependency-ready child at a time. Before work begins, the child must be assigned and have a timestamped CLAIMED by <canonical agent> at <UTC>; branch <branch> comment that is re-read; earliest valid claim wins.
Activity
MEMBERS-DUES-001A: immutable membership term/evidence receipt ledger (#…
MEMBERS-DUES-001A: immutable membership term/evidence receipt ledger (#…
MEMBERS-DUES-001F: pure member/account status projection + renewal af…
daliu commentedon Jul 22, 2026
Dependency correction #451 is claimed from exact main 0b9960f. It makes the already-required paid-but-unlinked membership sequence representable in the pure unused authority contract while preserving link-first compatibility and fail-closed entitlement. Parent #114 remains open; no payment policy, Stripe/runtime, persistence, migration, deployment, or live behavior is in scope.
daliu commentedon Jul 22, 2026
Corrective dependency #451 merged through PR #452 as exact main
937e336031ffe064aa120460327538aab0d45d30; exact-main CI 29920636668 passed. Paid/current evidence can now remain safely unlinked in the pure authority contract, and later association preserves it without granting anything beforehand. Parent #114 remains open. No payment policy, Stripe/runtime, persistence, migration, deployment, provider, or live behavior changed.daliu commentedon Oct 11, 2026
Readiness check, 2026-10-11: Dave requested membership and event signup/cancellation next, with low cost and staging before production or real payments. Reviewed current membership authority/status helpers and race signup/admin cancellation. The membership helpers remain unwired; the legacy admin cancel action only changes Firestore and is not a safe paid cancellation workflow. Four existing synthetic unit suites passed on Node 22: 273 tests (membershipAuthority, membershipAccountStatusProjection, raceCheckoutValidation, adminRegistrationAction). This is local regression evidence, not new implementation or hosted staging proof. A cancellation policy decision is pending: access through the already-paid term versus immediate offboarding; neither implies a refund. Recommended delivery order is officer-confirmed existing dues and free-event signup/cancellation before a separate paid-race lifecycle. No new policy, grant, IAM change, provider call, staging deployment, production write or payment test performed. Existing #81/#114/#115 dependencies remain open. Officer impact: no new officer or member workflow is available. Officer documentation: None — no workflow changed; decision and next-step handoff recorded privately. Deployment evidence: no website, Firebase or outside-provider deployment in this follow-up.
daliu commentedon Oct 11, 2026
Owner decision resolved, October 11, 2026: Dave selected Continue through the paid term. Voluntary membership cancellation must preserve access through the already-paid annual term and issue no automatic refund; security suspension remains separate. Focused dependency-clearing child #705 / PR #706 records a versioned backend policy and 15 existing-authority boundary regressions. Full local backend: 7609 pass / 64 skipped; lint passes. This does not implement a cancellation command or launch membership/events; hosted staging proof and the parent remain open. No production/provider/payment change.
daliu commentedon Oct 15, 2026
October 15 direct owner decisions for the minimum member release:
First focused runtime source change is #737: canonical current-member admission for new free-event signup with expiry-safe cancellation and immutable retry. This does not complete #81/#115/#114 or activate real membership/payments.