ZyncDocs · ZyncGold ERP · Modules · Membership (detailed)
Must Should Could
Detailed Functional Requirements

Membership — Detailed Requirements

The deep specification for the customer loyalty membership module — expanding the module summary into a full data model, testable requirements with acceptance criteria, status lifecycles, business rules, and known gaps. Members are organised into tiers; each qualifying purchase records a reward as a double-entry ledger pair, and confirmed reward points automatically promote the member to the highest tier they qualify for. Derived from the live membership module.

3
Entities
12
Requirements
4
Concerns

Tier products

Loyalty tiers with a points threshold, reward multiplier, benefits, and branding.

Enrolment

A customer's membership record, its tier, and resolved points / amount spent.

Reward transactions

Double-entry reward postings tied to the sale that earned them.

Auto-upgrade

Confirmed points promote a member to the highest tier they qualify for.

Membership · Detailed

Data model

Three entities: the tier product, the customer enrolment, and the reward transaction (which extends the finance ledger's account-transaction).

MembershipType tier product
FieldTypeNotes
namestringTier display name.
iconstringIcon URL/identifier.
level keynumberTier rank; lowest level = entry tier. Drives ordering and the upgrade selection.
points keynumber (default 0)Qualifying threshold — minimum confirmed points to hold this tier.
multiplier keynumberPoints per currency unit: pointsGained = floor(amount × multiplier).
terms, descriptionstringTerms and description text.
primaryColor, secondaryColorstringTier branding colours.
benefitsstring[]List of benefit lines.
membershipAccountId keyObjectId → AccountGL account credited when a reward is recorded.
fromAmount, toAmountnumberunused Stored but never queried (intended spend range).
cashAccountIdObjectId → Accountunused Defined but never accessed in code.
UserMembership enrolment
FieldTypeNotes
userIdObjectId → UserThe customer.
membershipTypeIdObjectId → MembershipTypeThe currently held tier.
statusenum (default ACTIVE)ACTIVE / INACTIVE / EXPIRED / SUSPENDED.
points resolvednumberΣ pointsGained of CONFIRMED DEBIT reward entries.
next resolvedMembershipTypeFirst tier whose threshold exceeds the member's total points.
pointsValue resolvednumberpoints × 0.01 (conversion rate hardcoded).
amountSpent resolvednumberΣ amount of CONFIRMED DEBIT reward entries.
UserMembershipTransaction reward

Extends the finance AccountTransaction; rewards are posted as two linked rows.

FieldTypeNotes
userMembershipIdObjectId → UserMembershipThe enrolment being rewarded.
invoiceIdObjectId → InvoiceOriginating sales invoice (optional).
amountnumberReward base amount.
pointsGained computednumber (default 0)floor(amount × tier.multiplier).
statusenum (default PENDING)PENDING / CONFIRMED / REJECTED.
confirmedAt, confirmedBynumber, ObjectId → UserSet when confirmed.
accountId, type, kind, relationIdinheritedDEBIT customer account; CREDIT membership account; kind = MembershipTransaction; shared relationId links the pair.
weight, ratenumberunused Stored but never read.

Membership · Detailed

Tier products MMB-T

Administrators define the loyalty tiers — each a threshold (points), a reward rate (multiplier), benefits, branding, and a linked GL account.

FR-MMB-T01Must
The system SHALL allow administrators to create, update, soft-delete, query, and paginate membership tier products, each carrying name, icon, level, points threshold, reward multiplier, terms, description, branding colours, benefits, and a linked membership account.
Acceptance criteria
  • Create accepts all fields; points defaults to 0 when omitted.
  • Update is partial (any subset of fields).
  • Delete is a soft delete — the record is retained and excluded from normal queries.
  • List paginates (default 20 per page) and filters by keyword, level, or an ids array.
FR-MMB-T02Must
On creation of the first tier, the system SHALL auto-enrol every existing customer who has no membership into that tier with ACTIVE status.
Acceptance criteria
  • Creating the first MembershipType assigns each unassigned customer a UserMembership(ACTIVE) pointing to it.
  • Subsequent tier creations do not re-assign existing members.
FR-MMB-T03Should
The system SHALL treat the tier with the lowest level as the entry tier and use level ordering to resolve tier progression.
Acceptance criteria
  • The "first tier" lookup returns the tier with the lowest level.
  • Upgrade eligibility is evaluated against tiers sorted by level ascending.

Membership · Detailed

Enrolment MMB-E

A customer's membership record — which tier they hold and the resolved points and spend that drive upgrades.

FR-MMB-E01Must
The system SHALL allow staff to enrol a customer into a tier and to update, soft-delete, query, and paginate enrolments; a new enrolment SHALL default to ACTIVE.
Acceptance criteria
  • Create requires userId and membershipTypeId; status defaults to ACTIVE.
  • Update may change the tier, status, or user.
  • Listing resolves the linked customer and tier for display.
FR-MMB-E02Must
The system SHALL expose, per enrolment, the resolved current tier, the next qualifying tier, the total confirmed points, the point value, and the amount spent.
Acceptance criteria
  • points = Σ pointsGained of the member's CONFIRMED DEBIT reward entries.
  • next = the first tier whose threshold is greater than the member's total points.
  • pointsValue = points × 0.01.
  • amountSpent = Σ amount of CONFIRMED DEBIT reward entries.
FR-MMB-E03Should
An enrolment's status SHALL be one of ACTIVE, INACTIVE, EXPIRED, or SUSPENDED, changed administratively.
Acceptance criteria
  • Status is settable via update.
  • No automatic expiry or suspension is applied (see Known gaps).

Membership · Detailed

Reward transactions MMB-R

Each reward is a balanced double-entry ledger pair, tied to the sale that earned it, that accrues points once confirmed.

Posting

LegPostingShared
RewardDR Customer account (input)
CR Membership account (tier's membershipAccountId)
same amount, same relationId, kind = MembershipTransaction, invoiceId
FR-MMB-R01Must
The system SHALL record a loyalty reward as a balanced pair of ledger entries sharing one relation id — a DEBIT to the supplied customer account and a CREDIT to the tier's membership account — both tagged kind = MembershipTransaction and optionally linked to the originating sales invoice.
Acceptance criteria
  • Creating a reward posts exactly two entries: DEBIT to the input accountId, CREDIT to tier.membershipAccountId.
  • Both rows carry the same amount, the same generated relationId, and the same invoiceId.
  • The DEBIT entry is returned to the caller.
FR-MMB-R02Must
The system SHALL compute points earned as floor(amount × tier.multiplier) and store it on the reward entries; on an amount change it SHALL recompute from the enrolment's current tier multiplier.
Acceptance criteria
  • On create, pointsGained = floor(amount × multiplier) on both legs.
  • Updating the amount recomputes pointsGained from the enrolment's tier.
FR-MMB-R03Must
A reward transaction SHALL move through PENDINGCONFIRMED (or REJECTED); only CONFIRMED entries SHALL count toward points and tier eligibility.
Acceptance criteria
  • A new reward defaults to PENDING.
  • Confirming records confirmedAt / confirmedBy.
  • Only CONFIRMED DEBIT entries are summed for points / spend; REJECTED are excluded and not reversed.
FR-MMB-R04Must
The system SHALL reject a reward whose enrolment — or that enrolment's tier — does not exist, with a specific error.
Acceptance criteria
  • Missing/invalid userMembershipId → error "UserMembership not found".
  • Enrolment with no resolvable tier → error "MembershipType not found".

Membership · Detailed

Auto-upgrade MMB-U

Confirming a reward re-evaluates the member's tier and promotes them to the highest tier their confirmed points qualify for.

FR-MMB-U01Must
When a reward becomes CONFIRMED (on create with that status, or on a PENDING → CONFIRMED update), the system SHALL promote the member to the highest-level tier whose points threshold their total confirmed points meet.
Acceptance criteria
  • Trigger: a reward created as CONFIRMED, or transitioned PENDING → CONFIRMED.
  • totalPoints = Σ pointsGained of all CONFIRMED DEBIT entries for the enrolment.
  • Eligible tiers = those where tier.points ≤ totalPoints, sorted by level; the chosen tier is the highest-level eligible one.
  • If the chosen tier differs from the current one, membershipTypeId is updated.
FR-MMB-U02Must
The system SHALL NOT downgrade a member automatically; when no tier qualifies, or the member already holds the best qualifying tier, it SHALL leave the tier unchanged.
Acceptance criteria
  • No eligible tier (total below the lowest threshold) → no change.
  • Member already on the best eligible tier → no change.
  • Promotion is only ever upward.

Membership · Detailed

Statuses & key values

Enrolment status

ACTIVEINACTIVEEXPIREDSUSPENDED

Reward transaction status

PENDINGCONFIRMEDREJECTED

Ledger

type: DEBIT / CREDITkind: MembershipTransactionpointsValue rate: 0.01

Membership · Detailed

Business rules

  • Every reward is a balanced double-entry pair (DEBIT cash / CREDIT membership account) sharing one relationId.
  • Points and amount-spent are evaluated only against CONFIRMED DEBIT reward entries.
  • Tier promotion is to the highest qualifying tier by level, never just the next one up, and never downward.
  • The lowest-level tier is the entry tier and is auto-assigned to unassigned customers when the first tier is created.
  • Deletes are soft across all three entities (records are retained).

Membership · Detailed

Known gaps & risks

High — Tiers (MembershipType) and enrolments (UserMembership) are not company-scoped — they are global — while reward transactions are scoped per company. A member can therefore accrue points in one company against a globally-shared enrolment, allowing cross-company anomalies.
High — The reward's two ledger legs are posted in parallel (not wrapped in a single database transaction). If the CREDIT fails after the DEBIT succeeds, the ledger can be left with an orphaned, unbalanced entry.
Medium — No uniqueness on tier name or level; duplicate levels are resolved by "last in the sorted list wins", which is deterministic but undocumented.
Medium — Nothing prevents a customer from holding multiple ACTIVE memberships at once.
Medium — The EXPIRED and SUSPENDED statuses exist but are never set automatically — there is no expiry/validity job.
Low — fromAmount, toAmount, cashAccountId, and the transaction's weight / rate are stored but never used.
Low — The pointsValue conversion rate is hardcoded at 0.01 rather than configurable.
Low — No validation that invoiceId or the linked account ids reference real records.