---
title: "Refcodes architecture"
description: "Attribution cookies, visit analytics, checkout UX, PostgreSQL ledger, ReferralRewards UUPS minter, and dual-rail PaymentConductor integration"
locale: "en"
---
# Refcodes architecture

> **Info**
> **Dual-rail:** Token minting (this document) pairs with ERP `settlements` referral commission on the same `orderReference`. Overview: [Affiliate enablement](/docs/features/affiliate-enablement.md).

## System diagram

```mermaid
flowchart TB
    subgraph Edge["Edge / proxy.ts"]
        RefParam["?ref=CODE"]
        Cookie["ring_ref + ring_ref_visible"]
        Beacon["ReferralAttributionEffect"]
        Track["POST /api/refcodes/track"]
    end

    subgraph Checkout["Store checkout"]
        Badge["ReferralCheckoutBadge"]
        Flash["checkout-referral-flash sessionStorage"]
    end

    subgraph API["App API"]
        Orders["POST /api/store/orders"]
        Credit["POST /api/store/payments/credit"]
        RefAPI["GET /api/refcodes"]
        AdminMint["POST /api/refcodes/mint"]
        CronMint["GET /api/cron/refcodes-mint"]
    end

    subgraph Services["features/refcodes/services"]
        RefcodeSvc["RefcodeService"]
        AttrSvc["attribution-service"]
        RewardSvc["ReferralRewardService"]
        Minter["reward-minter"]
        VisitLib["visit-analytics.ts"]
    end

    subgraph Payments["lib/payments/conductor"]
        WFP["handleStoreWayForPayWebhook"]
        Mem["membership-upgrade handler"]
        ERP["settlement-pipeline"]
    end

    subgraph Data["PostgreSQL ring_platform"]
        RefTable["refcodes visits + visitDaily"]
        RewardTable["referral_rewards"]
        OrdersTable["orders"]
        Settle["settlements + erp_sales_assists"]
    end

    subgraph Chain["Polygon"]
        Contract["ReferralRewards UUPS proxy"]
        Token["IMintableERC20 reward token"]
    end

    RefParam --> Cookie
    Cookie --> Beacon --> Track --> RefTable
    Cookie --> Badge
    Cookie --> Orders
    Orders --> Flash
    Orders --> AttrSvc
    AttrSvc --> RefcodeSvc
    Orders --> OrdersTable
    WFP --> RewardSvc
    WFP --> ERP --> Settle
    Credit --> RewardSvc
    Credit --> ERP
    Mem --> RewardSvc
    RewardSvc --> RewardTable
    RewardSvc --> Minter
    AdminMint --> Minter
    CronMint --> Minter
    Minter --> Contract
    Contract --> Token
    RefAPI --> RefcodeSvc
    RefcodeSvc --> RefTable
    VisitLib --> RefTable
```

## Core modules

| Module | Path | Responsibility |
|--------|------|----------------|
| Cookie capture | `proxy.ts` | First-touch `ring_ref` from `?ref=` |
| Code registry | `refcode-service.ts` | CRUD codes per `(userId, wallet)` |
| Attribution | `attribution-service.ts` | Self-ref, first-purchase, wallet overlap guards |
| Reward ledger | `referral-reward-service.ts` | Fiat/credit paths, approval, oracle sizing |
| On-chain mint | `reward-minter.ts` | viem `simulateContract` + `writeContract` |
| Server wallet | `lib/web3/server-wallet.ts` | `REFERRAL_MINTER_PRIVATE_KEY` → viem account |

## Integration points

### Store order creation

`app/api/store/orders/route.ts` resolves attribution before `StoreOrdersService.createOrder`. Referral fields are stored in the `orders` JSONB document:

- `referralCode`
- `referrerUserId`
- `referrerWallet`

### PaymentConductor (fiat)

`lib/payments/conductor/handlers/store-order.ts` calls `ReferralRewardService.onOrderPaid` inside the `Approved` + `isNew` branch — after stock deduction and vendor settlement. Failures are logged but do not fail the webhook.

### Internal credit (instant)

`app/api/store/payments/credit/route.ts` marks the order paid, deducts stock, writes `settlements` via `settlement-pipeline.ts`, then calls `onOrderPaid` with `rail: 'crypto'` (auto-approved mint).

### Membership (fiat)

`handlers/membership-upgrade.ts` → `ReferralRewardService.onMembershipPaid` when `users.data.referredBy` is set (first-touch signup attribution).

### Cron, visits, and checkout

| Endpoint / component | Role |
|----------------------|------|
| `POST /api/refcodes/track` | `trackRefcodeVisit` — bumps `visits` + `visitDaily[UTC date]` (28-day prune) |
| `ReferralAttributionEffect` | Public layout client beacon when `ring_ref_visible` is set |
| `ReferralCheckoutBadge` | Review step reads `ring_ref_visible` |
| `checkout-referral-flash.ts` | WayForPay redirect toast survival (30 min TTL) |
| `GET /api/cron/refcodes-mint` | `processApprovedRewards(20)` — `Authorization: Bearer $CRON_SECRET` |

### Mint notification (i18n)

After on-chain success, `reward-minter.ts` loads copy via `lib/i18n/refcodes-labels.ts`:

1. `getUserPreferredLocaleForNotifications(referrerUserId)` — `users.settings.language` (DB-only, smoke-safe).
2. `getReferralMintNotificationCopy(locale, { amount, token })` — `modules/refcodes.json` → `notifications.minted`.
3. `createNotification` with type `REFERRAL_REWARD_MINTED`.

## Idempotency

| Layer | Key |
|-------|-----|
| PostgreSQL | Unique index on `referral_rewards (data->>'orderReference')` |
| Service | `rewardExistsForOrder` short-circuit |
| Contract | `paidOrders[orderRef]` mapping — reverts `ReferralRewards__AlreadyPaid` |

`orderRef` on-chain = `keccak256(bytes(orderReference))` where `orderReference` comes from PaymentConductor.

## Contract roles

```
initialize(admin, operator, token, mode)
  ├─ DEFAULT_ADMIN_ROLE → admin (upgrade, pause, setRewardToken/Mode)
  └─ OPERATOR_ROLE      → operator (payReferral)

MINT mode: token must authorize proxy to mint
TRANSFER mode: contract must hold token balance (treasury-funded)
```

## i18n

| Surface | Bundle keys |
|---------|-------------|
| User/admin UI | `locales/{en,uk,ru}/modules/refcodes.json` — visits, stats, admin queue |
| Checkout toast | `modules/store.json` → `checkout.referralApplied*` |
| Mint notification | `modules/refcodes.json` → `notifications.minted` (server via `refcodes-labels.ts`) |

- Scope: `modRefcodes` in `lib/i18n/message-scopes.ts` (authenticated + admin)
- Routes: `REFCODES`, `ADMIN_REFCODES` in `constants/routes.ts`

## Database placement

| Environment | Database | Notes |
|-------------|----------|-------|
| ring-platform.org dev | `ring_platform` | Homebrew Postgres (`bootstrap-brew-dev.sh`) or Docker `ring-postgres-dev` |
| ring-platform.org prod | `ring_platform` | `postgres.ring-platform-org.svc.cluster.local` |
| ring-connect-software | `ring_connect_software_dev` / prod name | Separate clone DB |
| ring-ringdom-org | `ring_ringdom_org` | Separate clone DB |

Migration file: `data/migrations/005_refcodes_schema.sql`.

## Related

- [Feature: Referral Codes](/docs/features/refcodes.md)
- [Affiliate enablement](/docs/features/affiliate-enablement.md) — dual-rail audit and operator checklist
- [ERP commissions](/docs/features/erp/commissions.md) — vendor-funded rail
- [PaymentConductor architecture](/docs/architecture/payment-conductor.md)
- [Proxy and i18n](/docs/architecture/proxy-and-intl.md)
