Skip to content

MEMBERS-ADMIN-001 — Add audited officer membership association and manual activation #115

Description

@daliu

Officer impact: An authorized officer can confirm dues and deliberately connect a paid membership to a verified website account without editing Firestore or toggling a raw role. Every action has an actor, reason, source, and result.

Officer documentation: Update OFFICER_START_HERE.md, docs/officers/EVENTS_SHOP_MEMBERS.md, docs/officers/ACCESS_CONTINUITY.md, docs/officers/SYSTEM_MAPS.md and its text alternative, and the glossary in the implementation pull request.

Deployment evidence: None at issue creation. Closure requires emulator tests, merged source, frontend publication and runmprc.com verification, Firebase Functions/Rules deployment evidence, staged operator evidence, and an approved backup-officer walkthrough. Until then this workflow is NOT AVAILABLE YET.

Product decision

MPRC will initially onboard members manually as they create accounts. A membership may also be recorded against a pre-existing contact email before an account exists. The final connection to an account must be explicit, officer-confirmed, and based on authoritative payment/membership evidence—not automatic email matching.

Problem

The current Admin Members page directly lists members/{uid} and offers buttons that change unverified, member, and admin roles by email. It has no annual term, dues/payment evidence, membership record, scoped membership capability, recent-auth requirement, stable command ID, durable audit, or collision workflow. A role toggle cannot safely represent paid annual membership.

Atomic outcome

Build a scoped server workflow that:

  1. records approved manual/off-platform dues evidence for a membership term when policy permits;
  2. associates an existing membership record with an authoritative Firebase UID only after explicit review; and
  3. derives/refreshes or revokes the account's membership entitlement from the resulting current membership state.

Manual payment recording and identity association are separate commands, even if one authorized officer performs both in sequence.

Required behavior

  • Membership records use a stable non-email ID and may remain unlinked until the person creates an account.
  • A confidential contact email can help officers locate candidates, but it is not an authorization key or document ID.
  • The server reads authoritative Firebase Auth state. Association requires a verified account email and an explicit officer selection of both the membership and UID.
  • A unique normalized-email match may be shown as a suggestion only. It never auto-links, auto-creates an Auth user, grants a role, or resolves a collision silently.
  • Separate minimum capabilities govern payment confirmation, membership association, and privileged-role administration. A generic browser admin role is not sufficient long-term.
  • Sensitive actions require MFA/recent authentication under AUTH-003 and a stable idempotent command ID.
  • Every command records actor UID/capability, membership ID, target UID, source/evidence category, term, reason, prior/new state, timestamp, result, and safe correlation ID in append-oriented server-only audit records.
  • Do not store screenshots, bank details, payment credentials, raw provider payloads, or arbitrary notes as evidence.

Acceptance criteria

  • An officer can record an owner-approved off-platform payment confirmation without creating or claiming a Stripe payment.
  • An officer can associate an active paid membership to an existing verified Auth account and preserve its UID/data.
  • A paid membership can remain safely unlinked before account creation and appear in a bounded officer review queue.
  • Missing account, unverified email, duplicate account, duplicate/contact-email collision, changed email, already-linked membership, UID already linked elsewhere, household overlap, wrong term, lapsed/suspended membership, and stale command all stop or enter explicit review.
  • Repeating the same command returns the same result; a conflicting payload with the same command ID is rejected.
  • No public response reveals whether an email, membership, or Auth account exists.
  • Association does not fabricate payment state and payment confirmation does not silently associate an account.
  • Member access/custom claims are derived only after the canonical membership transition succeeds; failures cannot leave claim/profile/membership state silently divergent.
  • Lapse, suspension, unlink, corrected association, and offboarding have idempotent undo/recovery paths and safe token refresh/revocation.
  • The club account may act only if it signs in as a verified Firebase identity deliberately granted the same scoped capability and MFA/recent-auth requirements as named officers; the email address itself is never an allowlist bypass.
  • Synthetic positive/negative/emulator tests cover every state above without contacting production or using real member/payment data.
  • A backup officer can complete the current, approved path from the website with no terminal, source edit, shared password, secret, or direct database mutation.

Dependencies and coordination

Explicitly out of scope

  • Bulk Forms/Sheets/Firebase import or automatic linking by email.
  • Creating Auth accounts, setting passwords, sharing login credentials, or sending unsolicited invites.
  • Annual checkout/webhook implementation, recurring subscriptions, pricing/policy decisions, or payment-provider reconciliation.
  • Admin-role grants, Google/WhatsApp/Strava/Instagram provisioning, or roster export.
  • Production/manual Firestore edits, real payment tests, or storing sensitive evidence.

Claim protocol

Creation is not a claim. Do not edit implementation files until dependencies are complete, the issue is assigned, and a timestamped CLAIMED by <canonical agent> at <UTC>; branch <branch> comment is posted and re-read. Earliest valid claim wins. External account, policy, and production actions remain owner-only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:adminAdministrative workflowsarea:authAuthentication and authorizationarea:firebaseFirebase services and dataarea:membershipMembership lifecycle and reconciliationpriority:P0Launch blocker or urgent security risksize:MMedium multi-file issuestatus:proposedDesigned but dependencies or decisions remaintype:featureProduct capabilitytype:securitySecurity or privacy boundary

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions