Skip to content

Commit 3715bfa

Browse files
brownjuly2003-codeJuliaEdomclaude
authored
docs(domain): business legend source of truth — own-brand kitchen-appliance importer (A1) (#136)
Adds docs/domain.md: the company legend (own-brand small kitchen appliances, RU design / China manufacturing, ~2k orders/day across wholesale + FBS marketplaces + D2C), 5-branch / 3-jurisdiction footprint incl. the JAFZA free-zone re-export hub, gift-driven seasonality and the Chestny ZNAK marking frame, the reinterpretation dictionary for existing code/schema names (no code renames; x5__->mp__ and currency repin recorded as planned data-phase changes), and the persona x question x endpoint matrix that the operational layer will serve. Market grounding researched 2026-07-03 (sources in section 7). Co-authored-by: JuliaEdom <uedomskikh@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 4104382 commit 3715bfa

1 file changed

Lines changed: 243 additions & 0 deletions

File tree

‎docs/domain.md‎

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
# Domain Model — the Business Behind the Demo Data
2+
3+
AgentFlow is the platform. This document describes the **company whose data
4+
flows through it** in every seed, demo, metric, and warehouse table — the
5+
single source of truth for the business legend. Docs, demo values, the data
6+
generator, and the operational layer are aligned to this document, not the
7+
other way around.
8+
9+
Downstream consumers:
10+
11+
- **Generator spec / unit economics** — order volumes, channel mix, and
12+
seasonality below are the fixed frame; exact distributions are pinned in the
13+
generator spec.
14+
- **Docs sweep** — README, `docs/architecture.md`, and the DV2 docs inherit
15+
the storyline and the vocabulary from §5.
16+
- **Operational layer design** — the three ops surfaces (order timeline,
17+
stuck-orders worklist, exception inbox) serve the workflows in §4.
18+
19+
---
20+
21+
## 1. The company
22+
23+
A **mid-size Russian own-brand (private-label) importer of small kitchen
24+
appliances**. Product design, QC, and the brand live in Russia; manufacturing
25+
is contracted to audited factories in China. The archetype is well established
26+
on the Russian market — own-brand appliance importers of this shape have grown
27+
from ~4.7 to ~13–14 B ₽ of annual revenue over the last five years
28+
([Forbes on the Kitfort founders](https://www.forbes.ru/svoi-biznes/533609-kak-prodavcy-bytovoj-tehniki-postroili-kompaniu-s-vyruckoj-bolee-14-mlrd-rublej)).
29+
The demo company sits earlier on that curve: **~2,000 orders/day, ~3–5 B ₽/year**
30+
— large enough for real multi-channel pain, small enough that a single data
31+
platform team is plausible.
32+
33+
**Positioning.** Mid price segment with a deliberate value twist: the product
34+
*looks* premium but sells at an accessible price (marketplace bestsellers at
35+
1,500–3,000 ₽, top lines at 5,000–8,000 ₽). The catalog is small kitchen
36+
appliances: kettles, grills and air fryers, blenders and planetary mixers,
37+
coffee makers, multibakers, kitchen scales, vacuum sealers. A large share of
38+
purchases are **gifts** — which drives both the seasonality (§3) and the CRM
39+
practice of tracking contact birthdays for gift campaigns.
40+
41+
**Brand narrative vs. data.** The marketing story is "smart kitchen" —
42+
app-connected appliances are part of the brand's roadmap and demo narrative,
43+
but **no IoT/device telemetry exists in the v1 data model**. Do not add device
44+
events, firmware versions, or app sessions to seeds or contracts; the data
45+
story is orders, stock, and fulfilment.
46+
47+
**Brand name.** Deliberately unnamed in v1 ("the importer"). Product names in
48+
seeds use neutral category-based names without a brand string; if the
49+
generator spec needs a brand token, that is a generator-spec decision.
50+
51+
### Footprint: 5 locations, 3 jurisdictions
52+
53+
| Branch | Region | Jurisdiction | Role in the legend |
54+
| ------ | ------ | ------------ | ------------------ |
55+
| `msk` | RU | RU | HQ, central warehouse (fulfils all three RU channels), main WMS |
56+
| `spb` | RU | RU | Regional warehouse + B2B showroom |
57+
| `ekb` | RU | RU | Regional warehouse (Urals/Siberia dealer logistics) |
58+
| `dxb` | UAE | UAE | **Re-export trading hub, registered as a free-zone entity in JAFZA (Jebel Ali Free Zone)**: China → Jebel Ali → Gulf market + re-export. Re-export is ~40% of UAE foreign trade; Chinese electronics reach the Middle East through exactly this route |
59+
| `ala` | KZ | KZ | **EAEU hub**: Kazakhstan local market + EAEU customs contour |
60+
61+
Each branch is a separate legal entity in its jurisdiction, which is why
62+
per-jurisdiction PII satellites and per-branch row policies in the DV2 vault
63+
are a business requirement, not an architectural flourish: RU customer data
64+
stays in RU, UAE data in UAE, KZ data in KZ.
65+
66+
The `dxb` entity's free-zone registration is load-bearing for the economics:
67+
goods held in JAFZA sit **outside UAE customs territory** (no import duty
68+
until they enter the mainland, none at all on re-export), and qualifying
69+
free-zone trading income is taxed at 0% under the UAE corporate tax regime.
70+
That is what makes a China → Jebel Ali → Gulf/Africa consolidation-and-re-export
71+
leg cheaper than routing the same containers through the mainland — and why
72+
the branch exists as a trading hub rather than a sales office.
73+
74+
## 2. Channels and order shapes
75+
76+
Three sales channels with deliberately asymmetric economics — most of the
77+
**money** is wholesale, most of the **order count** is marketplaces:
78+
79+
| Channel | Who buys | Order shape | Typical check | Volume |
80+
| ------- | -------- | ----------- | ------------- | ------ |
81+
| **B2B wholesale** | Several hundred active dealer accounts: regional appliance chains, gift/corporate buyers, independent e-com sellers | Multi-line orders (boxes of units), negotiated prices, deferred payment, retro-bonus program | 30,000–80,000 ₽ | ~150–200 orders/day |
82+
| **Marketplaces (FBS)** | Retail buyers on Wildberries / Ozon | Single-item orders fulfilled from the importer's own warehouse (FBS) | 1,500–3,000 ₽ | ~1,800 orders/day |
83+
| **Own D2C site** | Retail buyers, brand loyalists, gift shoppers | Small orders; the only channel with session/funnel telemetry | 2,000–5,000 ₽ | small share of orders |
84+
85+
Market grounding: in the small-appliance category ~76% of purchases happen
86+
online and ~92% of online purchases go through marketplaces; category sales
87+
grew ~50% on Wildberries and ~65% on Ozon in 2025
88+
([Oborot.ru](https://oborot.ru/articles/rynok-bytovoj-tehniki-82-i271420.html),
89+
[AdIndex](https://adindex.ru/news/researches/2026/05/26/345316.phtml)).
90+
An importer with a 90/10 marketplace/D2C split in retail order count is the
91+
norm, not an outlier.
92+
93+
Channel-specific mechanics that show up in the data:
94+
95+
- **Retro-bonuses (B2B).** Dealers earn quarterly rebates for hitting volume
96+
thresholds. This is what "loyalty" means in this business — dealer bonus
97+
accrual, not retail points.
98+
- **CRM-driven B2B sales.** Wholesale runs on Bitrix24: deals, dealer
99+
organizations, and decision-maker contacts, including birthdays — the gift
100+
assortment makes personal dates a real sales trigger.
101+
- **Marketplace mechanics (FBS).** Commission, returns with a return window,
102+
price promos dictated by platform sales events. Stock is *shared* with the
103+
other channels — see the oversell case in §4.
104+
105+
## 3. Seasonality and supply
106+
107+
- **Demand peaks are gift-driven**: New Year (Nov–Dec, the dominant peak),
108+
March 8, a secondary February 23 bump, plus marketplace-dictated sale events
109+
(11.11, platform birthdays).
110+
- **Supply is containers from China**: 40–60 day lead time (factory → sea →
111+
customs → central warehouse). Procurement for the New Year peak is committed
112+
in early autumn; a late or customs-stuck container is a top-3 business risk
113+
and a core operational storyline (§4).
114+
- **Regulatory frame — mandatory marking.** Russia's Chestny ZNAK (Честный
115+
знак) marking became **mandatory for importers of electronics on
116+
2026-05-01**, with the remaining household-appliance categories (multicookers,
117+
microwaves, vacuum cleaners, etc.) joining on 2026-09-01
118+
([kontur.ru](https://kontur.ru/markirovka/spravka/53675-markirovka_radioelektronnoy_produkcii),
119+
[1C](https://torg.1c.ru/news/v-2026-godu-vsya-elektronika-dolzhna-byt-promarkirovana/)).
120+
For a kitchen-appliance importer in mid-2026 this is a live compliance
121+
program: every imported unit carries a GS1 DataMatrix code. This is why the
122+
warehouse has a first-class marking-code hub (`hub_marking_code`) and why
123+
customs classification (ТНВЭД) lives in the product catalog satellite.
124+
125+
## 4. Operational reality — what the ops surfaces serve
126+
127+
The operations team currently juggles five tools to answer one question about
128+
one order: 1С, Bitrix24, the WMS screen, marketplace seller cabinets, and
129+
logistics Excel sheets. AgentFlow's serving layer exists to replace that
130+
tab-switching with one API surface. Three recurring situations define the
131+
requirements:
132+
133+
1. **Cross-channel stock sync (the freshness case).** One central warehouse
134+
serves all three channels. A wholesale order for 200 units of a bestseller
135+
must be reflected in available-to-promise *before* the marketplaces keep
136+
selling those units — otherwise the importer ships apologies instead of
137+
goods and collects marketplace penalties for cancellations. This is the
138+
business reading of AgentFlow's headline **event → live metric** axis:
139+
second-level freshness is not a vanity benchmark, it is oversell
140+
prevention.
141+
2. **The inbound container.** ETA / customs / receiving status for goods on
142+
the water. Everyone from procurement to B2B sales plans against it
143+
("promise the dealer the grills from the March container?"). Today it lives
144+
in Excel manifests (`excel__*` sources); surfacing it is a roadmap item for
145+
the ops layer.
146+
3. **Kill-the-five-programs triage.** Where is order X? Which orders are stuck
147+
between confirmation and shipment longer than the stage SLA? Which failed
148+
events need a manual decision? These map to the three planned ops surfaces:
149+
**Order 360 timeline**, **stuck-orders worklist**, and **exception inbox**.
150+
151+
## 5. Reinterpretation dictionary
152+
153+
Ground rule: **entity and table names in code do not change.** The legend is
154+
applied by reading existing structures in domain terms (and by docs), not by
155+
renames. The two exceptions are listed in §5.4.
156+
157+
### 5.1 Serving layer (demo store: 4 entities, 6 metrics)
158+
159+
| Code artifact | Reading in the legend |
160+
| ------------- | --------------------- |
161+
| `order` / `orders_v2` (`ORD-YYYYMMDD-NNNN`) | An order from **any** of the three channels. Status flow `pending → confirmed → shipped → delivered / cancelled` is the central-warehouse fulfilment path |
162+
| `user` / `users_enriched` | A **customer**: either a dealer-account contact (B2B) or a retail buyer (D2C/marketplace). `total_spent` = lifetime value; `preferred_category` = appliance category |
163+
| `session` / `sessions_aggregated` | **D2C site sessions only** — marketplaces do not expose session telemetry. Funnel stages (`add_to_cart`, `checkout`) are meaningful for the D2C slice |
164+
| `product` / `products_current` | An own-brand SKU (kettle, air fryer, blender, …); `category` = small-appliance category; `stock_quantity` = units at the central warehouse — the shared pool behind the oversell case |
165+
| metric `revenue` | Confirmed order value across **all channels** |
166+
| metrics `order_count`, `avg_order_value` | All channels; AOV is bimodal by design (30–80k ₽ wholesale vs 1.5–3k ₽ retail) — segment before averaging |
167+
| metrics `conversion_rate`, `active_sessions` | D2C site funnel only |
168+
| metric `error_rate` | Pipeline/data health (an ops signal, not a commerce number) |
169+
170+
### 5.2 DV2 warehouse (hubs, satellites, business vault)
171+
172+
| Code artifact | Reading in the legend |
173+
| ------------- | --------------------- |
174+
| `hub_store` / `store_code` (`msk-01`, `spb-shr-02`, …) | A **branch facility**: central warehouse, regional warehouse, showroom, hub office. Not a retail chain store |
175+
| `hub_customer` | Dealer organizations *and* retail buyers, deduplicated to one golden record; representations live in per-source satellites |
176+
| `hub_supplier` (`supplier_inn` / foreign tax-id) | **Chinese contract factories** (plus a few RU packaging/component suppliers — hence INN support) |
177+
| `hub_employee` | Sales / account managers — B2B attribution |
178+
| `hub_marking_code` (`gs1_gtin`) | Chestny ZNAK GS1 DataMatrix codes — a live importer obligation since 2026-05-01 (§3) |
179+
| `hub_shipment`, `lnk_order_shipment` | Outbound warehouse shipments (split-shipment capable). Inbound container receipts are the planned second leg of this hub |
180+
| `sat_customer_loyalty__bitrix__*` | **Dealer retro-bonus program**: segment, accrued bonus (né "points"), last activity |
181+
| `sat_customer_personal__1c__*` | Contact PII per jurisdiction; `birth_date` is load-bearing — gift campaigns run on contact birthdays |
182+
| `sat_order_marketplace__wb__*` | FBS order facets: platform status, commission, return window |
183+
| `sat_product_catalog__1c__*` (ТНВЭД) | Customs classification — first-class data for an importer, not decoration |
184+
| `sat_product_stock__wms__*` | The shared stock pool (`qty_on_hand` / `qty_reserved` / `qty_available`) that all three channels draw down |
185+
| `bv_customer_mdm` | Golden customer record: 1С is master for identity/PII, Bitrix24 for the commercial relationship |
186+
| `bv_order_canonical` | One status vocabulary across channels — the substrate for Order 360 and stuck-orders |
187+
188+
### 5.3 `record_source` prefixes (source systems)
189+
190+
| Prefix | System | Feeds |
191+
| ------ | ------ | ----- |
192+
| `1c__` | 1С:УТ + 1С:ЗУП (ERP) | Orders, pricing, catalog, suppliers, employees, customer identity |
193+
| `bitrix__` | Bitrix24 CRM | B2B deals, dealer orgs, decision-maker contacts, retro-bonus state |
194+
| `wms__` | Warehouse management | Stock, shipments, marking codes at receiving |
195+
| `site__` | Own D2C site | Sessions, behavior events, site orders |
196+
| `wb__` | Wildberries seller API | FBS orders, commissions, returns |
197+
| `excel__` | Logistics spreadsheets | Container manifests, cross-dock — the inbound-container storyline |
198+
| `pg_ops__` | Postgres OLTP (hot tier) via CDC | Operational order/customer rows promoted into the vault |
199+
| `mp__` (currently `x5__`) | Consolidated marketplace order feed | High-volume retail order history (see §5.4) |
200+
201+
### 5.4 Planned renames / repins (the only code changes the legend requires)
202+
203+
| Change | Scope | Status |
204+
| ------ | ----- | ------ |
205+
| `x5__*` → `mp__*` record_source (+ governance SQL, officer probes, admission tests) | The prefix currently carries the name of the Kaggle seed dataset (X5 Retail Hero) that the demo loader replays as transaction history. Under the legend it is the **consolidated marketplace feed**, and the prefix should say so. Dataset attribution stays in the loader README | Planned (data phase) |
206+
| Demo value repin: currencies to `RUB` (primary), `AED`/`KZT` in branch stories; demo revenue/counts consistent with §1–2 | `contracts/entities/order.yaml` currency examples, NL demo answers, seeded `ORD-*` rows | Planned (data phase, after the generator spec) |
207+
208+
Vocabulary guardrails for all public docs: the company is an **own-brand /
209+
private-label importer** — always that framing; "store" (in `hub_store`) is
210+
rendered as *branch/warehouse*, never as a retail shop; "loyalty" is rendered
211+
as *dealer retro-bonuses*; IoT stays in the brand narrative and out of the
212+
data model.
213+
214+
## 6. Personas × questions × endpoints
215+
216+
Six humans, one machine, one compliance role. Endpoints marked **planned** are
217+
the operational-layer roadmap; everything else is live API surface.
218+
219+
| Persona | Questions they ask | Surface |
220+
| ------- | ------------------ | ------- |
221+
| **Owner / CEO** | "Revenue today vs yesterday? Orders during the НГ peak? Is AOV holding after the price move?" | `GET /v1/metrics/revenue` · `order_count` · `avg_order_value`; `POST /v1/query` (NL: "top products this week") |
222+
| **B2B account manager** | "What has dealer X ordered this quarter? Are they on track for the retro-bonus threshold? Which of my contacts has a birthday before March 8?" | `GET /v1/entity/user/{id}`; `POST /v1/query`; vault: `bv_customer_mdm`, `sat_customer_loyalty__bitrix__*` |
223+
| **E-com / marketplace manager** | "Site conversion this week? Are WB orders flowing or did the feed break? Top SKUs by orders during the sale event?" | `GET /v1/metrics/conversion_rate` · `active_sessions` · `error_rate`; `GET /v1/analytics/top-entities`; `POST /v1/query` |
224+
| **Operations manager** | "Everything about ORD-20260404-1001 — now, in one place. Which orders are stuck pre-shipment past SLA? What failed overnight and needs a human?" | `GET /v1/entity/order/{id}`; `/v1/alerts` (+history/test); `/v1/deadletter` (+replay/dismiss); **planned:** order timeline, stuck-orders worklist, exception inbox |
225+
| **Category / procurement manager** | "Which SKUs sell fastest per branch? What is on hand vs reserved? When does the next container land?" | `GET /v1/search`; `GET /v1/entity/product/{id}`; `POST /v1/query`; vault: `sat_product_stock__wms__*`; container ETA — **planned** (today: `excel__*` manifests) |
226+
| **Data engineer / analyst** | "Which events move this metric? What is the contract and its staleness budget? What changed between contract v3 and v4? Are we inside SLO?" | `GET /v1/catalog`; `/v1/contracts/*` (+versions/diff/validate); `/v1/lineage/*`; `/v1/slo`; `/v1/analytics/*` |
227+
| **AI agent / integration** | Any of the above, programmatically — the agent is one consumer, not the product | Python/TS SDKs, MCP/LangChain/LlamaIndex integrations over the same API: `POST /v1/query` + `/v1/query/explain`, `/v1/entity/*`, `POST /v1/batch`, `/v1/webhooks`, `/v1/stream` |
228+
| **PII officer (per jurisdiction)** | "Who can read dealer-contact PII in `dxb`? Prove RU data never crosses the border" | Not REST: DV2 governance — jurisdiction-scoped officer roles, column-limited analyst grants, per-branch row policies (`warehouse/agentflow/dv2/governance/`, ClickHouse and Postgres variants) |
229+
230+
The bimodal channel mix is what makes several of these questions interesting:
231+
revenue questions need channel segmentation (§5.1), stock questions are
232+
cross-channel by nature, and the operational questions exist precisely because
233+
three channels share one warehouse.
234+
235+
## 7. Sources
236+
237+
Market research grounding the legend (retrieved 2026-07-03):
238+
239+
- [Forbes — история основателей Kitfort](https://www.forbes.ru/svoi-biznes/533609-kak-prodavcy-bytovoj-tehniki-postroili-kompaniu-s-vyruckoj-bolee-14-mlrd-rublej) — own-brand importer archetype and revenue trajectory
240+
- [Oborot.ru — рынок бытовой техники](https://oborot.ru/articles/rynok-bytovoj-tehniki-82-i271420.html) — online/marketplace share in the small-appliance category
241+
- [AdIndex — прогноз продаж бытовой техники](https://adindex.ru/news/researches/2026/05/26/345316.phtml) — category growth on WB/Ozon
242+
- [Контур — маркировка радиоэлектроники](https://kontur.ru/markirovka/spravka/53675-markirovka_radioelektronnoy_produkcii) and [1С — сроки маркировки электроники](https://torg.1c.ru/news/v-2026-godu-vsya-elektronika-dolzhna-byt-promarkirovana/) — Chestny ZNAK timeline for importers
243+
- [Кристалл Форвардинг — импорт через Jebel Ali](https://kf.com.ru/uae) and [DDA — торговые партнёры ОАЭ](https://dda-realestate.com/posts/torgovye-partnery-oae-import-eksport-mezdunarodnaia-torgovlia) — UAE re-export share and the China → Gulf electronics route

0 commit comments

Comments
 (0)