Skip to content

Economy Module — EmojiPay

Location: apps/api/src/modules/economy/

Aggregate roots: EmojiWallet, EmojiPayment (append-only), PostBoost

Feature flag: emoji-pay — must be enabled via admin settings.


Core Concepts

EmojiPay is a mana-based micro-economy that lets users express appreciation for content through emotional resonance. Mana is not real money in Alpha — no fiat conversion until Wave 3.


Wallet

Every user receives an EmojiWallet on registration via the identity.user_registered event.

PropertyValue
Starter balance50 mana
Daily regeneration+5 mana
Regeneration cap50 mana (regen does NOT apply if balance ≥ 50)
Regeneration interval24 hours (last_regen_at guard)

The nightly cron job processes all wallets that are below cap and have last_regen_at older than 24h.

Wallet Fields

typescript
{
  balance: number;        // Current mana
  lifetimeEarned: number; // Total mana received ever
  lifetimeSpent: number;  // Total mana sent ever
  lastRegenAt: Date;      // Guard for regen cadence
}

Emotions

8 canonical emotions on the emotion wheel:

SlugDisplay
loveLove
aweAwe
joyJoy
curiosityCuriosity
gratitudeGratitude
insightInsight
calmCalm
courageCourage

Payment Tiers

6 tiers with different mana costs and reputation requirements:

TierNameManaRep Required*
0Spark10
1Wave30
2Storm1010
3Surge2520
4Tempest5035
5Nova10050

*Rep required = minimum reputation in the post's primary interest. Only enforced when postId is provided (post context).


Payment Flow

mermaid
sequenceDiagram
    participant Sender
    participant API
    participant Receiver

    Sender->>API: POST /economy/pay {postId, emotion, tier}
    Note over API: Validate tier rep threshold<br/>Debit sender wallet<br/>Split across co-authors<br/>Credit receiver(s)
    Note over API: Append-only EmojiPayment row
    API-->>Sender: {payment, senderBalance}
    API->>Receiver: notification (via EventBus)

Co-Author Mana Split

When a post has accepted PostCoAuthor rows, the payment is split:

  • Primary author receives: (100 - sum(accepted splitShare)) % of the mana
  • Each co-author receives their splitShare %
  • Server enforces: total accepted splitShare ≤ 90 (primary always keeps ≥ 10 %)

Example: post with one co-author at splitShare = 30, payment of 10 mana:

  • Co-author receives: 3 mana
  • Primary author receives: 7 mana

Append-Only Ledger

Never UPDATE an emoji_payments row.

Reversals are a new row with reversed: true. The balance re-credit is a separate transaction. This ensures the full payment history is always auditable.


Boost System

Authors can spend mana to boost their post's reach in the feed algorithm.

TierCostScore MultiplierDuration
110 mana×1.524 hours
225 mana×2.048 hours
  • Post.boostScore is the materialised multiplier (0 = not boosted)
  • Post.boostExpiresAt is when the current boost expires
  • A cron job runs to clear expired boosts (set boostScore = 0, boostExpiresAt = null)
  • post_boosts table stores all boost purchases — append-only

Boost API

POST /posts/:id/boost
Body: { tier: 1 | 2 }

EmojiBreakdown

All post listing endpoints include an emojiBreakdown object showing aggregated payments per emotion:

json
{
  "emojiBreakdown": {
    "love": { "count": 12, "total": 45 },
    "curiosity": { "count": 3, "total": 9 },
    "awe": { "count": 1, "total": 10 }
  }
}

API Endpoints

MethodPathDescription
GET/economy/walletMy current wallet state
POST/economy/paySend EmojiPay (body: postId?, replyId?, emotion, tier)
GET/economy/payments?direction=sent|receivedPayment history
GET/economy/payments/:postId/breakdownEmoji breakdown for a post

Admin

The admin Economy page shows:

  • Wallet balances sorted by balance / lifetime earned
  • Recent payment ledger (all transactions)
  • Boost activity log
  • Ability to trigger manual regen for testing

Regulus — invite-only social-knowledge platform