Skip to content

MEMBERS-IDENTITY-001 — Define authoritative membership and external-account state #81

Open

Description

@daliu

Officer impact: Officers will have one plain-language source for whether a person is a current member and what access should follow. No officer workflow becomes available from this design ticket alone.

Officer documentation: Update OFFICER_START_HERE.md, docs/officers/EVENTS_SHOP_MEMBERS.md, docs/officers/ACCESS_CONTINUITY.md, and docs/officers/SYSTEM_MAPS.md with the approved contract and text alternative when implementation lands.

Deployment evidence: None at issue update. Closure must distinguish contract/source changes, tests, merge, website publication, Firebase deployment, provider configuration, and production verification; no green workflow alone proves live membership behavior.

Problem

Website roles, dues/roster membership, Google access, WhatsApp access, and Strava connections can drift. Treating any external channel as a peer membership authority would create accidental access and discount grants.

Invariant

Firebase UID plus a server-verified current MPRC membership record is the only membership authority. Google, WhatsApp, and Strava are desired/observed projections and never grant membership, prices, or privileges.

Scope

  • Define membership states and transitions for approval, renewal, expiry, suspension, reactivation, household/nonresident cases, and offboarding.
  • Define an additive provider-link contract with non-secret metadata, restricted identifiers/tokens, consent, desired state, observed state, last reconciliation, error, and stable command ID.
  • Define collision handling for duplicate email, changed email, Google credential already linked elsewhere, duplicate WhatsApp number, and duplicate Strava athlete.
  • Define minimization, consent, retention, deletion, and access-revocation SLA.
  • Define pure idempotent transition rules and migration from current role-only records.

Acceptance criteria

  • No provider connection or matching email automatically grants club membership.
  • Custom claims contain authorization only, not provider IDs, phone/profile data, or rosters.
  • Duplicate, out-of-order, lapse, renewal, relink, disconnect, and partial-failure transitions are specified and tested.
  • Other integration tickets consume this contract rather than inventing provider-specific membership logic.
  • Migration is additive, dry-runnable, and preserves existing accounts.

Dependencies and sequencing

SEC-001 (#100) and the remaining AUTH-001 verified-email/claim protections are prerequisites for implementation. This issue defines the authoritative membership contract consumed by AUTH-002/AUTH-002A (#117), #114, and #115; those downstream issues are not prerequisites for defining or completing this contract. Align with AUTH-003 capability design before implementation.

Coordination

Parent: #79

Do not begin implementation until dependencies are complete, this issue is assigned, and a timestamped CLAIMED comment naming the agent and branch is posted. Creation of this ticket is not a claim. Preserve the parallel agent work tracked by stable IDs in GITHUB_ISSUES.md.

Activity

  1. added
    priority:P0Launch blocker or urgent security risk
    area:membershipMembership lifecycle and reconciliation
    area:authAuthentication and authorization
    area:firebaseFirebase services and data
    size:SSmall focused issue
    status:proposedDesigned but dependencies or decisions remain
    on Jul 12, 2026
  2. daliu commented on Jul 12, 2026

    @daliu
    ContributorAuthor

    PRODUCT REQUIREMENT (2026-07-12): membership/account state must be identity-provider-neutral. Members may create/sign into a Firebase account with email/password or Google through #109, but either method starts account-only/pending and never grants membership, discounts, member pricing, payment state, or admin authority. The #81 contract must model the same lifecycle and collision rules for both providers with plain-language states suitable for elderly/nontechnical members; provider metadata remains a minimal derived identity link, not membership evidence.

  3. daliu commented on Jul 12, 2026

    @daliu
    ContributorAuthor

    Privacy dependency: #110 will inventory provider/member fields, purposes, access, vendor handling, retention-decision status, and request behavior. It must consume this issue's provider-neutral account/membership state and must not redefine membership authority. #110 is owner-blocked and unclaimed.

  4. daliu commented on Jul 12, 2026

    @daliu
    ContributorAuthor

    Legacy-source dependency: #113 now owns the read-only inventory and disposition decision for the inaccessible Firebase project, the club-owned Firebase project, and active Google Forms/Sheets. This issue remains the authority for the target provider-neutral membership/account contract. Do not infer membership from email or build the roster import until #113 identifies the approved source categories and #81 defines their target state.

  5. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    PRODUCT DECISION (2026-07-12): the MPRC website/Firebase backend will hold the full authoritative membership record. Membership renews annually based on approved payment evidence. A stable membership record may exist without a website account; initial onboarding may be one-at-a-time as people create accounts, but association to a UID must be explicit, audited, and require authoritative verified Auth state—never a silent email-only role grant.

    The #81 contract must now include annual term boundaries, plan/household/non-resident semantics, payment-evidence-to-term transitions, renewal/lapse/grace/reactivation, manual/off-platform confirmation authority, refund/dispute outcomes, account-independent member IDs, link collisions, and derived claim expiry/revocation. Do not invent unresolved prices/policy values.

    Published children/consumers:

    Historical import remains deferred behind #113; do not create BACKEND-002 yet.

  6. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    COORDINATION EDIT STARTED by Codex agent /root/membership-access at 2026-07-13T06:35:55Z. This is not an implementation claim. I am correcting only the circular dependency direction among #81, #115, and #117; product scope and status labels remain unchanged.

  7. daliu commented on Jul 13, 2026

    @daliu
    ContributorAuthor

    COORDINATION EDIT COMPLETE at 2026-07-13T06:37:39Z. The circular edge was removed: #81 is now explicitly upstream of #114/#115/#117, while #100 and remaining AUTH-001 protections remain its implementation prerequisites. Status stays proposed; this is still unassigned and unclaimed for implementation.

  8. daliu commented on Jul 14, 2026

    @daliu
    ContributorAuthor

    AUTH-001B / #196 source outcome merged through PR #198 as exact a8801770e97cf21d81f3307f5893734115140d8f. Exact-head CI 29297012945 and post-merge CI 29297116454 passed all blocking jobs; the Rules emulator proof is 348/348 with a prior 30-case red proof. No protected release ran and Firebase Rules were not deployed, so the boundary is not live. This advances the Rules prerequisite only; Functions/Admin SDK authorization, mirror reconciliation, token refresh/revocation, deployment, and live readback remain open. Verification still grants no membership or role.

  9. daliu commented on Jul 18, 2026

    @daliu
    ContributorAuthor

    CLAIMED (scoped, source-only) at 2026-07-18T23:16:56Z by agent /root on branch codex/issue-367-provider-link (child #367).

    Scope of this claim is only the provider-neutral external-account link + collision sub-contract as a pure, unused source module (functions/membershipProviderLink.js) delivered as a draft PR for owner review — a design deliverable for #81, not its implementation. It grants no membership/role/authority, is imported by no runtime path, and changes no live behavior.

    This does not claim or complete #81 overall. #81's live implementation (Firestore wiring, custom-claim issuance, provider configuration, UID association) remains gated on #100 (closed) plus the remaining AUTH-001 Functions/Admin authorization protections noted at 2026-07-14, and stays with the owner. The membership state/term/entitlement side remains owned by functions/membershipAuthority.js and #114/#115; this slice only fills the provider-link + collision gap.

    Verification still grants no membership or role.

  10. daliu commented on Jul 18, 2026

    @daliu
    ContributorAuthor

    CLAIMED (scoped, source-only) at 2026-07-18T23:41:29Z by agent /root on branch codex/issue-370-consent-state (child #370).

    Scope of this claim is only the provider-neutral versioned consent-state derivation sub-contract as a pure, unused source module (functions/membershipConsentState.js) delivered as a draft PR for owner review — a design deliverable for #81, not its implementation. It fills the consent-state gap that #367 (membershipProviderLink.js) explicitly deferred: given the latest recorded consent decision for a (provider, subject, scope) track and the policy version now in force, it derives the effective disposition (active / reaffirmation_required / withdrawn / not_consented). Every result carries grantsAuthority: false; policy versions are compared for equality only (no ordering/recency invented). It is imported by no runtime path and changes no live behavior.

    This does not claim or complete #81 overall, and does not cover consent capture (the append-only event ledger), withdrawal side effects, the retention/deletion/SLA matrix (#110), or provider-specific WhatsApp consent wiring (#87). #81's live implementation (Firestore wiring, custom-claim issuance, provider configuration, UID association) remains gated on #100 (closed) plus the remaining AUTH-001 Functions/Admin authorization protections noted at 2026-07-14, and stays with the owner.

    Verification still grants no membership or role.

  11. daliu commented on Jul 18, 2026

    @daliu
    ContributorAuthor

    CLAIMED (scoped, source-only) at 2026-07-18T23:56:47Z by agent /root on branch codex/issue-373-claim-reconciliation (child #373).

    Scope of this claim is only the entitlement-to-authorization-claim reconciliation sub-contract as a pure, unused source module (functions/membershipClaimReconciliation.js) delivered as a draft PR for owner review — a design deliverable for #81, not its implementation. It fills the gap that membershipAuthority.js (#208) defers ("custom claims, token refresh/revocation"): given an entitlement disposition + email-verification + the observed member/officer claims, it derives aligned / grant_member / revoke_member fail-closed, encoding #81's "custom claims contain authorization only" and the separation that membership never grants or revokes the officer admin role. Every result carries grantsAuthority: false and officerRoleAffected: false. It writes no claim, mints/revokes no token, is imported by no runtime path, and changes no live behavior.

    This does not claim or complete #81 overall, and does not cover the live custom-claim write/refresh/revocation or token lifecycle (gated on the remaining AUTH-001/AUTH-003 Functions/Admin authorization protections), the officer-role grant path (#115, setMemberRole), or the retention/deletion/SLA matrix (#110). #81's live implementation stays with the owner.

    Verification still grants no membership or role.

  12. daliu commented on Jul 22, 2026

    @daliu
    ContributorAuthor

    Atomic P0 child #445 claimed on branch codex/issue-445-provider-link-lifecycle from exact base 3cbfb9e. Scope: pure, unused, versioned provider-link lifecycle/reconciliation state machine with optimistic revision, idempotent command handling, fail-closed relink/disconnect behavior, focused tests, and named source/future officer design notes. Excludes runtime exports, Firestore/rules, provider calls, migration, deployment, and production behavior. Parent #81 remains open.

  13. daliu commented on Jul 22, 2026

    @daliu
    ContributorAuthor

    Dependency-clearing child #445 merged through PR #446 as exact main commit 3586733. Exact-main CI run 29913889737 passed all five jobs.

    The child now supplies the pure unused provider-link lifecycle snapshot/reducer missing between #367 and future runtime work: canonical changed-command detection, optimistic revision and ordered reconciliation sequence, link/unlink/relink, collision evidence, definitive failure, outcome-unknown, unresolved-intent invalidation, and replacement only after confirmed unlink. Every record/verdict grants no authority, strict typed inputs contain no raw provider/member data, and no runtime imports it.

    #81 remains open. No Firestore schema/Rules, Auth claim, provider call/configuration, persistence, cross-record uniqueness, migration, deployment, production data, or live behavior changed. The automatic PR preview was not a production publication; no protected release ran.

  14. daliu commented on Jul 22, 2026

    @daliu
    ContributorAuthor

    Atomic P0 child #447 claimed by /root at 2026-07-22T11:08:25Z on branch codex/issue-447-consent-receipts from exact main 3586733. Scope is one pure, unused append-oriented consent-decision receipt/head contract that composes #370 and remains technical history only. It excludes policy/legal consent decisions, retention/deletion, actor/capture evidence, persistence, runtime, provider configuration, deployment, and live behavior. Parent #81 remains open.

  15. daliu commented on Jul 22, 2026

    @daliu
    ContributorAuthor

    Dependency-clearing child #447 merged through PR #448 as exact main commit 35240fa84efcda935b88eacbb0685e32aeb8ef10. Exact-main CI run 29916594885 passed all five blocking jobs.

    The child supplies the missing pure, unused append-oriented technical consent-decision receipt/head seam between #370 and future persistence. It is bounded to one latest receipt, detects only current-head conflicts, composes #370 in a separate call, and grants no authority. It explicitly cannot authenticate a self-consistent rewritten head or prove informed/legal consent.

    #81 remains open. No actor/capture evidence, policy/notice text, retention/deletion rule, persistence, durable all-history uniqueness, Firestore schema/Rules, Auth claim/token action, provider call/configuration, migration, deployment, production data, or live behavior changed. The automatic PR preview was not production publication; no protected release ran.

  16. daliu commented on Jul 22, 2026

    @daliu
    ContributorAuthor

    Atomic P0 corrective child #451 claimed by /root at 2026-07-22T12:18:35Z on branch codex/issue-451-term-before-association from exact main 0b9960f. It corrects the pure unused authority reducer so term evidence and explicit UID association may occur in either safe order; unlinked entitlement remains fail-closed. Parent #81 remains open. No runtime, persistence, Rules, migration, provider, deployment, or live behavior is in scope.

  17. daliu commented on Jul 22, 2026

    @daliu
    ContributorAuthor

    Dependency-clearing child #451 merged through PR #452 as exact main commit 937e336031ffe064aa120460327538aab0d45d30. Exact-main CI run 29920636668 passed all five jobs. The pure unused membership authority now supports term-first and link-first ordering while denying every unlinked record; a later one-time UID association preserves the latest term. Parent #81 remains open. No runtime/persistence, cross-record uniqueness, Auth claim, Rules, migration, deployment, provider, production-data, or live behavior changed.

  18. daliu commented on Oct 15, 2026

    @daliu
    ContributorAuthor

    October 15 direct owner decisions for the minimum member release:

    • $25 individual and $30 family, full calendar year.
    • Verified email, accepted waiver and confirmed paid current term suffice; no further discretionary membership approval.
    • Online dues are included in the first launch. Officers retain a private admin dues-confirmation convenience; do not advertise external payment options/instructions publicly.
    • Participating family members have separate verified accounts, share one paid Family ID and do not pay again. A bare Family ID must not grant access; private single-use invitations are the proposed secure enrollment path.
    • Privacy/retention/waiver, including guardian/minor handling, remain undecided. Requested drafts are being prepared, not approved or wired into acceptance.
    • Standing build/deploy authority remains; paid-race checkout/refunds/transfers remain a separate later release. No actual charge, provider, production or real-data action has occurred.

    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.

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

    area:authAuthentication and authorizationarea:firebaseFirebase services and dataarea:membershipMembership lifecycle and reconciliationpriority:P0Launch blocker or urgent security risksize:SSmall focused issuestatus:proposedDesigned but dependencies or decisions remaintype:architectureArchitecture and contract design

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions