MLM Module (Partners, Referrals, Commissions, Ranks)
Overview
The MLM (Multi-Level Marketing) Module is the core business engine of the IWM Platform. It manages the partner network, referral tracking, commission calculations, rank advancement, and payout processing. This module implements a unilevel compensation structure where partners earn commissions from their direct referrals and their downline network.
Responsibilities
- Partner registration and lifecycle management
- Referral link generation and attribution tracking
- Network tree structure management (closure table)
- Rank qualification and progression
- Commission calculation and distribution
- Balance management (pending, available)
- Payout request processing
Domain Entities
Partner
The central entity representing an MLM network member.
| Field | Type | Description |
|---|---|---|
| id | UUID | Partner identifier |
| user_id | UUID | Reference to core.users |
| sponsor_id | UUID | Direct upline partner |
| referral_code | VARCHAR(20) | Unique referral code |
| status | ENUM | Partner status |
| current_rank_id | UUID | Current rank |
| highest_rank_id | UUID | Highest achieved rank |
| direct_referrals_count | INT | Direct downline count |
| total_network_size | INT | Total network size |
| tree_depth | INT | Depth in tree from root |
| joined_at | TIMESTAMP | Registration timestamp |
| activated_at | TIMESTAMP | First qualifying action |
PartnerTreePath
Closure table for efficient tree queries.
| Field | Type | Description |
|---|---|---|
| ancestor_id | UUID | Ancestor partner |
| descendant_id | UUID | Descendant partner |
| depth | INT | Distance between nodes |
ReferralLink
Trackable referral links for attribution.
| Field | Type | Description |
|---|---|---|
| id | UUID | Link identifier |
| partner_id | UUID | Owning partner |
| code | VARCHAR(20) | Unique link code |
| name | VARCHAR(100) | Link label (Instagram, YouTube) |
| target_url | VARCHAR(500) | Custom landing page |
| utm_source | VARCHAR(100) | UTM source parameter |
| utm_medium | VARCHAR(100) | UTM medium parameter |
| utm_campaign | VARCHAR(100) | UTM campaign parameter |
| clicks_count | INT | Total clicks |
| registrations_count | INT | Registrations from link |
| conversions_count | INT | Conversions (purchases/investments) |
| is_active | BOOLEAN | Link active status |
| expires_at | TIMESTAMP | Optional expiration |
ReferralAttribution
Tracks referral source for users.
| Field | Type | Description |
|---|---|---|
| id | UUID | Attribution identifier |
| user_id | UUID | Referred user |
| partner_id | UUID | Referring partner |
| link_id | UUID | Source link (optional) |
| attribution_type | ENUM | FIRST_TOUCH or LAST_TOUCH |
| first_touch_at | TIMESTAMP | First interaction |
| last_touch_at | TIMESTAMP | Last interaction |
| converted_at | TIMESTAMP | Conversion timestamp |
| cookie_id | VARCHAR(100) | Tracking cookie ID |
Rank
MLM rank definitions.
| Field | Type | Description |
|---|---|---|
| id | UUID | Rank identifier |
| name | VARCHAR(100) | Display name |
| code | VARCHAR(50) | Unique code |
| level | INT | Rank level (1 = lowest) |
| description | TEXT | Rank description |
| badge_url | VARCHAR(500) | Rank badge image |
| color_code | VARCHAR(20) | Brand color |
| is_active | BOOLEAN | Rank available |
CommissionPlan
Commission calculation rules.
| Field | Type | Description |
|---|---|---|
| id | UUID | Plan identifier |
| name | VARCHAR(100) | Plan name |
| code | VARCHAR(50) | Unique code |
| source_type | ENUM | INVESTMENT, PRODUCT, ALL |
| max_levels | INT | Maximum depth for commissions |
| is_active | BOOLEAN | Plan active |
| valid_from | TIMESTAMP | Effective start |
| valid_to | TIMESTAMP | Effective end |
CommissionTransaction
Individual commission record.
| Field | Type | Description |
|---|---|---|
| id | UUID | Transaction identifier |
| partner_id | UUID | Receiving partner |
| source_type | ENUM | ORDER, INVESTMENT, BONUS, RANK_BONUS |
| source_id | UUID | Source entity ID |
| source_partner_id | UUID | Partner who generated |
| level_depth | INT | Network level |
| plan_id | UUID | Applied commission plan |
| gross_amount | DECIMAL | Amount before deductions |
| net_amount | DECIMAL | Final amount |
| career_points | DECIMAL | Points earned |
| status | ENUM | Transaction status |
| period_id | VARCHAR(20) | Accounting period |
| idempotency_key | VARCHAR(255) | Duplicate prevention |
PartnerBalance
Partner financial state.
| Field | Type | Description |
|---|---|---|
| id | UUID | Balance identifier |
| partner_id | UUID | Partner reference |
| available_balance | DECIMAL | Withdrawable amount |
| pending_balance | DECIMAL | Awaiting approval |
| total_earned | DECIMAL | Lifetime earnings |
| total_withdrawn | DECIMAL | Lifetime withdrawals |
| career_points_total | DECIMAL | Lifetime points |
| career_points_period | DECIMAL | Current period points |
| currency | VARCHAR(3) | Balance currency |
| version | INT | Optimistic lock version |
PayoutRequest
Withdrawal request from partner.
| Field | Type | Description |
|---|---|---|
| id | UUID | Request identifier |
| partner_id | UUID | Requesting partner |
| amount | DECIMAL | Requested amount |
| currency | VARCHAR(3) | Currency code |
| payout_method_type | ENUM | BANK_CARD, BANK_TRANSFER, EWALLET |
| payout_details | JSONB | Encrypted payment info |
| status | ENUM | Request status |
| rejection_reason | TEXT | If rejected |
| processed_by | UUID | Admin who processed |
| external_reference | VARCHAR(255) | Payment provider reference |
Partner Lifecycle
Registration Flow
Partner Status Flow
Activation Criteria
A partner is activated (PENDING -> ACTIVE) upon:
- First product purchase (minimum order value)
- First investment participation
- Manual admin activation
Referral System
Link Generation
Partners can create multiple referral links for different channels:
UTM Parameter Tracking
Links support full UTM tracking:
| Parameter | Example | Purpose |
|---|---|---|
| utm_source | Traffic source | |
| utm_medium | social | Marketing medium |
| utm_campaign | summer_2024 | Campaign identifier |
Cookie-Based Attribution
Attribution Rules:
- Cookie lifetime: 30 days
- Attribution type: Last-touch (most recent referrer wins)
- Override: New referral link click updates attribution
- Persistence: Attribution locked at conversion (purchase/investment)
Tree Structure
Closure Table Pattern
The partner network uses a closure table for efficient hierarchical queries:
Key Queries
Get Direct Referrals (Level 1):
SELECT descendant_id FROM partner_tree_paths
WHERE ancestor_id = :partner_id AND depth = 1Get Full Downline:
SELECT descendant_id, depth FROM partner_tree_paths
WHERE ancestor_id = :partner_id AND depth > 0
ORDER BY depthGet Upline Chain:
SELECT ancestor_id, depth FROM partner_tree_paths
WHERE descendant_id = :partner_id AND depth > 0
ORDER BY depthGet Network at Specific Levels (for commissions):
SELECT descendant_id FROM partner_tree_paths
WHERE ancestor_id = :partner_id AND depth BETWEEN 1 AND 10Rank System
Rank Hierarchy
Qualification Rules
Ranks have multiple requirement types:
| Requirement Type | Description |
|---|---|
| CAREER_POINTS_TOTAL | Lifetime career points |
| CAREER_POINTS_PERIOD | Points in current period |
| PERSONAL_VOLUME | Personal purchases/investments |
| GROUP_VOLUME | Total network volume |
| DIRECT_REFERRALS | Number of direct recruits |
| ACTIVE_REFERRALS | Active direct recruits |
| TEAM_SIZE | Total network size |
| REFERRALS_AT_RANK | Direct referrals at specific rank |
Qualification Example (Gold Rank)
| Requirement | Threshold | Period |
|---|---|---|
| Career Points | 50,000 | LIFETIME |
| Personal Volume | 10,000 RUB | MONTHLY |
| Group Volume | 100,000 RUB | MONTHLY |
| Direct Referrals | 10 | LIFETIME |
| Active Referrals | 5 | MONTHLY |
Rank Maintenance
- Ranks must be maintained monthly
- Failure to meet requirements results in demotion
- Highest achieved rank preserved for benefits calculation
- Grace period: 1 month warning before demotion
Rank Benefits
| Rank | Commission Bonus | Exclusive Benefits |
|---|---|---|
| Bronze | +2% on levels 1-3 | Basic training access |
| Silver | +3% on levels 1-5 | Monthly webinars |
| Gold | +5% on all levels | Quarterly events |
| Platinum | +7% on all levels | Annual retreat |
| Diamond | +10% on all levels | Leadership council |
Commission Calculation
Unilevel Model
Commissions flow up the network from the source partner:
Commission Tiers
| Level | Base Percentage | With Gold Rank |
|---|---|---|
| 1 | 5% | 10% |
| 2 | 3% | 6% |
| 3 | 2% | 4% |
| 4 | 1% | 2% |
| 5-10 | 0.5% | 1% |
Calculation Flow
Commission Triggers
| Trigger | Source Type | Description |
|---|---|---|
| Order Completed | ORDER | Product purchase delivered |
| Investment Activated | INVESTMENT | Investment participation funded |
| Rank Achievement | RANK_BONUS | One-time rank promotion bonus |
| Period Bonus | BONUS | Monthly/quarterly performance bonus |
Commission Status Flow
Balance Management
Balance Types
Pending vs Available
| Balance | Description | Can Withdraw |
|---|---|---|
| Pending | Commissions awaiting approval | No |
| Available | Approved, withdrawable | Yes |
Holds
Commissions can be placed on hold for:
- Fraud investigation
- Dispute resolution
- Compliance review
Concurrency Safety
Balance operations use optimistic locking with version numbers:
// Example: Withdraw from balance
const result = await updateBalanceOptimistic(
partnerId,
amount,
'WITHDRAW',
expectedVersion
);
if (!result.success) {
if (result.error_message.includes('Version mismatch')) {
// Retry with fresh version
}
}Payout System
Payout Request Flow
Payout Rules
- Minimum Amount: 100 RUB minimum withdrawal
- Single Pending: Only one pending payout per partner
- KYC Required: STANDARD KYC level required
- Balance Deduction: Amount deducted immediately on request
- Failure Refund: Balance restored if payment fails
Payout Methods
| Method | Provider | Processing Time |
|---|---|---|
| Bank Card | Stripe/YooKassa | 1-3 business days |
| Bank Transfer | Manual | 3-5 business days |
| E-Wallet | Various | Same day |
Approval Workflow
Events Published
| Event | Trigger | Payload |
|---|---|---|
| PartnerRegistered | New partner created | partnerId, userId, sponsorId |
| PartnerActivated | First qualifying action | partnerId, activationType |
| PartnerStatusChanged | Status transition | partnerId, fromStatus, toStatus |
| ReferralLinkCreated | New link created | linkId, partnerId, code |
| ReferralLinkClicked | Link visited | linkId, partnerId, visitorInfo |
| ReferralAttributed | User attributed to partner | userId, partnerId, linkId |
| CommissionCalculated | Commission created | transactionId, partnerId, amount |
| CommissionApproved | Commission approved | transactionId, partnerId, amount |
| CommissionPaid | Commission moved to available | transactionId, partnerId, amount |
| CommissionReversed | Commission reversed | transactionId, partnerId, reason |
| BalanceUpdated | Balance changed | partnerId, type, amount, newBalance |
| PayoutRequested | Payout submitted | payoutId, partnerId, amount |
| PayoutApproved | Payout approved | payoutId, partnerId |
| PayoutCompleted | Payout processed | payoutId, partnerId, reference |
| PayoutRejected | Payout rejected | payoutId, partnerId, reason |
| RankChanged | Rank promotion/demotion | partnerId, fromRank, toRank, type |
| RankAchieved | New highest rank | partnerId, rankId, isFirst |
Events Consumed
| Event | Source | Handler |
|---|---|---|
| UserRegistered | Core | Create partner if referral code present |
| OrderCompleted | Commerce | Calculate commissions |
| OrderRefunded | Commerce | Reverse commissions |
| InvestmentActivated | Investment | Calculate commissions |
| InvestmentWithdrawn | Investment | Handle early withdrawal penalties |
Business Rules and Invariants
Partner Rules
- One partner per user (1:1 relationship)
- Partner cannot sponsor themselves
- Sponsor cannot be changed after registration
- Only ACTIVE partners earn commissions
- TERMINATED partners cannot be reactivated
Commission Rules
- Commissions calculated only for ACTIVE upline partners
- Maximum 10 levels of commission depth
- Idempotency key prevents duplicate commissions
- Commissions require admin approval (configurable threshold)
- Reversed/cancelled source reverses all related commissions
Balance Rules
- Available balance cannot be negative
- Pending balance cannot be negative
- Version must match for update (optimistic locking)
- Total earned >= total withdrawn + available + pending
Payout Rules
- Only one pending/processing payout per partner
- Minimum withdrawal amount enforced
- KYC verification required
- Partner must be ACTIVE to request payout
Integration Points
Provides to Other Modules
| Interface | Consumers | Purpose |
|---|---|---|
| IPartnerLookupService | Commerce, Investment | Get partner by referral code |
| ICommissionService | Commerce, Investment | Trigger commission calculation |
| IAttributionService | Commerce, Investment | Get referral attribution for user |
Consumes from Other Modules
| Interface | Provider | Purpose |
|---|---|---|
| IUserLookupService | Core | Get user profile data |
| IKycStatusService | Core | Check KYC level for payouts |