# kbeauty.market — What a 15% service fee actually leaves behind.

Every figure below is derived from one file of inputs. The inputs are published, split into what the operator specified and what is still only assumed, and each assumption carries a note saying what it rests on. If an assumption is wrong the arithmetic is still right — change the input and every number on this page moves with it.

> The shelf is real: real products at real Korean retail prices. What is not connected yet is this shop's own checkout — where a product also stands on Amazon's shelf, its page carries a door that works today. The figures below are illustrative, and their inputs are published.

> Independent project. Not affiliated with, endorsed by, or connected to any brand or platform shown or read, with one exception the rules require naming: as an Amazon Associate, kbeauty.market earns from qualifying purchases made through its Amazon links.

## The goods pass straight through. Everything else has to be carried.

Nothing is marked up: the customer is charged what the item costs on the shelf in Korea, and that same amount goes back out when we buy it. So the goods net to nothing, and the service fee and what is charged for carriage are left to cover the domestic leg, the international leg, handling, a cross-border card rate, and the parcels that never turn up.

| per order | USD |
| --- | ---: |
| Goods, at Korean retail | $57.60 |
| Service fee | $8.64 |
| Carriage, charged | $32.00 |
| …the goods, bought | −$57.60 |
| Korean domestic leg | −$2.50 |
| Carriage, paid | −$22.00 |
| Check, consolidate, pack | −$3.00 |
| Card, cross-border | −$4.62 |
| Parcels that do not arrive | −$2.39 |
| **What is left** | **$6.13** |

## An order leaves less than the fee the customer thinks they paid.

That is the whole shape of a buying service. The fee is what is being compared and negotiated, and it is not, on its own, enough — the margin on carriage is what closes the gap. Price carriage at cost and the service runs at a loss on every order.

- Service fee the customer pays: **$8.64**
- What the order actually leaves: **$6.13**
- …which is **71%** of that fee
- Contribution margin on the whole order: **6.2%**
- Margin on carriage (charged less paid): **$10.00**

## The real cost centre is video, and it never stops.

This model is built on at least three shorts per product. The shelf today is not there — the products standing on it carry one each, and every figure below is what the catalogue this page describes would cost, not what has been spent. Those videos are not free and they do not stay useful — short-form creative decays, and a product whose best video is a year old is a product that stops being shown. Replacing a quarter of the library each quarter is not a marketing line item. It is the cost of goods for a business whose actual product is attention.

- Cost of one usable video: **$130.00**
- Library at the modelled size (1,847 shorts): **$240,110**
- Videos replaced each month: **154**
- Video refresh per month: **$20,009**
- Fixed overhead per month: **$1,400**
- Share of the fixed base that is video: **93%**

## Said per product, it is a number an operator can act on.

This is what each of the SKUs on the shortlist has to sell every month simply to pay for its own videos. A SKU below it is not underperforming — it is being subsidised by the ones above it, and the shortlist should be shorter.

- Orders per month to break even: **3,493**
- Gross revenue at that point: **$343,137**
- Video carried by each SKU per month: **$83.37**
- Orders each SKU must produce per month: **13.6**

## Medusa 2.0, with video as a first-class object.

Commerce is not the interesting part of this build and should not be written. What is interesting is that the thing being sold is a video, and a Medusa 2.0 module may not reach into another module's tables — so video cannot be a column on Product. It is its own module, associated through a link and read back across the boundary in a single query. The buying, consolidation and seeding flows are durable workflows because they are long, they call outside services, and a half-created order must never become visible.

**Modules are isolated. They are linked, not joined.** A Medusa 2.x module owns its own tables and may not hold a foreign key into another module's. The video library therefore cannot be a column on Product. It is its own module, associated through `defineLink`, and read back across the boundary with `query.graph`. Getting this wrong is the standard way a Medusa project ends up unable to upgrade.

### Commerce modules, used as shipped

- **Product** — The shortlist as a catalogue. A product exists because a curation entry was approved, not because someone typed it in.
- **Pricing** — USD price sets. One currency: the service fee and the carriage are quoted in dollars wherever the customer is.
- **Inventory** — Not used to hold stock. Variants are created with `manage_inventory: false` — we buy each unit after the order, so there is nothing to decrement and nothing to reserve.
- **Stock Location** — One location, and it is not a warehouse: the Seoul consolidation point where goods bought on a customer's behalf wait for the rest of their order.
- **Cart** — Built from a video, not from a grid. The line item carries the clip it came from.
- **Order** — The order is the request to buy. What happens afterwards is tracked next door, in Purchase.
- **Payment** — Cross-border card rates, which are higher than domestic and are not refunded on a return. The model treats them as sunk.
- **Fulfillment** — One shipping option: everything leaves Korea in one box once the last item has been bought.
- **Customer** — Accounts, addresses and order history.
- **Promotion** — Launch pricing, drop codes, creator codes.
- **Tax** — By destination country. In a buying service the customer is usually the importer, which changes who owes what — this is the module where that gets encoded, not a detail to settle later.
- **Region** — One region, Global, covering the twelve countries we ship to today. Japan and Mexico are there because this business has actually sold into them.
- **Sales Channel** — Web storefront now; the app feed and any TikTok Shop surface later, without a second catalogue.
- **Auth** — Email and social sign-in.
- **Notification** — Order mail, sourcing updates, the message that says an item was unavailable.
- **File** — Creative assets. Video itself does not live here — it stays on the platform it was posted to.

### Infrastructure modules

- **Workflow Engine** — Redis. Durable execution: a long-running buying job survives a restart and rolls back on failure. In-process would lose it.
- **Event Bus** — Redis. Decouples ingest and campaign flows from the request that started them.
- **Cache** — Redis. Feed responses and price calculations.
- **Locking** — Redis. Stops two ingest runs creating the same SKU twice, and stops two instances taking the same lock.

### Written for this product

- **Video** (Clip) — Every product is sold through short-form video and nothing else, so video is a first-class commerce object rather than an attachment. Linked to Product with `defineLink` and read back in one `query.graph` call. Holds the embed reference, not the file and not a cached poster frame. The storefront embeds from the platform on viewport entry.
- **Curation** (Source record, listing image, our own selection note) — The shortlist is the product, so how something got onto it has to be written down. The note shown to a shopper is ours — no outside platform's ranking is presented as an endorsement. The image credit field records where each photograph came from, so replacing it with the brand's own asset later is a data change.
- **Purchase** (Buying job, buying line) — A normal shop's order is finished when it ships. Ours has a middle — sourcing, purchase, inbound, consolidation — and each of those is a state a customer can reasonably ask about. Lines carry their own status. Two of three items bought and one sold out is the ordinary case, not an exception.

### Data stores

- **PostgreSQL 18** — Every commerce module and all three custom ones. Medusa's own store, unmodified.
- **Redis 8** — Event bus, cache, locks, workflow state. Four modules, one instance, separable later.
- **Object storage + CDN** — Product photography and creative. Not built yet.
- **MongoDB** — Planned, not built: view and conversion time series, where the write pattern is append-heavy and the shape changes often. Nothing depends on it today.

### Durable workflows

#### Shortlist an item

Trigger: A candidate clears our own selection criteria

1. Open a Curation record with the factual product data and the listing image
2. Write the selection note — the reason a shopper will be shown, in our words
3. Create the Product and its USD price set, with inventory management off
4. Link Product to the Curation record
5. Queue a seeding campaign for the minimum three clips

Rollback: Any step failing leaves the product in draft. A half-created SKU is never visible to a shopper.

#### Attach an approved clip

Trigger: A creator deliverable is approved in SocialSeed.ing

1. Record the deliverable against its seed
2. Create the Clip from the platform's canonical URL
3. Link it to its Product
4. Recompute cost per usable video for the campaign
5. Publish the SKU once it holds three clips

Rollback: A missing or deleted source video leaves the seed open and the SKU unpublished rather than shipping a product with a dead embed.

#### Run a buying job

Trigger: An order is placed

1. Open a Purchase job against the order, one line per item
2. Buy each line at Korean retail and record what was actually paid
3. Mark anything sold out as unavailable and refund that line, keeping the rest of the order
4. Receive the goods domestically and consolidate them into one parcel
5. Ship, and record charged carriage against actual carriage

Rollback: A failure part-way leaves the job in its last completed state with the bought lines recorded. Nothing is silently re-bought.

## Everything the arithmetic rests on.

Nothing else is typed anywhere. Assumed inputs are marked — they have not been validated against a real month of trading, and the ones most likely to be optimistic are the share of seeded creators who deliver usable video, the number of items in an average order, and a single carriage figure standing in for a table that really varies by destination.

| input | value | validated | basis |
| --- | ---: | :---: | --- |
| Catalogue size | 240 | given | Operator's brief. Small on purpose: every SKU has to carry its own video cost, so the catalogue is a cost base rather than an asset. |
| Shorts in catalogue | 1,847 | given | Operator's brief. Above the three-per-SKU minimum, which is what a video-first storefront needs to avoid showing the same clip twice. |
| Minimum shorts per SKU | 3 | given | Operator's brief. Below three a product page repeats itself within one session, which is the point at which the format stops working. |
| Creators | 120 | given | Operator's brief. Campaigns are run through SocialSeed.ing, so the roster is a standing asset rather than a per-campaign spend. |
| Card rate, cross-border | 4.4% | given | Standard online card pricing plus the cross-border and currency-conversion surcharges that apply when the buyer is not in the merchant's country — which, here, is every buyer. |
| Card fixed fee | $0.30 | given | Standard per-transaction fee. |
| Average item, at Korean retail | $18 | assumed | What one item costs on the shelf in Korea, converted. This is what the customer is charged for the goods — the buying service does not mark the goods up, it charges for the service. |
| Items per order | 3.2 | assumed | Consolidation rewards larger baskets — one carriage charge covers the whole parcel — so buying-service orders run bigger than ordinary retail ones. Still a placeholder. |
| Service fee on goods | 15% | assumed | What is charged for finding, buying, checking and consolidating. The visible price of the service and the number a customer will compare against a rival agent. |
| Carriage charged to the customer | $32 | assumed | A single blended figure standing in for a table that really varies by destination and weight. Set above cost deliberately; the model below shows why it has to be. |
| Carriage actually paid | $22 | assumed | Blended international rate for a consolidated parcel of this size. Japan is far cheaper than Mexico; a single figure hides a spread that pricing will eventually have to face. |
| Korean domestic leg | $2.50 | assumed | Getting each purchase from the Korean seller to the consolidation point. Charged per order rather than per item because most items in one order arrive together. |
| Check, consolidate, pack | $3 | assumed | Labour: opening, checking against the order, repacking into one parcel, photographing. The step a customer is actually paying the service fee for. |
| Parcels lost, damaged or refused | 3.0% | assumed | Cross-border parcels go missing, get held, and occasionally get refused at the door. The service carries this, not the customer. |
| Seeding fee per creator | $60 | assumed | Flat fee paid per seeded creator at the micro tier, on top of the product they keep. |
| Seeds that yield usable video | 60% | assumed | Share of seeded creators who post something good enough to run as a product video. The number most likely to be optimistic. |
| Catalogue refreshed per quarter | 25% | assumed | Short-form creative decays. A quarter of the library replaced each quarter keeps a product's top video roughly a season old. |
| Fixed monthly overhead | $1,400 | assumed | Consolidation space, commerce platform, domain and tooling. Excludes any salary. |
| Rated Korean catalogue | 9,000 | assumed | Order of magnitude for how many skincare products carry an ingredient rating at home. Used only to express the selection ratio; nothing else depends on it. |

## The shop opened around this document. Its own till did not.

This page is fully static, stores nothing, and has no account system — there is no database behind it to secure. Most of what this section once had to admit missing now exists: the backend is migrated and live, the catalogue is real — a shelf of products bought at Korean retail — and where a product also stands on Amazon's shelf, its page carries a door that works today. What is still not connected is this shop's own checkout: you cannot yet pay us. The arithmetic has been real throughout.

Raw inputs: https://kbeauty.market/model.json
