Skip to content

Contribution Module

Location: apps/api/src/modules/contribution/

Aggregate roots: ContributionEvent, ContributionSnapshot

The Contribution context tracks a holistic activity score per user. It uses an append-only ledger with a materialised snapshot. After each event, it propagates a partial score up the invite tree (50%/25%/10% to direct parent/grandparent/great-grandparent).


Score Deltas

KindDeltaTrigger Event
post_created+10posts.created
reply_created+3posts.replied
reaction_given+1posts.reacted
bookmark_given+1posts.bookmarked
emoji_pay_sent+2economy.payment.sent

Prisma Models

ModelTableNotes
ContributionEventcontribution_eventsAppend-only; delta ≥ 0 for positive, negative for reversal
ContributionSnapshotcontribution_snapshotsMaterialised total per user

ContributionEvent Fields

FieldTypeNotes
idUUID PK
userIdUUID
kindString (40)See deltas table
deltaIntAlways positive; reversals use negative delta
refIdUUID?Audit reference (postId, replyId, etc.)
createdAtDateTime

Indexes: (userId, createdAt), createdAt

ContributionSnapshot Fields

FieldTypeNotes
userIdUUID PK
totalIntRolled-up sum
updatedAtDateTime

Key Methods

MethodDescription
record(userId, kind, refId?)Append event + increment snapshot; fire invite-tree inheritance
getScore(userId)Return snapshot total
getLeaderboard(limit)Top users by total score
recomputeSnapshot(userId)Admin: recompute from ledger (fixes drift)

Invite-Tree Inheritance

After each record(), the service propagates score up the invite tree using INHERIT_RATIOS = [0.5, 0.25, 0.1]:

Ancestor LevelFraction of delta
Direct inviter (depth 1)50%
Inviter's inviter (depth 2)25%
Depth 310%

Example: User creates a post (+10). Their inviter receives +5, their inviter's inviter receives +2.

This means the quality of who you invite into the platform affects your own contribution score.


Nightly Reconciliation

A @Cron(EVERY_DAY_AT_2AM) job recomputes all snapshots from the ledger SUM(delta) grouped by userId. This corrects any incremental drift from race conditions.


HTTP Endpoints

All under /api/v1/contribution/. Require JwtAuthGuard.

MethodPathDescription
GET/contribution/meMy score + rank
GET/contribution/leaderboardTop contributors ?limit=20
GET/contribution/users/:idAnother user's score (public)

Regulus — invite-only social-knowledge platform