---
title: "Multi-Vendor Store"
description: "Multi-vendor marketplace — vendor onboarding, cached catalog, client+server cart, authenticated checkout, Agent Knowledge Research, tier commissions, and member audience gating"
locale: "en"
---
# Multi-Vendor Store

Ring Platform ships a multi-vendor marketplace: any **verified Entity** can onboard as a vendor, list products, and earn after paid orders settle. Buyers browse a cached catalog, hold a cart, then check out through authenticated order + PaymentConductor rails. Vendors enrich catalog copy with **Agent Knowledge Research** (WebConductor → fields, markdown, Admin Wiki NODUS, File Cabinet alt images) and opt media into the gallery explicitly.

> **Info**
> Use the **Founder** / **Developer** tabs in the docs sidebar to filter this page. Cart and checkout below match `features/store` + `app/api/store/*` in Layer1 — do not invent extra cart REST beyond the verified session mirror.

## Capability map

| Concern | Where it lives | Notes |
|---------|----------------|-------|
| Catalog SSOT | `getCachedProductCatalog()` → `GET /api/store/products` | `'use cache'` + `cacheTag('store:products')`; invalidate with `updateTag` after create |
| Guest cart | `localStorage` key `ring_cart` | `{ id, qty }[]` in `features/store/context.tsx` |
| Auth cart mirror | `GET`/`POST /api/store/cart` | Session-bound; ignores client `userId`; soft-holds via `POST /api/store/cart/hold` |
| Checkout | `POST /api/store/checkout` | Auth required → `StoreOrdersService` + inventory reserve |
| Pay | `POST /api/store/payments/*` | PaymentConductor purpose `store_order` |
| Vendor desk | `/vendor/start`, `/vendor/products` | Server actions — not `/api/store/vendors` |
| Commissions | `settlement.ts` + `/admin/store/commissions` | Platform tier % from `TIER_BENEFITS` (`StoreTier`) |

### For founders

## Why the multi-vendor store matters for your clone

Every Entity in your Ring deployment can become a selling vendor — no external marketplace needed. Platform revenue comes from **tier-based commission rates** on settled sales. Vendors catalogue themselves; operators approve products and settle commissions from the admin cockpit.

### Key operator capabilities

  
- **[Vendor lifecycle](/docs/features/store.md)** — Onboard entities at /vendor/start. Trust scoring, tier progression, and suspension live in vendor-lifecycle.

  
- **[Agent Knowledge Research](/docs/features/generative-media.md)** — On create/edit product forms: Research → fields + markdown + wiki NODUS + cabinet alt images. **Use in gallery** is explicit — nothing silently replaces the primary photo.

  
- **[Commission settlements](/docs/features/erp/commissions.md)** — Tier-based platform commission per sale. Admin dashboard at /admin/store/commissions — dry-run and process due payouts.

  
- **[Product audience gating](/docs/features/store.md)** — Mark products member-only. Non-members see public products only (`hasMemberPrivileges()`).

  
- **[Payments for store orders](/docs/features/payment-conductor.md)** — After checkout, buyers pay via PaymentConductor (`store_order`) — WayForPay, Stripe, credit, token, or PayPal when enabled.

  
- **[ERP stock](/docs/features/erp/inventory.md)** — Checkout reserves stock; paid webhooks drive commitSale — keep inventory and settlements aligned.

### Typical scenarios

- **Local business network** — every shop lists inventory; settlements run from the commissions cockpit.
- **DAO / member catalog** — member-gated SKUs; public products as lead magnets (`productAudience: 'member'`).
- **Catalog enrichment** — vendor pastes a manufacturer URL, runs **Research**, reviews suggested fields, saves Agent Knowledge, then clicks **Use in gallery** only for photos they want on the storefront.
- **DAGI assist** — vendor ERP chat tool `dagi_research_product` returns the same suggested fields / research media / cabinet path for the bound vendor.

> **Tip**
> Storefront **product agent** chats use `Conversation.type: 'product'` and stay visible in Messages. **Generative Gallery** tool chats set metadata `kind: 'generative_gallery'` (inbox filtering in conversation-service). See [Messaging](/docs/features/messaging.md) and [Generative Gallery](/docs/features/generative-media.md).

### Commission tiers (operator view)

Settlement platform commission uses **`StoreTier`** benefits (`constants/store.ts` → `TIER_BENEFITS`):

| Store tier | Platform commission % | Typical settlement cadence |
|------------|----------------------|----------------------------|
| `starter` | 20% | Weekly |
| `growth` | 17% | Daily |
| `professional` | 15% | Daily |
| `enterprise` | 12% | Instant |

Default fallback when tier benefits are missing: **`DEFAULT_COMMISSION_PCT` = 15**. Vendor **trust levels** (`new` → `premium`) track reputation separately from store tier. Referral commission is a dual rail — see [Commissions](/docs/features/erp/commissions.md) and [refcodes](/docs/features/refcodes.md).

### For developers

## Implementation

### Multi-vendor architecture

```mermaid
flowchart TB
    subgraph Vendor[Vendor Onboarding]
        Start[/vendor/start]
        Approve[Admin approval]
        Profile[createVendorProfile]
    end

    subgraph Research[Agent Knowledge]
        UI[ProductAgentKnowledgeSection]
        Act[researchProductAgentAction / Draft]
        WC[WebConductor]
        Cab[product-cabinet-media]
        Wiki[createProductNodusWikiFromDraft]
    end

    subgraph Catalog[Catalog SSOT]
        Cache[getCachedProductCatalog]
        API[GET /api/store/products]
        Action[getStoreProducts]
    end

    subgraph CartCheckout[Cart and checkout]
        LS[ring_cart localStorage]
        SC[GET/POST /api/store/cart]
        Hold[POST /api/store/cart/hold]
        CO[POST /api/store/checkout]
        Pay[POST /api/store/payments/*]
    end

    Vendor --> UI
    UI --> Act --> WC
    Act --> Cab
    Act --> Wiki
    UI --> Cache
    Cache --> API
    Cache --> Action
    LS --> SC
    SC --> Hold
    LS --> CO
    CO --> Pay
```

### Cart and checkout (verified — no invented routes)

| Piece | Path | Role |
|-------|------|------|
| Client context | `features/store/context.tsx` | Global `StoreProvider`; defers catalog fetch until pathname includes `/store` **or** `ring_cart` has items; single-flight `GET /api/store/products` |
| Guest lines | `useLocalStorage('ring_cart')` | `{ id, qty }[]` |
| Server cart | `features/store/services/server-cart.ts` | Collection `store_user_carts`; doc id `cart_{userId}` |
| Cart HTTP | `app/api/store/cart/route.ts` | Auth required; binds `session.user.id` only |
| Soft-hold | `app/api/store/cart/hold/route.ts` | Inventory soft-hold while cart has lines |
| Adapter checkout | `features/store/adapters/http-adapter.ts` | `fetch('/api/store/checkout', { items, info })` |
| Checkout HTTP | `app/api/store/checkout/route.ts` | Auth → `StoreOrdersService` + `reserveInventoryForOrder`; legacy adapter `store_orders` path is **not** the payable pipeline |

There is **no** public unauthenticated cart REST CRUD and **no** `/api/store/vendors` apply endpoint. Vendor onboarding is UI + server actions.

### Agent Knowledge Research (shipped)

| Piece | Path | Role |
|-------|------|------|
| Conductor | `lib/web/conductor/web-conductor.ts` | TextConductor `webSearch: true` → structured fields + `productAgentMarkdown` + NODUS JSON + citation-host image candidates |
| Orchestrator | `features/store/lib/product-agent-research.ts` | Builds request + `runProductAgentResearch` |
| Cabinet writer | `features/store/lib/product-cabinet-media.ts` | Dirs `store/[storename]/[product-slug]/alt` (fits `MAX_FOLDER_DEPTH` 3; conceptual `files/` prefix), SSRF-safe image fetch → RingBase → cabinet nodes |
| Actions | `app/_actions/product-agent-research.ts` | `researchProductAgentAction`, `researchProductDraftAction`, `saveProductAgentKnowledgeAction` |
| UI | `features/store/components/product-agent-knowledge-section.tsx` | Create + edit; **Use in gallery** explicit |
| Wiki helper | `features/store/lib/product-nodus-wiki.ts` | `createProductNodusWikiFromDraft` → tenant Admin Wiki |
| DAGI | `features/store/services/dagi-erp-tools.ts` | `dagi_research_product` → `suggestedFields` / `researchMedia` / `cabinetPath` / `skippedImages` |
| Schema notes | `AI-LEGIOX/legiox-truth-lens/AGENT-PRODUCT-SCHEMA.md` | Photo / research generator steps |

**Auth:** vendor entity owner or platform admin (`resolveResearchVendor` + ownership check). Draft research (no product id yet) uses `researchProductDraftAction` and still writes cabinet artifacts under the vendor owner.

**Gallery rule:** research media is never auto-merged as primary. Operators must click **Use in gallery**.

### Product catalog SSOT

`getCachedProductCatalog()` in `features/store/config.ts` (`'use cache'` + `cacheTag('store:products')`). Consumers: `app/api/store/products/route.ts`, `getStoreProducts` in `app/_actions/store-products.ts`, MCP `app/api/mcp/v1/store/products/route.ts`. Invalidate with `updateTag('store:products')` after create.

### Verified app routes

| Route | Purpose | Auth |
|-------|---------|------|
| `/vendor/start` | Vendor onboarding | Subscriber+ |
| `/vendor/products` | Vendor product CRUD + Agent Knowledge | Vendor entity owner |
| `/admin/store/products` | Product approval queue (same form) | Platform admin |
| `/admin/store/commissions` | Commission settlements | Platform admin |
| `/admin/store/orders` | Order desk | Platform admin |
| `/admin/store/stock` | Stock desk | Platform admin |
| `/store` | Public storefront + audience filter | Public |

### Product custom fields

Vendor selects a category on the product form.

Adds name+value parameters (“Add product parameter”).

Persists via `createProductCustomField()` in `app/_actions/vendor-actions.ts` (ownership-guarded).

### Product audience filtering

Products with `productAudience: 'member'` (or legacy `audience`) are hidden unless `isAdmin || hasMemberPrivileges(currentRole)` in `app/_actions/store-products.ts`.

### Settlement commission SSOT

`features/store/services/settlement.ts` reads `TIER_BENEFITS[vendor.storeTier || 'starter'].commissionRate` (fallback `DEFAULT_COMMISSION_PCT`). Weighted referral commission uses `features/store/lib/referral-commission.ts`. Do not document WayForPay’s local `getCommissionRateForTier(NEW…PREMIUM)` map as the settlement SSOT — that helper is payment-path specific.

### Module summary

| Module | Purpose |
|--------|---------|
| `features/store/config.ts` | Adapter + cached catalog SSOT |
| `features/store/context.tsx` | Deferred client catalog + cart + checkout call |
| `features/store/services/server-cart.ts` | Authenticated cart mirror |
| `features/store/services/vendor-lifecycle.ts` | Vendor profile + trust levels |
| `features/store/services/settlement.ts` | Commission calculation |
| `features/store/services/orders-service.ts` | Payable `orders` pipeline |
| `features/store/services/inventory-sync.ts` | reserve / commitSale / cancel restore |
| `lib/web/conductor/web-conductor.ts` | Web product research |
| `features/store/lib/product-cabinet-media.ts` | Research → File Cabinet alt |
| `app/_actions/product-agent-research.ts` | Research / draft / save knowledge |
| `app/_actions/vendor-actions.ts` | Vendor product CRUD + research form fields |
| `app/_actions/admin-store-erp.ts` | Admin product path + Agent Knowledge hidden fields |
| `features/auth/user-role.ts` | `hasMemberPrivileges()` |
| `constants/store.ts` | `StoreTier`, `VendorTrustLevel`, `TIER_BENEFITS` |

## Frequently asked questions

### Impact

#### Will guests keep a cart without signing in?

Yes — lines live in `ring_cart` on the device. Signing in hydrates from `GET /api/store/cart` (server wins) and subsequent edits POST back to the session mirror.

#### Do commissions run when someone adds to cart?

No. Platform commission and referral splits are calculated on vendor order settlement after a payable order exists — not on cart mutations.

#### Can member-only products appear on the public storefront?

Not for non-members. `getStoreProducts` filters `productAudience: 'member'` unless the viewer is admin or has member privileges.

### Migration

#### We used a client-only cart and no server mirror — what changes?

Keep `ring_cart` for guests. For authenticated buyers, treat `/api/store/cart` as the SSOT on hydrate and after edits; soft-holds may return 409 on insufficient stock. Checkout still requires a session.

#### Is `POST /api/store/orders` still valid?

Checkout and orders share the same payable `orders` pipeline via `StoreOrdersService`. Prefer the documented checkout entry used by `HttpStoreAdapter` (`/api/store/checkout`). Avoid any legacy path that wrote only `store_orders` — payment webhooks do not settle those.

### Ops

#### Where do operators settle vendor payouts?

`/admin/store/commissions` — dry-run due payouts, process due, and hold. Deep dive: [Commissions & Settlements](/docs/features/erp/commissions.md).

#### Catalog looks stale after a product create — what to invalidate?

Call `updateTag('store:products')` (already wired on product create in `app/api/store/products/route.ts`). Consumers must go through `getCachedProductCatalog()`.

#### How do payments attach to store checkout?

After order create, UI posts to `/api/store/payments/{wayforpay|stripe|credit|token|paypal|card}` → PaymentConductor purpose `store_order`. See [PaymentConductor](/docs/features/payment-conductor.md) and [Store API](/docs/api/store.md).

## Related documentation

  
- [features/payment-conductor](/docs/features/payment-conductor.md) — Depends-on: store_order checkouts settle through PaymentConductor and the payment_transactions ledger.

  
- [features/payments](/docs/features/payments.md) — Same-workflow: clone payment rails and env gates that store checkout methods respect.

  
- [features/erp](/docs/features/erp.md) — Next-step: ERP hub for stock invariant, commitSale, and settlements cockpit.

  
- [features/erp/inventory](/docs/features/erp/inventory.md) — Deep-dive: reserve on checkout → commitSaleForOrder on paid → cancel/refund restore.

  
- [features/erp/commissions](/docs/features/erp/commissions.md) — Next-step: vendor commission ledger, dry-run payouts, and referral dual-rail.

  
- [api/store](/docs/api/store.md) — Deep-dive: verified /api/store HTTP surface for products, cart mirror, checkout, and payments.

  
- [features/file-cabinet](/docs/features/file-cabinet.md) — Same-workflow: research images land under store/product/alt; Image/Video chat enhances siblings.

  
- [features/generative-media](/docs/features/generative-media.md) — Next-step: Generative Gallery Upload | Generate on product forms and cabinet scope.

  
- [features/admin-wiki](/docs/features/admin-wiki.md) — Depends-on: Research writes product NODUS pages into the tenant wiki vault.

  
- [features/ring-oracle](/docs/features/ring-oracle.md) — Depends-on: SSR FX hydrate and presentment convertPrice / displayMode for checkout.
