Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Preparing Ring content
Preparing Ring content
Preparing Ring content
Use Founder / Developer tabs in the docs sidebar to filter this page. Activity rewards are on when credit.rewards.enabled is omitted or true. Set false to stop every credit-balance-add award and hide the profile quest widget. Credit purchase, admin/MCP mint, and referral ShareEarn stay independent.
Ring can award credit-balance units when a member completes a real contribution (profile fields, KYC, comments, reviews, requests, approved news). The unit label is credit.creditBalanceUnitLabel (often points). Amounts, role multipliers, and UTC daily caps live in ring-config.json → credit.rewards. This is not on-chain token minting and not the referral rail.
| Surface | When enabled is omitted / true | When enabled is false |
|---|---|---|
enqueueRewardCreditAddEvent | Evaluates per-trigger rules, caps, idempotency | Skips immediately (reason: rewards_disabled) |
| Profile quest widget | Renders on /profile (UserProgressWidget) | Does not render |
| Onboarding KYC hints | /login/onboarding lists earn amounts | Hints empty; lead copy omits earn language |
| Reward toast / celebration | CreditRewardReceivedListener mounted | Listener not mounted |
| Catalog / quest board | Enabled event rules | Empty catalog; no summary query |
| Card credit top-up | Unchanged | Unchanged |
POST /api/mcp/v1/credit/add | Unchanged (explicit confirm: true) | Unchanged |
| Referral ShareEarn / refcodes | Unchanged | Unchanged |
/admin/rewards | Charts historical credit_add_events | Same desk with a disabled banner — no new activity awards |
Contribution rewards are optional clone policy. Some rings want a published quest board; others (for example a store-first overlay) want members to buy credits and never earn them from comments.
Use clone-customization-with-implementer (L3 overlay only). Do not copy ring/web onto the clone.
Set
credit.rewards.enabledtofalseon this clone’s overlayweb/ring-config.jsonat the top of the existingcredit.rewardsobject. Do not forkreward-credit-service.tsorUserProgressWidget. Confirm card top-up,POST /api/mcp/v1/credit/add, and referral ShareEarn stay enabled. Pause for approval before compose or deploy.
Inputs: clone slug, overlay web/ring-config.json already has credit.rewards, operator wants activity awards off.
Confirm the overlay owns credit.rewards
If the clone’s web/ring-config.json already has a credit.rewards block, add "enabled": false there. Compose replaces the whole file — Layer1 "enabled": true will not apply.
If the clone inherits Layer1 config
Add "enabled": false on Layer1 only when every compose of that image should stop awards. Prefer overlay for a single white-label.
Do not disable adjacent rails
Leave CreditAddFsModal, Token Desk, MCP credit add, and refcodes alone. Those paths do not call enqueueRewardCreditAddEvent.
/profile?No. UserProgressWidget returns null and profile-content.tsx does not mount it when isClientCreditRewardsEnabled() is false. Profile hero credit balances still show.
credit_add_events?No new awards. Callers still invoke enqueue; the engine returns { status: 'skipped', reason: 'rewards_disabled' } before DB writes.
enabled?Awards stay on (backward compatible). Layer1 documents "enabled": true explicitly.
No. Presets have no credit.rewards copies and no quest widget.
/admin/rewards go away?No. Admins can still chart history. New contribution awards stop.
No. SSOT is ring-config.json → credit.rewards.enabled. env.local.template has no REWARDS_ENABLED flag.
Depends-on: credit ledger, Token Desk, and card top-up stay independent of this kill switch.
Depends-on: awards stamp `getMainCurrencyCreditAccountingRate` and display `getCreditUnitLabel`.
Same-workflow: `/profile` mounts UserProgressWidget only when rewards are enabled.
Next-step: `/admin/rewards` charts `credit_add_events` for platform admins.
Use Founder / Developer tabs in the docs sidebar to filter this page. Activity rewards are on when credit.rewards.enabled is omitted or true. Set false to stop every credit-balance-add award and hide the profile quest widget. Credit purchase, admin/MCP mint, and referral ShareEarn stay independent.
Ring can award credit-balance units when a member completes a real contribution (profile fields, KYC, comments, reviews, requests, approved news). The unit label is credit.creditBalanceUnitLabel (often points). Amounts, role multipliers, and UTC daily caps live in ring-config.json → credit.rewards. This is not on-chain token minting and not the referral rail.
| Surface | When enabled is omitted / true | When enabled is false |
|---|---|---|
enqueueRewardCreditAddEvent | Evaluates per-trigger rules, caps, idempotency | Skips immediately (reason: rewards_disabled) |
| Profile quest widget | Renders on /profile (UserProgressWidget) | Does not render |
| Onboarding KYC hints | /login/onboarding lists earn amounts | Hints empty; lead copy omits earn language |
| Reward toast / celebration | CreditRewardReceivedListener mounted | Listener not mounted |
| Catalog / quest board | Enabled event rules | Empty catalog; no summary query |
| Card credit top-up | Unchanged | Unchanged |
POST /api/mcp/v1/credit/add | Unchanged (explicit confirm: true) | Unchanged |
| Referral ShareEarn / refcodes | Unchanged | Unchanged |
/admin/rewards | Charts historical credit_add_events | Same desk with a disabled banner — no new activity awards |
Contribution rewards are optional clone policy. Some rings want a published quest board; others (for example a store-first overlay) want members to buy credits and never earn them from comments.
Use clone-customization-with-implementer (L3 overlay only). Do not copy ring/web onto the clone.
Set
credit.rewards.enabledtofalseon this clone’s overlayweb/ring-config.jsonat the top of the existingcredit.rewardsobject. Do not forkreward-credit-service.tsorUserProgressWidget. Confirm card top-up,POST /api/mcp/v1/credit/add, and referral ShareEarn stay enabled. Pause for approval before compose or deploy.
Inputs: clone slug, overlay web/ring-config.json already has credit.rewards, operator wants activity awards off.
Confirm the overlay owns credit.rewards
If the clone’s web/ring-config.json already has a credit.rewards block, add "enabled": false there. Compose replaces the whole file — Layer1 "enabled": true will not apply.
If the clone inherits Layer1 config
Add "enabled": false on Layer1 only when every compose of that image should stop awards. Prefer overlay for a single white-label.
Do not disable adjacent rails
Leave CreditAddFsModal, Token Desk, MCP credit add, and refcodes alone. Those paths do not call enqueueRewardCreditAddEvent.
/profile?No. UserProgressWidget returns null and profile-content.tsx does not mount it when isClientCreditRewardsEnabled() is false. Profile hero credit balances still show.
credit_add_events?No new awards. Callers still invoke enqueue; the engine returns { status: 'skipped', reason: 'rewards_disabled' } before DB writes.
enabled?Awards stay on (backward compatible). Layer1 documents "enabled": true explicitly.
No. Presets have no credit.rewards copies and no quest widget.
/admin/rewards go away?No. Admins can still chart history. New contribution awards stop.
No. SSOT is ring-config.json → credit.rewards.enabled. env.local.template has no REWARDS_ENABLED flag.
Depends-on: credit ledger, Token Desk, and card top-up stay independent of this kill switch.
Depends-on: awards stamp `getMainCurrencyCreditAccountingRate` and display `getCreditUnitLabel`.
Same-workflow: `/profile` mounts UserProgressWidget only when rewards are enabled.
Next-step: `/admin/rewards` charts `credit_add_events` for platform admins.
Use Founder / Developer tabs in the docs sidebar to filter this page. Activity rewards are on when credit.rewards.enabled is omitted or true. Set false to stop every credit-balance-add award and hide the profile quest widget. Credit purchase, admin/MCP mint, and referral ShareEarn stay independent.
Ring can award credit-balance units when a member completes a real contribution (profile fields, KYC, comments, reviews, requests, approved news). The unit label is credit.creditBalanceUnitLabel (often points). Amounts, role multipliers, and UTC daily caps live in ring-config.json → credit.rewards. This is not on-chain token minting and not the referral rail.
| Surface | When enabled is omitted / true | When enabled is false |
|---|---|---|
enqueueRewardCreditAddEvent | Evaluates per-trigger rules, caps, idempotency | Skips immediately (reason: rewards_disabled) |
| Profile quest widget | Renders on /profile (UserProgressWidget) | Does not render |
| Onboarding KYC hints | /login/onboarding lists earn amounts | Hints empty; lead copy omits earn language |
| Reward toast / celebration | CreditRewardReceivedListener mounted | Listener not mounted |
| Catalog / quest board | Enabled event rules | Empty catalog; no summary query |
| Card credit top-up | Unchanged | Unchanged |
POST /api/mcp/v1/credit/add | Unchanged (explicit confirm: true) | Unchanged |
| Referral ShareEarn / refcodes | Unchanged | Unchanged |
/admin/rewards | Charts historical credit_add_events | Same desk with a disabled banner — no new activity awards |
Contribution rewards are optional clone policy. Some rings want a published quest board; others (for example a store-first overlay) want members to buy credits and never earn them from comments.
Use clone-customization-with-implementer (L3 overlay only). Do not copy ring/web onto the clone.
Set
credit.rewards.enabledtofalseon this clone’s overlayweb/ring-config.jsonat the top of the existingcredit.rewardsobject. Do not forkreward-credit-service.tsorUserProgressWidget. Confirm card top-up,POST /api/mcp/v1/credit/add, and referral ShareEarn stay enabled. Pause for approval before compose or deploy.
Inputs: clone slug, overlay web/ring-config.json already has credit.rewards, operator wants activity awards off.
Confirm the overlay owns credit.rewards
If the clone’s web/ring-config.json already has a credit.rewards block, add "enabled": false there. Compose replaces the whole file — Layer1 "enabled": true will not apply.
If the clone inherits Layer1 config
Add "enabled": false on Layer1 only when every compose of that image should stop awards. Prefer overlay for a single white-label.
Do not disable adjacent rails
Leave CreditAddFsModal, Token Desk, MCP credit add, and refcodes alone. Those paths do not call enqueueRewardCreditAddEvent.
/profile?No. UserProgressWidget returns null and profile-content.tsx does not mount it when isClientCreditRewardsEnabled() is false. Profile hero credit balances still show.
credit_add_events?No new awards. Callers still invoke enqueue; the engine returns { status: 'skipped', reason: 'rewards_disabled' } before DB writes.
enabled?Awards stay on (backward compatible). Layer1 documents "enabled": true explicitly.
No. Presets have no credit.rewards copies and no quest widget.
/admin/rewards go away?No. Admins can still chart history. New contribution awards stop.
No. SSOT is ring-config.json → credit.rewards.enabled. env.local.template has no REWARDS_ENABLED flag.
Depends-on: credit ledger, Token Desk, and card top-up stay independent of this kill switch.
Depends-on: awards stamp `getMainCurrencyCreditAccountingRate` and display `getCreditUnitLabel`.
Same-workflow: `/profile` mounts UserProgressWidget only when rewards are enabled.
Next-step: `/admin/rewards` charts `credit_add_events` for platform admins.
Wallet-linked share links mint a different rail — not credit.rewards.
enabled omitted or true. Members see quest progress on /profile and earn within daily caps."enabled": false on the clone overlay web/ring-config.json. The quest widget disappears; store and top-up still work.credit.rewards — compose copies that file as a whole. You must set enabled on the overlay; Layer1’s "enabled": true does not leak through.true| Write path | lib/wallet/reward-credit-service.ts | First-line skip rewards_disabled |
| Catalog | lib/ring-config-chain.ts → getPublicRewardCatalog | [] when disabled |
| Quest board | app/_actions/wallet.ts → getRewardQuestBoard | Empty payload when disabled |
| Widget | features/auth/components/user-progress-widget.tsx | return null when disabled |
| Profile mount | features/auth/components/profile-content.tsx | Conditional render |
| Listener | features/wallet/components/credit-reward-received-listener.tsx | Gated in locale-app-chrome.tsx |
| Profile hooks | lib/wallet/profile-reward-hooks.ts | Still calls enqueue; skip is inside the engine |
Read fallback for event rules (not the kill switch): credit.rewards.events → credit.creditAddEvents → credits.rewards.events.
Per-trigger events.*.enabled still applies when the global flag is on. Global false wins without evaluating triggers.
enqueueRewardCreditAddEvent (lib/wallet/reward-credit-service.ts):
skipped / rewards_disabledenabled, minRole, username, verifiedexistingfloor(base × role multiplier) (minimum 1 if base ≥ 1) + UTC daily capcreditBalanceService.addCredits(..., 'reward_credit_add', getMainCurrencyCreditAccountingRate())appendEvent('reward_credit_add') + notifyRewardCreditReceivedDaily cap skip returns reason: 'daily_cap' and does not write an idempotency_key row (would permanently block a later award). Ledger failures → status failed.
| Idempotency mode | Key | Use |
|---|---|---|
once_per_user | credit_add_event:{trigger}:{userId} | Profile fields, KYC, completion bonus |
once_per_object | …:{objectType}:{objectId} | Comments, reviews, approved news, requests |
Unique index on credit_add_events.idempotency_key prevents races.
| Trigger | Caller |
|---|---|
ringUsername, addedBio, addedLocation, addedWebsite, addedTelegram, addedWhatsapp, profileCompleted | maybeAwardProfileRewards after updateProfile / vitals onboarding |
addedTelegram (OAuth / Mini App link) | features/auth/services/user-resolve.ts |
adminVerify | features/verification/services/admin-manual-user-verification.ts |
newsStoryApproved | features/news/services/news-promotion-workflow.ts (user-authored main-page approval) |
commentCreated | features/comments/services/comment-service.ts |
reviewCreated | app/api/store/products/[id]/reviews/route.ts |
requestCreated | features/opportunities/services/create-opportunity.ts |
Visitors earn nothing when minRole is subscriber (default).
| Surface | Path |
|---|---|
| Console | /admin/rewards (AdminRewardsDashboard, minRole: admin) |
| Stats | GET /api/admin/rewards/stats?range=7d|28d|90d |
| Events | GET /api/admin/rewards/events |
| Per-user | GET /api/admin/rewards/users/[id] |
Disabling awards does not hide this desk. Historical rows remain.
Layer2 packs (ring-presets/) do not copy reward chrome. Clone TS overlays do not copy UserProgressWidget; compose delivers Layer1. Only overlay ring-config.json files that already contain a credit.rewards object need the enabled key.
See-also: referral token minting is a separate rail from credit.rewards.
Wallet-linked share links mint a different rail — not credit.rewards.
enabled omitted or true. Members see quest progress on /profile and earn within daily caps."enabled": false on the clone overlay web/ring-config.json. The quest widget disappears; store and top-up still work.credit.rewards — compose copies that file as a whole. You must set enabled on the overlay; Layer1’s "enabled": true does not leak through.true| Write path | lib/wallet/reward-credit-service.ts | First-line skip rewards_disabled |
| Catalog | lib/ring-config-chain.ts → getPublicRewardCatalog | [] when disabled |
| Quest board | app/_actions/wallet.ts → getRewardQuestBoard | Empty payload when disabled |
| Widget | features/auth/components/user-progress-widget.tsx | return null when disabled |
| Profile mount | features/auth/components/profile-content.tsx | Conditional render |
| Listener | features/wallet/components/credit-reward-received-listener.tsx | Gated in locale-app-chrome.tsx |
| Profile hooks | lib/wallet/profile-reward-hooks.ts | Still calls enqueue; skip is inside the engine |
Read fallback for event rules (not the kill switch): credit.rewards.events → credit.creditAddEvents → credits.rewards.events.
Per-trigger events.*.enabled still applies when the global flag is on. Global false wins without evaluating triggers.
enqueueRewardCreditAddEvent (lib/wallet/reward-credit-service.ts):
skipped / rewards_disabledenabled, minRole, username, verifiedexistingfloor(base × role multiplier) (minimum 1 if base ≥ 1) + UTC daily capcreditBalanceService.addCredits(..., 'reward_credit_add', getMainCurrencyCreditAccountingRate())appendEvent('reward_credit_add') + notifyRewardCreditReceivedDaily cap skip returns reason: 'daily_cap' and does not write an idempotency_key row (would permanently block a later award). Ledger failures → status failed.
| Idempotency mode | Key | Use |
|---|---|---|
once_per_user | credit_add_event:{trigger}:{userId} | Profile fields, KYC, completion bonus |
once_per_object | …:{objectType}:{objectId} | Comments, reviews, approved news, requests |
Unique index on credit_add_events.idempotency_key prevents races.
| Trigger | Caller |
|---|---|
ringUsername, addedBio, addedLocation, addedWebsite, addedTelegram, addedWhatsapp, profileCompleted | maybeAwardProfileRewards after updateProfile / vitals onboarding |
addedTelegram (OAuth / Mini App link) | features/auth/services/user-resolve.ts |
adminVerify | features/verification/services/admin-manual-user-verification.ts |
newsStoryApproved | features/news/services/news-promotion-workflow.ts (user-authored main-page approval) |
commentCreated | features/comments/services/comment-service.ts |
reviewCreated | app/api/store/products/[id]/reviews/route.ts |
requestCreated | features/opportunities/services/create-opportunity.ts |
Visitors earn nothing when minRole is subscriber (default).
| Surface | Path |
|---|---|
| Console | /admin/rewards (AdminRewardsDashboard, minRole: admin) |
| Stats | GET /api/admin/rewards/stats?range=7d|28d|90d |
| Events | GET /api/admin/rewards/events |
| Per-user | GET /api/admin/rewards/users/[id] |
Disabling awards does not hide this desk. Historical rows remain.
Layer2 packs (ring-presets/) do not copy reward chrome. Clone TS overlays do not copy UserProgressWidget; compose delivers Layer1. Only overlay ring-config.json files that already contain a credit.rewards object need the enabled key.
See-also: referral token minting is a separate rail from credit.rewards.
Wallet-linked share links mint a different rail — not credit.rewards.
enabled omitted or true. Members see quest progress on /profile and earn within daily caps."enabled": false on the clone overlay web/ring-config.json. The quest widget disappears; store and top-up still work.credit.rewards — compose copies that file as a whole. You must set enabled on the overlay; Layer1’s "enabled": true does not leak through.true| Write path | lib/wallet/reward-credit-service.ts | First-line skip rewards_disabled |
| Catalog | lib/ring-config-chain.ts → getPublicRewardCatalog | [] when disabled |
| Quest board | app/_actions/wallet.ts → getRewardQuestBoard | Empty payload when disabled |
| Widget | features/auth/components/user-progress-widget.tsx | return null when disabled |
| Profile mount | features/auth/components/profile-content.tsx | Conditional render |
| Listener | features/wallet/components/credit-reward-received-listener.tsx | Gated in locale-app-chrome.tsx |
| Profile hooks | lib/wallet/profile-reward-hooks.ts | Still calls enqueue; skip is inside the engine |
Read fallback for event rules (not the kill switch): credit.rewards.events → credit.creditAddEvents → credits.rewards.events.
Per-trigger events.*.enabled still applies when the global flag is on. Global false wins without evaluating triggers.
enqueueRewardCreditAddEvent (lib/wallet/reward-credit-service.ts):
skipped / rewards_disabledenabled, minRole, username, verifiedexistingfloor(base × role multiplier) (minimum 1 if base ≥ 1) + UTC daily capcreditBalanceService.addCredits(..., 'reward_credit_add', getMainCurrencyCreditAccountingRate())appendEvent('reward_credit_add') + notifyRewardCreditReceivedDaily cap skip returns reason: 'daily_cap' and does not write an idempotency_key row (would permanently block a later award). Ledger failures → status failed.
| Idempotency mode | Key | Use |
|---|---|---|
once_per_user | credit_add_event:{trigger}:{userId} | Profile fields, KYC, completion bonus |
once_per_object | …:{objectType}:{objectId} | Comments, reviews, approved news, requests |
Unique index on credit_add_events.idempotency_key prevents races.
| Trigger | Caller |
|---|---|
ringUsername, addedBio, addedLocation, addedWebsite, addedTelegram, addedWhatsapp, profileCompleted | maybeAwardProfileRewards after updateProfile / vitals onboarding |
addedTelegram (OAuth / Mini App link) | features/auth/services/user-resolve.ts |
adminVerify | features/verification/services/admin-manual-user-verification.ts |
newsStoryApproved | features/news/services/news-promotion-workflow.ts (user-authored main-page approval) |
commentCreated | features/comments/services/comment-service.ts |
reviewCreated | app/api/store/products/[id]/reviews/route.ts |
requestCreated | features/opportunities/services/create-opportunity.ts |
Visitors earn nothing when minRole is subscriber (default).
| Surface | Path |
|---|---|
| Console | /admin/rewards (AdminRewardsDashboard, minRole: admin) |
| Stats | GET /api/admin/rewards/stats?range=7d|28d|90d |
| Events | GET /api/admin/rewards/events |
| Per-user | GET /api/admin/rewards/users/[id] |
Disabling awards does not hide this desk. Historical rows remain.
Layer2 packs (ring-presets/) do not copy reward chrome. Clone TS overlays do not copy UserProgressWidget; compose delivers Layer1. Only overlay ring-config.json files that already contain a credit.rewards object need the enabled key.
See-also: referral token minting is a separate rail from credit.rewards.