Доменная модель
NOTE
Статус: Target design. Документ описывает целевую доменную модель. Соответствующий код реализован частично (см.
backend/internal/core/) или пока не начат. Правила маркировки — в50-processes/documentation-standard.md.
Это index доменной области Tracium. Здесь — карта Bounded Contexts, отношения между ними и Big Picture event storming (хронология ключевых событий).
Для глубокого погружения в конкретный контекст — contexts/.
Для сквозных бизнес-сценариев — scenarios/.
Для справочника моделей данных (агрегаты, сущности, value objects) — data-model.md.
Обозначения Event Storming
Используется классическая нотация. Обязательно к использованию во всех контекстных и сценарийных файлах.
| Стикер | Что обозначает | Markdown-обёртка |
|---|---|---|
| 🟧 Domain Event | Факт, произошёл в прошлом. Past tense. | > [!event] |
| 🟦 Command | Намерение/императив. Что-то должно произойти. | > [!command] |
| 🟨 Aggregate | Граница консистентности, обработчик команд. | > [!aggregate] |
| 🟪 Policy | Реакция: «когда событие X — отправить команду Y». | > [!policy] |
| 🟩 Read Model / View | Проекция для чтения, UI, поиска. | > [!readmodel] |
| 🟫 Actor | Человек или внешняя система, инициирующая команду. | > [!actor] |
| 🔴 Hotspot | Открытый вопрос, конфликт, точка модерации. | > [!hotspot] |
| 🌐 External System | Внешняя система (API поставщика, KMS, …). | > [!external] |
Доменные события именуются на русском языке в past tense (НаблюдениеЗаписано). В скобках — машинное имя для маппинга в код и Kafka-топики (OfferObservationRecorded).
Список Bounded Contexts
| BC | Назначение | Файл |
|---|---|---|
| Catalog (Каталог) | Canonical Product, identity, characteristics, equivalence | contexts/catalog.md |
| Ingestion (Поступление данных) | Опрос поставщиков, маршрутизация credentials, raw payloads, EnrichmentJob | contexts/ingestion.md |
| Offers (Предложения поставщиков) | SupplierOffer (товарная канва), SupplierOfferObservation (append-only) | contexts/offers.md |
| Matching (Сопоставление) | Anti-Corruption Layer между Offers и Catalog: MatchDecision, orphan pool, rematching | contexts/matching.md |
| Enrichment (Обогащение) | AI/LLM-извлечение характеристик и контента | contexts/enrichment.md |
| Pricing (Ценообразование) | Pricing Engine, Price Rules, Custom Pricing Handlers | contexts/pricing.md |
| Visibility (Видимость данных) | DataVisibilityPolicy engine | contexts/visibility.md |
| Moderation (Модерация — AI) | AI-агенты для всех кейсов, требовавших оператора (match_review, orphan_resolution, inferred relationships, critical attr enrichment, price overlap, credential group, ИНН edge). Человек только при escalation. | contexts/moderation.md |
| Search (Поиск) | Поисковый индекс, аналоги, ранжирование | contexts/search.md |
| Estimate (Смета) | Estimate aggregate, оптимизация | contexts/estimate.md |
| Customer (Клиент) | Customer, Pricing Group, Contract, B2B/B2C аутентификация | contexts/customer.md |
| Credentials (Учётные записи) | SupplierCredential, CredentialGroup, fingerprint, lifecycle | contexts/credentials.md |
| Supplier Network (Сеть поставщиков) | Граф поставщиков, роли, связи, SupplyChainTrace | contexts/supplier-network.md |
Context Map
flowchart LR classDef core fill:#fef3c7,stroke:#b45309,color:#1c1917 classDef supporting fill:#dbeafe,stroke:#1d4ed8,color:#1c1917 classDef generic fill:#e5e7eb,stroke:#4b5563,color:#1c1917 classDef external fill:#fae8ff,stroke:#a21caf,color:#1c1917 SUPPLIER[("Внешний API поставщика")]:::external KMS[("KMS / Vault")]:::external USER[("Пользователь B2B/B2C")]:::external LLM[("Внешний LLM провайдер")]:::external Customer["Customer<br/>(B2B/B2C, auth)"]:::supporting Credentials["Credentials"]:::supporting Ingestion["Ingestion"]:::core Offers["Offers"]:::core Matching["Matching<br/>(ACL)"]:::core Catalog["Catalog"]:::core SupplierNet["Supplier Network"]:::supporting Enrichment["Enrichment"]:::supporting Pricing["Pricing"]:::core Visibility["Visibility"]:::supporting Search["Search"]:::supporting Estimate["Estimate"]:::core Moderation["Moderation<br/>(AI-агенты)"]:::supporting CPH["Custom Pricing Handler<br/>(plugin)"]:::generic USER -- "регистрация / login" --> Customer Customer -- "owns (1..N)" --> Credentials Credentials -- "auth_payload (encrypted)" --> KMS Ingestion -- "uses CredentialContext (OHS)" --> Credentials Ingestion -- "fetch (REST/feed/webhook)" --> SUPPLIER Ingestion -- "publishes RawPayloadStored<br/>OfferObservationRecorded (PL)" --> Offers Ingestion -- "uses graph для trust/route" --> SupplierNet Offers -- "OfferSeen / OfferUpdated → Match (ACL)" --> Matching Matching -- "MatchDecided → CanonicalCreated/Linked (PL)" --> Catalog Catalog -- "CanonicalCharacteristicChanged (PL)" --> Enrichment Enrichment -- "CharacteristicEnriched (PL)" --> Catalog SupplierNet -- "SupplyChainTrace (Shared Kernel VO)" --> Offers SupplierNet -- "SupplyChainTrace (SK)" --> Pricing SupplierNet -- "SupplyChainTrace (SK)" --> Visibility Pricing -- "select observation" --> Offers Pricing -- "uses CredentialContext + group" --> Credentials Pricing -- "trigger when API нет ценовых правил" --> CPH CPH -- "PricingAdjustment" --> Pricing Pricing -- "filter / transform" --> Visibility Search -- "Conformist: read projections" --> Catalog Search -- "Conformist" --> Offers Search -- "filter" --> Visibility Estimate -- "use case orchestrator" --> Search Estimate -- "use case orchestrator" --> Pricing Estimate -- "use case orchestrator" --> Matching Estimate -- "filter" --> Visibility Matching -- "ModerationItemAdded / OrphanItemAssigned (PL)" --> Moderation Enrichment -- "EnrichmentReviewRequired (PL)" --> Moderation SupplierNet -- "InferredRelationshipProposed (PL)" --> Moderation Pricing -- "PriceRuleConflictDetected (PL)" --> Moderation Credentials -- "CredentialGroupCandidateOpened (PL, без секретов)" --> Moderation Catalog -- "ManufacturerAliasProposalCreated (PL)" --> Moderation Customer -- "LegalInfoVerificationEdge (PL)" --> Moderation Moderation -- "ProposedAction → ApplyModerationDecision (PL)" --> Matching Moderation -- "ProposedAction (PL)" --> Catalog Moderation -- "ProposedAction (PL)" --> Enrichment Moderation -- "ProposedAction (PL)" --> SupplierNet Moderation -- "ProposedAction (PL)" --> Credentials Moderation -- "ProposedAction (PL)" --> Customer Moderation -- "sandboxed LLM call (ACL)" --> LLM USER -- "search / estimate / order" --> Search USER -- "upload estimate" --> Estimate
Легенда отношений
DDD-паттерны, использованные на карте:
| Сокращение | Паттерн | Что означает |
|---|---|---|
| PL | Published Language | Контекст публикует стабильную схему интеграционных событий (Kafka). Подписчики читают как контракт. |
| ACL | Anti-Corruption Layer | Контекст переводит «грязную» внешнюю модель в свою чистую. Matching изолирует Catalog от Offers. |
| OHS | Open Host Service | Контекст предоставляет стабильный API для нескольких потребителей (Credentials → Ingestion/Pricing). |
| SK | Shared Kernel | Маленький общий kernel из VO (например, SupplyChainTrace). Изменяется по согласованию всех владельцев. |
| Conformist | — | Подписчик принимает модель публикатора как есть (Search → Catalog). |
| Customer/Supplier | — | Upstream диктует, downstream подстраивается. Принимаются изменения через переговоры, не вето. |
Big Picture — хронология (Event Storming Timeline)
Сквозная лента доменных событий, упорядоченная во времени по 4 фазам. Каждое событие принадлежит одному BC (помечено меткой). Подробности — в файлах контекстов.
Фаза 1 — Onboarding клиента и подключение поставщика
| # | Событие | BC | Триггер |
|---|---|---|---|
| 1 | КлиентЗарегистрирован (CustomerRegistered) | Customer | Actor: Visitor → команда ЗарегистрироватьКлиента |
| 2 | КлиентАутентифицирован (CustomerAuthenticated) | Customer | Actor: Customer → Войти |
| 3 | УчётнаяЗаписьПоставщикаПередана (SupplierCredentialProvided) | Credentials | Customer → ДобавитьУчётнуюЗапись |
| 4 | УчётнаяЗаписьЗашифрована (CredentialEncryptedAtRest) | Credentials | Policy: при SupplierCredentialProvided — обернуть DEK через KMS |
| 5 | УчётнаяЗаписьПроверена (SupplierCredentialValidated) | Credentials | Policy: тестовый запрос через коннектор |
| 6 | ГруппаУчётныхЗаписейОбъединена (SupplierCredentialGroupMerged) | Credentials | Policy: совпал fingerprint |
| 7 | ПолитикаВидимостиПрименена (VisibilityPolicyAttachedToSubject) | Visibility | Policy: при КлиентЗарегистрирован — применить дефолты pricing_group |
Подробно: scenarios/customer-auth.md, scenarios/credential-onboarding.md.
Фаза 2 — Поступление данных от поставщика и сборка каталога
| # | Событие | BC | Триггер |
|---|---|---|---|
| 8 | ЗапросНаПоступлениеДанныхСоздан (EnrichmentJobEnqueued) | Ingestion | Schedule / user request / system event |
| 9 | СырыеДанныеПолучены (RawPayloadStored) | Ingestion | Connector → S3 |
| 10 | ТоварнаяКанваОбнаружена (SupplierOfferSeen) | Offers | Parser извлёк (supplier_ref, supplier_sku) |
| 11 | НаблюдениеЗаписано (OfferObservationRecorded) | Offers | Parser → append-only observation |
| 12 | СовпадениеЗапрошено (MatchAttemptRequested) | Matching | Policy: при SupplierOfferSeen или OfferCharacteristicsUpdated |
| 13 | СовпадениеРешено (MatchDecided) | Matching | Matcher: exact / strong / probable / weak / unmatched |
| 14 | КаноническийТоварСоздан (CanonicalCreated) | Catalog | Policy: при MatchDecided=unmatched + valid identity_signature |
| 15 | ХарактеристикаДобавлена (CharacteristicAdded) | Catalog | Policy: новая critical attribute из offer |
| 16 | ХарактеристикаОбогащенаAI (CharacteristicEnrichedByAI) | Enrichment | Policy: при отсутствии critical attr запустить LLM |
| 17 | ЦепочкаПоставокПересчитана (SupplyChainTraceRecomputed) | Supplier Network | Policy: при SupplierOfferSeen или изменении графа |
| 18 | ОчередьМодерацииПополнена (ModerationItemAdded) | Matching / Catalog / Pricing / Credentials / SupplierNet / Enrichment / Customer | Любая ситуация, требовавшая бы оператора → input для AI-агента Moderation BC |
| 18a | КейсМодерацииСоздан (ModerationCaseCreated) | Moderation | Policy: при любом ModerationItemAdded |
| 18b | СобраныСвидетельства (EvidenceGathered) | Moderation | Pre-LLM: read-only сбор данных из source BC |
| 18c | АгентВынесРешение (AgentDecisionEmitted) | Moderation | LLM в sandbox вернул verdict + confidence |
| 18d | РешениеПримененоВИсходномBC (DecisionApplied) | Source BC (Matching / Catalog / …) | Применение ProposedAction через ack-loop |
| 18e | КейсЭскалирован (CaseEscalated) | Moderation | Только при low confidence / security-critical / circuit broken |
Подробно: scenarios/ingestion-flow.md, scenarios/matching-flow.md.
Фаза 3 — Обновления и определение разницы (diff)
| # | Событие | BC | Триггер |
|---|---|---|---|
| 19 | ПовторныйОпросЗапланирован (RefreshScheduled) | Ingestion | Cron / TTL |
| 20 | НаблюдениеЗаписано (новое) (OfferObservationRecorded) | Offers | Append-only |
| 21 | ИзменениеЦеныОбнаружено (OfferPriceChanged) | Offers (derived) | Diff к предыдущему observation |
| 22 | ИзменениеОстатковОбнаружено (OfferStockChanged) | Offers (derived) | Diff |
| 23 | ИзменениеХарактеристикОбнаружено (OfferCharacteristicsUpdated) | Offers | Diff в товарной канве |
| 24 | СтатусЖизненногоЦиклаОбновлён (OfferLifecycleStatusChanged) | Offers | Поставщик пометил discontinued |
| 25 | КаноническийТоварУстаревший (CanonicalDeprecated) | Catalog | Policy: все active offers стали discontinued |
| 26 | ПреемникУстановлен (ReplacedBySet) | Catalog | Manual / supplier feed |
| 27 | ПовторныйМатчингЗапущен (RematchRequested) | Matching | Policy: при OfferCharacteristicsUpdated или новых aliases |
| 28 | СовпадениеУлучшено (MatchUpgraded) | Matching | probable → strong / strong → exact |
Подробно: scenarios/update-and-diff.md.
Фаза 4 — Поиск, цена, смета (клиентский путь)
| # | Событие | BC | Триггер |
|---|---|---|---|
| 29 | СметаЗагружена (EstimateUploaded) | Estimate | Customer → ЗагрузитьСмету |
| 30 | СтрокаСметыРаспознана (EstimateLineParsed) | Estimate | Parser (LLM-assisted) |
| 31 | КандидатыНайдены (SearchCandidatesReturned) | Search | Estimate → НайтиКандидатов |
| 32 | КандидатВыбран (EstimateLineCandidateSelected) | Estimate | Customer / auto если match_confidence ≥ strong |
| 33 | РасчётЦеныЗапрошен (PricingRequested) | Pricing | Estimate → РассчитатьЦену |
| 34 | ИсточникНаблюденияВыбран (PricingObservationSelected) | Pricing | Алгоритм: own credential > group > system |
| 35 | ПолитикаВидимостиПрименена (VisibilityPolicyEvaluated) | Visibility | Policy: фильтр / transform |
| 36 | ПравилоЦеныПрименено (PriceRuleApplied) | Pricing | Цепочка по priority |
| 37 | КастомныйОбработчикВызван (CustomPricingHandlerInvoked) | Pricing | Policy: API поставщика не вернул правил → плагин клиента |
| 38 | ЦенаРассчитана (PricingResolved) | Pricing | С breakdown + observation_source |
| 39 | СметаОптимизирована (EstimateOptimized) | Estimate | ILP / greedy |
| 40 | СметаЗафиксирована (EstimateFinalized) | Estimate | Customer подтвердил |
Подробно: scenarios/analog-search.md, scenarios/pricing-calculation.md, scenarios/estimate-end-to-end.md.
Big Picture — диаграмма (mermaid)
flowchart TB subgraph Phase1["Фаза 1 — Onboarding"] E1["🟧 КлиентЗарегистрирован"] E2["🟧 КлиентАутентифицирован"] E3["🟧 УчётнаяЗаписьПередана"] E5["🟧 УчётнаяЗаписьПроверена"] E6["🟧 ГруппаОбъединена"] E1 --> E2 --> E3 --> E5 --> E6 end subgraph Phase2["Фаза 2 — Каталог"] I1["🟧 СырыеДанныеПолучены"] I2["🟧 ТоварнаяКанваОбнаружена"] I3["🟧 НаблюдениеЗаписано"] I4["🟧 СовпадениеРешено"] I5["🟧 КаноническийТоварСоздан"] I6["🟧 ЦепочкаПоставокПересчитана"] I1 --> I2 --> I3 --> I4 --> I5 I3 --> I6 end subgraph Phase3["Фаза 3 — Diff"] U1["🟧 ПовторныйОпросЗапланирован"] U2["🟧 НаблюдениеЗаписано (new)"] U3["🟧 ИзменениеЦеныОбнаружено"] U4["🟧 ИзменениеХарактеристикОбнаружено"] U5["🟧 ПовторныйМатчингЗапущен"] U1 --> U2 --> U3 U2 --> U4 --> U5 end subgraph Phase4["Фаза 4 — Клиентский путь"] C1["🟧 СметаЗагружена"] C2["🟧 СтрокаРаспознана"] C3["🟧 КандидатыНайдены"] C4["🟧 РасчётЦеныЗапрошен"] C5["🟪 Policy: API без правил?"] C6["🟧 КастомныйОбработчикВызван"] C7["🟧 ЦенаРассчитана"] C8["🟧 СметаОптимизирована"] C1 --> C2 --> C3 --> C4 --> C5 C5 -->|да| C6 --> C7 C5 -->|нет| C7 C7 --> C8 end Phase1 -.-> Phase2 Phase2 -.-> Phase3 Phase2 -.-> Phase4 Phase3 -.-> Phase4
Принципы снижения связности (decoupling)
Система спроектирована так, чтобы изменение в одном BC не каскадно ломало другие. Правила:
- Нет прямых вызовов между Core BC — общение только через интеграционные события Kafka (Published Language). Синхронные in-process вызовы допустимы лишь внутри одного процесса (например, Estimate → Pricing внутри
estimate-builder). - Anti-Corruption Layer на границах — Matching изолирует Catalog от любых форм supplier-данных. Любые поля поставщика парсятся в собственную модель Offers, оттуда — в Matching, и только потом — в Catalog.
- Shared Kernel минимизирован — общий kernel:
SupplyChainTrace,Money,CredentialContext,Subject. Любое изменение — RFC + согласие всех владельцев. - Open Host Service для plugin-точек — Custom Pricing Handler регистрируется через Open Host без знания внутренностей Pricing.
- Eventual consistency между BC — invariant внутри агрегата строгий, между BC — eventually consistent. Идемпотентность consumer’ов обязательна (см.
../20-architecture/event-sourcing.md). - Read-проекции вместо запросов — Search не дёргает Catalog API; читает свою проекцию, обновляемую consumer’ом из Kafka.
- No-proxy — клиент не дожидается поставщика синхронно. Pricing graceful degrades на stale observation, ставит async
EnrichmentJob(см.../20-architecture/integration-patterns.md). - AI-модерация по умолчанию — все ручные кейсы (match review, orphan resolution, inferred relationships, critical attr review, price overlap, credential group merge, ИНН edge) идут в Moderation BC и обрабатываются AI-агентами в детерминированном sandbox. Человек подключается только при escalation (low confidence / security-critical / circuit breaker). Source BC не имеет ручного UI — только Moderation BC может выписать кейс на человека.
Сценарии (end-to-end)
| Сценарий | Файл |
|---|---|
| Поступление данных от поставщика → хранилище | scenarios/ingestion-flow.md |
| Обновления + diff-detection + rematching | scenarios/update-and-diff.md |
| Новый offer → каноническое сопоставление | scenarios/matching-flow.md |
| Подбор аналогов | scenarios/analog-search.md |
| Подключение клиентской credential поставщика | scenarios/credential-onboarding.md |
| Регистрация / login B2B и B2C клиентов | scenarios/customer-auth.md |
| Расчёт цены (с custom handlers) | scenarios/pricing-calculation.md |
| Полный путь сметы (Acts 1–8) | scenarios/estimate-end-to-end.md |
| AI-модерация (автоматическая обработка очереди) | scenarios/ai-moderation-flow.md |
Связанное
ubiquitous-language.md— единый словарь.../GLOSSARY.md— расширенный глоссарий.data-model.md— справочник моделей данных.product-identity.md— deep-dive в identity (для Catalog).characteristics.md— deep-dive в характеристики (для Catalog).../20-architecture/module-layout.md— отображение BC на сервисы и модули.../20-architecture/event-sourcing.md— как события сохраняются и публикуются.../20-architecture/integration-patterns.md— паттерны интеграции с поставщиками.