Skip to content

Domain model

Every noun in the marketplace, what it means, and which table holds it.

The actors

Actor Identity Authenticates with Surface
Buyer Shopware customer Shopware storefront session Storefront — buy-box, checkout
Seller flyokai_seller bound 1:1 to a flyokai_user Portal JWT (OAuth password grant) Seller portal /flyok-portal/*
Operator flyokai_user with an operator/admin role Shopware admin token Admin modules /api/_action/marketplace/*

A seller is a marketplace account that lists offers, fulfils orders and gets paid. An operator is platform staff who approve sellers/offers, run finance and answer messages.

Seller

A seller is a flyokai_seller row joined to a flyokai_user (the login). Around it hang:

  • Branding (flyokai_seller_branding) — store name, logo, banner; drives the seller microsite /seller/{slug}.
  • Addresses (flyokai_seller_address) — billing / shipping.
  • Payout config (flyokai_seller_payout_config) — bank holder, IBAN, SWIFT.
  • Stock sources (flyokai_seller_stock_source) — the warehouses an offer's stock is held at.
  • Shipping profiles (flyokai_shipping_profile + _service + _service_carrier) — how the seller's shipping maps onto cart service tiers. See Cart & checkout → Shipping.
  • A group (flyokai_seller_group) — optional, carries a group-level commission default.

Sellers can be active, inactive or suspended. Operators manage them from the Sellers admin; sellers self-serve profile, branding and addresses from the portal.

Product ownership

A product is either operator-owned (the platform's own catalogue) or seller-owned (created by a seller through the portal or bulk import). The owner is recorded in product.flyokai_product_owner_id — NULL for operator-owned.

Ownership gates what a seller may touch: a seller can only edit, offer on via bulk import, or manage stock for their own products. Operator-owned products are open for any seller to make an offer against. The bulk import ownership guard enforces this on every CSV row.

Newly seller-created products are subject to the autoApproveProducts setting: off (default) → they land pending approval until an operator reviews them; on → sellers can publish directly.

Offer

An offer (flyokai_seller_offer) is one seller's proposition to sell one product at a price, with stock and shipping. Multiple sellers' offers on the same product compete for the buy-box.

flyokai_seller_offer            one row per (seller, product/variant)
  ├─ flyokai_seller_offer_price   price tier(s) — qty range → price
  └─ flyokai_seller_offer_stock   stock per stock-source (warehouse)

Offers are per-variant

On a configurable (variant) product, offers attach to the child variants, not the parent. The parent carries no offer of its own — the buy-box is resolved per variant. Tools exist to backfill variant offers when migrating (flyokai:marketplace:backfill-variant-offers).

Offer lifecycle

            create / material edit
   (draft) ───────────────────────► pending_approval ──► active
                                          │   ▲              │
                            operator reject│   │operator      │seller pause /
                                          ▼   │approve        ▼operator action
                                       rejected                inactive
  • New and materially edited offers land in pending_approval unless autoApproveOffers is on (then the seller may publish straight to active).
  • Operators approve or reject from the Offers admin.
  • Only active offers participate in the buy-box.

Purchase order (PO)

When a buyer checks out, the single Shopware order fans out into one purchase order per seller (flyokai_purchase_order), each with its own lines (flyokai_purchase_order_line), status, totals, commission and (later) payout link.

Shopware order  ──fan-out──►  PO (seller A)   status, total, commission, payout_id
                              PO (seller B)   …

A PO advances through pending → confirmed → shipped → delivered (or cancelled), driven by Shopware delivery state transitions. Each PO line snapshots the seller_offer, quantity, unit price and commission percent at the moment of sale — so the figures never drift when products or offers change later. Sellers see their POs read-only in the portal; operators see all of them in Finance.

Commission & fees

What the platform keeps from a sale:

Knob Where Resolution order
Per-product commission product.flyokaiCommissionPercent Used first when set (and non-zero).
Global default commission defaultCommissionPercent config Fallback when the product has none.
Fixed per-PO transaction fee defaultTransactionFeeAmount config Flat amount deducted from each PO's payout.

Both are snapshotted onto the PO line at order placement — the value in force at checkout applies to that PO for life. See Configuration → Marketplace.

Statement

A statement (flyokai_statement, lines in flyokai_statement_line) rolls a seller's POs over a closed date interval into a payable figure: total sales, total commission, and the resulting payout_amount. Optionally shipping the seller collected is added back in (includeShippingInPayout).

Statements are open → closed → paid. Open statements can be recomputed to pick up config changes; closed/paid statements are frozen. Generated via marketplace:statement:generate or the Finance admin. Full mechanics in Statements & payouts.

Payout

A payout (flyokai_payout) is a money movement to a seller against a closed statement, carrying the bank details snapshotted from the seller's payout config. Status runs pending → executing → completed. Created and executed via marketplace:payout:execute or the admin. Execution is the integration point where you wire your PSP / bank file — out of the box it records the movement.

Messaging

Seller ↔ operator mail is threaded:

  • flyokai_chain is a thread; flyokai_mail are the messages in it.
  • flyokai_mail_recipient tracks unread counts; flyokai_mail_pending_send is the outbox batch.

Delivery goes through Shopware's own mailer (MailerInterface). See Messaging.

The tables

The Base plugin owns 23 data-plane / identity DTOs, all prefixed flyokai_, reconciled into Shopware's MySQL on install:

Group Tables
Identity flyokai_user
Sellers flyokai_seller, flyokai_seller_group, flyokai_seller_address, flyokai_seller_branding, flyokai_seller_payout_config, flyokai_seller_stock_source
Offers flyokai_seller_offer, flyokai_seller_offer_price, flyokai_seller_offer_stock
Orders flyokai_purchase_order, flyokai_purchase_order_line
Finance flyokai_statement, flyokai_statement_line, flyokai_payout
Shipping flyokai_shipping_profile, flyokai_shipping_profile_service, flyokai_shipping_profile_service_carrier, flyokai_shipping_service
Messaging flyokai_chain, flyokai_mail, flyokai_mail_recipient, flyokai_mail_pending_send

Plus DAL extensions on Shopware's product, order_line_item and order_delivery (see Architecture → DAL extensions).

The OAuth client/token tables (identity plane) are created alongside on install but are managed by the OAuth layer rather than the marketplace schema DTOs.

Every term again, alphabetical, in the Glossary.