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. audience frontmatter controls in-page blocks; sidebar visibility is curated in lib/docs/audience-curated-docs.ts.
MVP-A ships Solana Metaplex Core gate NFTs for membership and vendor unlocks. Buyers pay primary sale with the clone native token (RING on this tree), stake into GateEscrow (not NATIVE_NFT_APR), and GateResolver.hasFeature unlocks product surfaces. Tradeable vendor gates can now list in the NFT Exhibition Marketplace, but a bought gate must still be staked before features activate.
| Concern | Truth |
|---|---|
| Mint SSOT | Metaplex Core (createCollection / create / fetchAsset) |
| Stake SSOT | GateEscrow DB + optional program id — not Ring staking APR |
| Primary sale | RING transferChecked then mint (features/nft-gates/purchase.ts) |
| User surface | /nft/gates |
| Secondary surface | /nft/market, /nft/market/[listingId], /nft/market/sell |
| Admin | /admin/nft/templates, /admin/nft/mint |
| Subscription provider | nft_gate → nftGateSubscriptionProvider |
| Schema | data/migrations/029_nft_gates_schema.sql |
| Marketplace schema | data/migrations/031_nft_exhibition_market_schema.sql |
Sell access as an on-chain certificate instead of only card or credit rails. Membership gates are soulbound; vendor deed / DAGI / license gates are tradeable in the NFT Exhibition Marketplace. Price changes mint a new active template asset — sold assets are never mutated.
nft.collectionMint in ring-config.json (devnet example already set on this tree)./nft/gates; membership slugs auto-stake and unlock member features./nft/market/sell only when they are owned, verified, non-soulbound, and not staked.solana/SECURITY.md).Solana Explorer Symbol comes from off-chain collection metadata JSON at the collection uri — Metaplex Core has no on-chain symbol. Ring Platform uses KEYS for the gate NFT family (Ringdom Keys Collection). RING remains the SPL sale currency only.
Live family JSON (devnet on-chain uri): gist collection.json with "symbol":"KEYS". App SSOT: public/nft/gates/collection.json. After deploy, stable path /nft/gates/collection.json rewrites to /api/nft/gates/collection.
Use Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter controls in-page blocks; sidebar visibility is curated in lib/docs/audience-curated-docs.ts.
MVP-A ships Solana Metaplex Core gate NFTs for membership and vendor unlocks. Buyers pay primary sale with the clone native token (RING on this tree), stake into GateEscrow (not NATIVE_NFT_APR), and GateResolver.hasFeature unlocks product surfaces. Tradeable vendor gates can now list in the NFT Exhibition Marketplace, but a bought gate must still be staked before features activate.
| Concern | Truth |
|---|---|
| Mint SSOT | Metaplex Core (createCollection / create / fetchAsset) |
| Stake SSOT | GateEscrow DB + optional program id — not Ring staking APR |
| Primary sale | RING transferChecked then mint (features/nft-gates/purchase.ts) |
| User surface | /nft/gates |
| Secondary surface | /nft/market, /nft/market/[listingId], /nft/market/sell |
| Admin | /admin/nft/templates, /admin/nft/mint |
| Subscription provider | nft_gate → nftGateSubscriptionProvider |
| Schema | data/migrations/029_nft_gates_schema.sql |
| Marketplace schema | data/migrations/031_nft_exhibition_market_schema.sql |
Sell access as an on-chain certificate instead of only card or credit rails. Membership gates are soulbound; vendor deed / DAGI / license gates are tradeable in the NFT Exhibition Marketplace. Price changes mint a new active template asset — sold assets are never mutated.
nft.collectionMint in ring-config.json (devnet example already set on this tree)./nft/gates; membership slugs auto-stake and unlock member features./nft/market/sell only when they are owned, verified, non-soulbound, and not staked.solana/SECURITY.md).Solana Explorer Symbol comes from off-chain collection metadata JSON at the collection uri — Metaplex Core has no on-chain symbol. Ring Platform uses KEYS for the gate NFT family (Ringdom Keys Collection). RING remains the SPL sale currency only.
Live family JSON (devnet on-chain uri): gist collection.json with "symbol":"KEYS". App SSOT: public/nft/gates/collection.json. After deploy, stable path /nft/gates/collection.json rewrites to /api/nft/gates/collection.
Use Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter controls in-page blocks; sidebar visibility is curated in lib/docs/audience-curated-docs.ts.
MVP-A ships Solana Metaplex Core gate NFTs for membership and vendor unlocks. Buyers pay primary sale with the clone native token (RING on this tree), stake into GateEscrow (not NATIVE_NFT_APR), and GateResolver.hasFeature unlocks product surfaces. Tradeable vendor gates can now list in the NFT Exhibition Marketplace, but a bought gate must still be staked before features activate.
| Concern | Truth |
|---|---|
| Mint SSOT | Metaplex Core (createCollection / create / fetchAsset) |
| Stake SSOT | GateEscrow DB + optional program id — not Ring staking APR |
| Primary sale | RING transferChecked then mint (features/nft-gates/purchase.ts) |
| User surface | /nft/gates |
| Secondary surface | /nft/market, /nft/market/[listingId], /nft/market/sell |
| Admin | /admin/nft/templates, /admin/nft/mint |
| Subscription provider | nft_gate → nftGateSubscriptionProvider |
| Schema | data/migrations/029_nft_gates_schema.sql |
| Marketplace schema | data/migrations/031_nft_exhibition_market_schema.sql |
Sell access as an on-chain certificate instead of only card or credit rails. Membership gates are soulbound; vendor deed / DAGI / license gates are tradeable in the NFT Exhibition Marketplace. Price changes mint a new active template asset — sold assets are never mutated.
nft.collectionMint in ring-config.json (devnet example already set on this tree)./nft/gates; membership slugs auto-stake and unlock member features./nft/market/sell only when they are owned, verified, non-soulbound, and not staked.solana/SECURITY.md).Solana Explorer Symbol comes from off-chain collection metadata JSON at the collection uri — Metaplex Core has no on-chain symbol. Ring Platform uses KEYS for the gate NFT family (Ringdom Keys Collection). RING remains the SPL sale currency only.
Live family JSON (devnet on-chain uri): gist collection.json with "symbol":"KEYS". App SSOT: public/nft/gates/collection.json. After deploy, stable path /nft/gates/collection.json rewrites to /api/nft/gates/collection.
hasFeature('vendor.dagi')).How nft_gate sits beside credit, WayForPay, Stripe, and native token.
Custodial Solana wallets and RING transfers that fund primary sale.
Where generated NFT art lands after ImageConductor.
Shipped Exhibition Marketplace for eligible vendor KEYS gates; audited on-chain GateMarket remains future work.
A marketplace purchase transfers ownership only. It does not grant features until the buyer stakes the gate. An active listing means hasFeature:false; an active stake means canList:false.
features/nft-gates/gate-resolver.ts | hasFeature (cache → stakes → RPC) |
features/nft-gates/admin-mint.ts | Collection create + template activate |
features/nft-gates/art-prompt.ts | Prompt vars + favicon data URI |
features/nft-market/listing-policy.ts | Tradeable SKU, soulbound, stake, duplicate listing checks |
features/nft-market/services/listing-service.ts | NFT Exhibition listing lifecycle |
features/nft-market/services/solana-market-client.ts | Ledger-dev marketplace adapter; Anchor branch blocked |
features/admin/nft/gate-art-preview-modal.tsx | 4-up preview fs-modal |
app/_actions/nft-gates.ts | Server actions |
app/_actions/nft-market.ts | List, cancel, purchase marketplace actions |
lib/payments/subscription/providers/nft-gate-subscription.ts | nft_gate provider |
ring-config.json → nft)Verified keys: enabled, collectionMint, collectionUri, collectionSymbol (KEYS), sponsorFeePayer, marketplaceEnabled, marketplaceFeeRecipient, marketplaceFeeBps, gateEscrowProgramId, gateMarketProgramId, templates[].
Off-chain family metadata: public/nft/gates/collection.json (symbol: KEYS). Admin Point collection URI → KEYS JSON runs Metaplex Core updateCollection when the sponsor still holds update authority.
Seven templates (slugs): one-month-membership, annual-membership, lifetime-membership, vendor-store-deed, vendor-dagi-key, vendor-annual-store-license, vendor-quarterly-store-license.
payment.gateways.nft_gate.enabled is true on this tree. nft_gate remains listed under payment.futureMethods (not yet in supportedMethods), so membership PaymentModal may still tag it as coming-soon while /nft/gates and the provider module are live.
Tradeable marketplace slugs are intentionally narrower: vendor-store-deed, vendor-dagi-key, vendor-annual-store-license, and vendor-quarterly-store-license. Membership slugs remain soulbound and unlistable.
| Action | Purpose |
|---|---|
purchaseGateAction | Buy gate NFT with RING |
stakeGateAction / unstakeGateAction | GateEscrow |
hasGateFeatureAction | Entitlement check |
previewGateArtAction | ImageConductor n: 4 + favicon reference |
adminActivateGateTemplateAction | Mint/activate with optional imageUri |
adminCreateGateCollectionAction | Create Core collection |
Open /admin/nft/templates or /admin/nft/mint and click Mint / activate + art.
previewGateArtAction interpolates $projectName, $activeColor, $secondaryColor, $projectColor1, $projectColor2, $organization, then calls ImageConductor.generate with n: 4 and favicon referenceImages.
Fullscreen modal shows a 2×2 grid, collapsible Generation prompt textarea, and Regenerate (session-only prompt edits — not written to ring-config).
Mint with selected art calls adminActivateGateTemplateAction({ imageUri, regenerateArt: false }) → Metaplex Core mint → nft_gates edition row + db() active-template pointer (nft_active_{slug}). Runtime SSOT is listNftGateTemplatesResolved() (ring-config defaults + DB overlay). ring-config.json is never rewritten in k8s.
| Piece | Path / env |
|---|---|
| Conductor | lib/images/conductor/image-conductor.ts |
| xAI provider | lib/images/providers/xai.provider.ts — /images/generations or /images/edits |
| Favicon PNG | public/images/favicon.png → data:image/png;base64,… |
| Persist | file().upload → RingBaseAdapter when NEXT_PUBLIC_STORAGE_PROVIDER=ring_filebase |
| Local→prod API | Port-forward ring-filebase-api to 127.0.0.1:18080 (see RingFileBase) |
Do not set RINGBASE_API_URL=https://api.ring-platform.org — that host is the Next.js app ingress, not ring-filebase-api. Uploads return HTML and surface as HTTP 500 in RingBaseAdapter.
Migration 029_nft_gates_schema.sql creates JSONB collections: nft_gates, nft_stakes, nft_entitlement_cache, nft_ownership (plus related indexes). Cron: GET /api/cron/nft-gate-expiry → runNftGateExpiry (daily 4am schedule in SubscriptionConductor docs).
Migration 031_nft_exhibition_market_schema.sql adds secondary-market persistence: nft_listings, nft_market_sales, and nft_market_collections.
If nft.collectionMint is empty, metaplex-core.ts issues ledger-dev asset ids when not production, or when ALLOW_LEDGER_NFT_MINT=1. Production refuses ledger mint without that flag.
If nft.gateMarketProgramId is empty, SolanaMarketClient uses the shipped ledger-dev market adapter. If a program id is set in this build, list/cancel/buy throw because audited Anchor GateMarket CPI is not implemented yet.
Anchor scaffolds exist at solana/programs/{gate-escrow,gate-market}. solana/SECURITY.md keeps both programs out of production until audit, Squads authority control, pinned IDs/IDLs, and invariant tests are complete.
Secondary trading for eligible vendor KEYS gates.
hasFeature('vendor.dagi')).How nft_gate sits beside credit, WayForPay, Stripe, and native token.
Custodial Solana wallets and RING transfers that fund primary sale.
Where generated NFT art lands after ImageConductor.
Shipped Exhibition Marketplace for eligible vendor KEYS gates; audited on-chain GateMarket remains future work.
A marketplace purchase transfers ownership only. It does not grant features until the buyer stakes the gate. An active listing means hasFeature:false; an active stake means canList:false.
features/nft-gates/gate-resolver.ts | hasFeature (cache → stakes → RPC) |
features/nft-gates/admin-mint.ts | Collection create + template activate |
features/nft-gates/art-prompt.ts | Prompt vars + favicon data URI |
features/nft-market/listing-policy.ts | Tradeable SKU, soulbound, stake, duplicate listing checks |
features/nft-market/services/listing-service.ts | NFT Exhibition listing lifecycle |
features/nft-market/services/solana-market-client.ts | Ledger-dev marketplace adapter; Anchor branch blocked |
features/admin/nft/gate-art-preview-modal.tsx | 4-up preview fs-modal |
app/_actions/nft-gates.ts | Server actions |
app/_actions/nft-market.ts | List, cancel, purchase marketplace actions |
lib/payments/subscription/providers/nft-gate-subscription.ts | nft_gate provider |
ring-config.json → nft)Verified keys: enabled, collectionMint, collectionUri, collectionSymbol (KEYS), sponsorFeePayer, marketplaceEnabled, marketplaceFeeRecipient, marketplaceFeeBps, gateEscrowProgramId, gateMarketProgramId, templates[].
Off-chain family metadata: public/nft/gates/collection.json (symbol: KEYS). Admin Point collection URI → KEYS JSON runs Metaplex Core updateCollection when the sponsor still holds update authority.
Seven templates (slugs): one-month-membership, annual-membership, lifetime-membership, vendor-store-deed, vendor-dagi-key, vendor-annual-store-license, vendor-quarterly-store-license.
payment.gateways.nft_gate.enabled is true on this tree. nft_gate remains listed under payment.futureMethods (not yet in supportedMethods), so membership PaymentModal may still tag it as coming-soon while /nft/gates and the provider module are live.
Tradeable marketplace slugs are intentionally narrower: vendor-store-deed, vendor-dagi-key, vendor-annual-store-license, and vendor-quarterly-store-license. Membership slugs remain soulbound and unlistable.
| Action | Purpose |
|---|---|
purchaseGateAction | Buy gate NFT with RING |
stakeGateAction / unstakeGateAction | GateEscrow |
hasGateFeatureAction | Entitlement check |
previewGateArtAction | ImageConductor n: 4 + favicon reference |
adminActivateGateTemplateAction | Mint/activate with optional imageUri |
adminCreateGateCollectionAction | Create Core collection |
Open /admin/nft/templates or /admin/nft/mint and click Mint / activate + art.
previewGateArtAction interpolates $projectName, $activeColor, $secondaryColor, $projectColor1, $projectColor2, $organization, then calls ImageConductor.generate with n: 4 and favicon referenceImages.
Fullscreen modal shows a 2×2 grid, collapsible Generation prompt textarea, and Regenerate (session-only prompt edits — not written to ring-config).
Mint with selected art calls adminActivateGateTemplateAction({ imageUri, regenerateArt: false }) → Metaplex Core mint → nft_gates edition row + db() active-template pointer (nft_active_{slug}). Runtime SSOT is listNftGateTemplatesResolved() (ring-config defaults + DB overlay). ring-config.json is never rewritten in k8s.
| Piece | Path / env |
|---|---|
| Conductor | lib/images/conductor/image-conductor.ts |
| xAI provider | lib/images/providers/xai.provider.ts — /images/generations or /images/edits |
| Favicon PNG | public/images/favicon.png → data:image/png;base64,… |
| Persist | file().upload → RingBaseAdapter when NEXT_PUBLIC_STORAGE_PROVIDER=ring_filebase |
| Local→prod API | Port-forward ring-filebase-api to 127.0.0.1:18080 (see RingFileBase) |
Do not set RINGBASE_API_URL=https://api.ring-platform.org — that host is the Next.js app ingress, not ring-filebase-api. Uploads return HTML and surface as HTTP 500 in RingBaseAdapter.
Migration 029_nft_gates_schema.sql creates JSONB collections: nft_gates, nft_stakes, nft_entitlement_cache, nft_ownership (plus related indexes). Cron: GET /api/cron/nft-gate-expiry → runNftGateExpiry (daily 4am schedule in SubscriptionConductor docs).
Migration 031_nft_exhibition_market_schema.sql adds secondary-market persistence: nft_listings, nft_market_sales, and nft_market_collections.
If nft.collectionMint is empty, metaplex-core.ts issues ledger-dev asset ids when not production, or when ALLOW_LEDGER_NFT_MINT=1. Production refuses ledger mint without that flag.
If nft.gateMarketProgramId is empty, SolanaMarketClient uses the shipped ledger-dev market adapter. If a program id is set in this build, list/cancel/buy throw because audited Anchor GateMarket CPI is not implemented yet.
Anchor scaffolds exist at solana/programs/{gate-escrow,gate-market}. solana/SECURITY.md keeps both programs out of production until audit, Squads authority control, pinned IDs/IDLs, and invariant tests are complete.
Secondary trading for eligible vendor KEYS gates.
hasFeature('vendor.dagi')).How nft_gate sits beside credit, WayForPay, Stripe, and native token.
Custodial Solana wallets and RING transfers that fund primary sale.
Where generated NFT art lands after ImageConductor.
Shipped Exhibition Marketplace for eligible vendor KEYS gates; audited on-chain GateMarket remains future work.
A marketplace purchase transfers ownership only. It does not grant features until the buyer stakes the gate. An active listing means hasFeature:false; an active stake means canList:false.
features/nft-gates/gate-resolver.ts | hasFeature (cache → stakes → RPC) |
features/nft-gates/admin-mint.ts | Collection create + template activate |
features/nft-gates/art-prompt.ts | Prompt vars + favicon data URI |
features/nft-market/listing-policy.ts | Tradeable SKU, soulbound, stake, duplicate listing checks |
features/nft-market/services/listing-service.ts | NFT Exhibition listing lifecycle |
features/nft-market/services/solana-market-client.ts | Ledger-dev marketplace adapter; Anchor branch blocked |
features/admin/nft/gate-art-preview-modal.tsx | 4-up preview fs-modal |
app/_actions/nft-gates.ts | Server actions |
app/_actions/nft-market.ts | List, cancel, purchase marketplace actions |
lib/payments/subscription/providers/nft-gate-subscription.ts | nft_gate provider |
ring-config.json → nft)Verified keys: enabled, collectionMint, collectionUri, collectionSymbol (KEYS), sponsorFeePayer, marketplaceEnabled, marketplaceFeeRecipient, marketplaceFeeBps, gateEscrowProgramId, gateMarketProgramId, templates[].
Off-chain family metadata: public/nft/gates/collection.json (symbol: KEYS). Admin Point collection URI → KEYS JSON runs Metaplex Core updateCollection when the sponsor still holds update authority.
Seven templates (slugs): one-month-membership, annual-membership, lifetime-membership, vendor-store-deed, vendor-dagi-key, vendor-annual-store-license, vendor-quarterly-store-license.
payment.gateways.nft_gate.enabled is true on this tree. nft_gate remains listed under payment.futureMethods (not yet in supportedMethods), so membership PaymentModal may still tag it as coming-soon while /nft/gates and the provider module are live.
Tradeable marketplace slugs are intentionally narrower: vendor-store-deed, vendor-dagi-key, vendor-annual-store-license, and vendor-quarterly-store-license. Membership slugs remain soulbound and unlistable.
| Action | Purpose |
|---|---|
purchaseGateAction | Buy gate NFT with RING |
stakeGateAction / unstakeGateAction | GateEscrow |
hasGateFeatureAction | Entitlement check |
previewGateArtAction | ImageConductor n: 4 + favicon reference |
adminActivateGateTemplateAction | Mint/activate with optional imageUri |
adminCreateGateCollectionAction | Create Core collection |
Open /admin/nft/templates or /admin/nft/mint and click Mint / activate + art.
previewGateArtAction interpolates $projectName, $activeColor, $secondaryColor, $projectColor1, $projectColor2, $organization, then calls ImageConductor.generate with n: 4 and favicon referenceImages.
Fullscreen modal shows a 2×2 grid, collapsible Generation prompt textarea, and Regenerate (session-only prompt edits — not written to ring-config).
Mint with selected art calls adminActivateGateTemplateAction({ imageUri, regenerateArt: false }) → Metaplex Core mint → nft_gates edition row + db() active-template pointer (nft_active_{slug}). Runtime SSOT is listNftGateTemplatesResolved() (ring-config defaults + DB overlay). ring-config.json is never rewritten in k8s.
| Piece | Path / env |
|---|---|
| Conductor | lib/images/conductor/image-conductor.ts |
| xAI provider | lib/images/providers/xai.provider.ts — /images/generations or /images/edits |
| Favicon PNG | public/images/favicon.png → data:image/png;base64,… |
| Persist | file().upload → RingBaseAdapter when NEXT_PUBLIC_STORAGE_PROVIDER=ring_filebase |
| Local→prod API | Port-forward ring-filebase-api to 127.0.0.1:18080 (see RingFileBase) |
Do not set RINGBASE_API_URL=https://api.ring-platform.org — that host is the Next.js app ingress, not ring-filebase-api. Uploads return HTML and surface as HTTP 500 in RingBaseAdapter.
Migration 029_nft_gates_schema.sql creates JSONB collections: nft_gates, nft_stakes, nft_entitlement_cache, nft_ownership (plus related indexes). Cron: GET /api/cron/nft-gate-expiry → runNftGateExpiry (daily 4am schedule in SubscriptionConductor docs).
Migration 031_nft_exhibition_market_schema.sql adds secondary-market persistence: nft_listings, nft_market_sales, and nft_market_collections.
If nft.collectionMint is empty, metaplex-core.ts issues ledger-dev asset ids when not production, or when ALLOW_LEDGER_NFT_MINT=1. Production refuses ledger mint without that flag.
If nft.gateMarketProgramId is empty, SolanaMarketClient uses the shipped ledger-dev market adapter. If a program id is set in this build, list/cancel/buy throw because audited Anchor GateMarket CPI is not implemented yet.
Anchor scaffolds exist at solana/programs/{gate-escrow,gate-market}. solana/SECURITY.md keeps both programs out of production until audit, Squads authority control, pinned IDs/IDLs, and invariant tests are complete.
Secondary trading for eligible vendor KEYS gates.