Спецификация сервиса — контракт между бизнесом и разработкой. Описывает один Bounded Context в доменных терминах: заполняется совместно бизнес-аналитиком, архитектором и разработчиками, читается человеком, используется AI-агентом как memory bank и как источник для генерации кода, диаграмм (Structurizr) и индексации (GraphRAG).
Перед заполнением — соберите данные через Event Storming. Workshop на 4–8 часов выявляет события, акторов, бизнес-правила, агрегаты и границы контекстов; каждый артефакт ложится в конкретный раздел спеки. См. стратегические паттерны DDD.
Заполненные примеры по сервисам маркетплейса — в разделе Кейс.
Принципы
- Единица спеки — Bounded Context, не агрегат. Один контекст = одна спека. Если в контексте несколько агрегатов — спека разбивается на корневой файл (секции уровня контекста) и по файлу на агрегат. Дробить контекст по агрегатам на отдельные спеки нельзя: Ubiquitous Language, Context Map, роли — свойства контекста.
- Домен без техники. Все секции, кроме «Технической реализации», — в доменных терминах. Фреймворки, аннотации, схема БД, механизмы доставки (Outbox), топики, стек — только в «Технической реализации».
- Ничего не дублируется. Каждый факт — в одном каноническом месте; остальные ссылаются. События описываются у агрегата-владельца; переходы — в матрице жизненного цикла; ошибки — в командах и бизнес-правилах.
- Карточки + строгие таблицы. Команды, запросы, use cases — карточки
### Имяс размеченными полями (читаемо человеку, парсится агентом). Структурные секции (доступ, события, интеграции) — таблицы с нормализованным словарём. - Контекст не претендует на знание соседей. Соседние контексты — только как рёбра на стыке (Context Map). Полная Context Map и классификация субдоменов — артефакт уровня домена.
Раскладка файлов
docs/spec/
<service>-spec.md # корень: секции уровня КОНТЕКСТА
aggregates/
<aggregate>.md # по файлу на агрегат: секции уровня АГРЕГАТА
Домен-юнит — всегда в отдельном файле aggregates/<name>.md, даже если он один и на любом уровне зрелости; корень держит только секции контекста. Домен-юнит — это агрегат на Уровне 3; на Уровне 1–2 (DDD-агрегатов нет) — центральная сущность контекста (product.md, notification.md). Единая структура «корень + aggregates/» во всех спеках.
Минимальный frontmatter — для идентичности чанка при индексации: корень context + bounded-context + level; файл юнита context + aggregate + level. Больше ничего: что выводимо из путей/имён или есть в теле — не дублируем.
Секции уровня контекста (корневой файл)
| № | Раздел | Что внутри |
|---|---|---|
| 1 | Bounded Context | контекст, субдомен (Core/Supporting/Generic), владелец, миссия; таблица агрегатов; что внутри/вне границы; стыки |
| 2 | Интеграции (Context Map) | контекст-карта (одна mermaid) + таблица рёбер (нормализованный словарь) + контракты (ссылки на OpenAPI/AsyncAPI) |
| 3 | Ubiquitous Language | глоссарий контекста; «не путать» |
| 4 | Роли и доступ | роли + общие ABAC-правила + PII; доступ к операциям — в каждом агрегате |
| 5 | Доменные события | контракт публикуемого языка: «агрегат → внешние события → топик» |
| 6 | Use Cases | сквозные сценарии карточками ### UC-N |
| 7 | Процессы | Saga / Process Manager: кросс-агрегатные процессы, sequence-диаграммы |
| 8 | UI-спецификация | связь статусов с UI, тексты ошибок для пользователя |
| 9 | Критерии приёмки | Given / When / Then |
| 10 | Нефункциональные требования | таблица: производительность, доступность, согласованность, безопасность, наблюдаемость (целевые значения, без инструментов) |
| 11 | Техническая реализация | единственный технический раздел: контейнеры C2, таблица «слой → стек → реализация», схема БД (ER + индексы) |
Секции уровня агрегата (файл агрегата)
| № | Раздел | Что внутри |
|---|---|---|
| 1 | Доменная модель | агрегат-корень + сущности, value objects (через инвариант), class-диаграмма |
| 2 | Жизненный цикл | статусы + матрица переходов (команды, события, политики/таймауты) + state-диаграмма |
| 3 | Доступ | матрица «операция × роль» + ABAC |
| 4 | Бизнес-правила | список BR-<префикс>NN с типом, командой и кодом ошибки |
| 5 | Команды | карточки: Переход · Вход · Предусловия · Логика · Эмитит · Ошибки |
| 6 | Доменные события | таблица «событие — триггер — scope — подписчики» |
| 7 | Запросы | карточки: Вопрос · Параметры · Возвращает · Логика (источник чтения, фильтр, согласованность) |
Конвенции
- Value Objects описываются через инвариант, который защищают (не через поля/типы — это БД). Для sum-типов — варианты (
Discount:Percentage | Fixed). - Бизнес-правила — код с префиксом агрегата (
BR-O01,BR-D01), чтобы не сталкивались. - Команды vs реакции/политики. В «Командах» — только публичные команды от акторов. Реакции на события и политики (таймауты) не выносятся отдельными карточками — они уже в матрице переходов и «Доменных событиях».
- Каталога ошибок нет. Коды — в «Командах» (поле «Ошибки») и «Бизнес-правилах»; тексты для пользователя — в «UI»; HTTP-маппинг — артефакт API.
- Кросс-агрегатные ссылки — по ID, без FK (
<other>_id— логическая ссылка); это отражается и в class-диаграммах, и в ER. - Интеграции — нормализованный словарь (
inbound|outbound|bidirectional,sync|async,customer-supplier|conformist|ohs). Контракты на рёбрах — ссылки: REST → OpenAPI, async → AsyncAPI; владелец по типу связи. - Диаграммы: поведенческие (state machine, sequence) рисуются вручную; одна контекст-карта в «Интеграциях»; ER — в «Технической реализации». Полные C1/C2/C3 при необходимости генерирует Structurizr из таблиц.
Уровень зрелости — глубина спеки
Глубина = уровень зрелости сервиса (одна ось 0–3):
| Уровень | Архитектура | Что меняется |
|---|---|---|
| 0 — As-is | реверс из кода без бизнес-брифа (ucp-spec-tier-0) | снимок «как сейчас»; not-declared для пробелов; точка отсчёта для миграции |
| 1 — Слоёный | Controller → Service → Repository, без usecase-pattern | DDD-агрегатов нет (один «модуль»); «Доменная модель» = ER + таблицы; «Доменные события» и «Процессы» пропускаются с пометкой; центральная сущность всё равно в aggregates/<name>.md |
| 2 — Use Case Pattern | usecase-pattern (UseCase + Handler) | команды = UseCase-классы; события — если реально публикуются; CQRS + Read Model — опция уровня |
| 3 — DDD + Hexagonal | агрегаты, доменные события, ports/adapters, ArchUnit | полная глубина, разбивка по агрегатам |
Уровень 0 — as-is из кода. Существующий сервис без бизнес-брифа: спеку генерирует скилл ucp-spec-tier-0, читая код, миграции и конфиги; ставит level: 0, не выдумывает агрегаты там, где код anemic, не классифицирует «правильно/неправильно»; отсутствующие данные помечает литералом not-declared — явный gap-сигнал. Это база для онбординга и точка отсчёта для миграции на нужный уровень.
Раздел, неприменимый на текущем уровне, не опускается молча — пишется заголовок и однострочная пометка («Не применимо на Уровне 1»).
Дальше
- Заполненные примеры — Кейс маркетплейса: спеки сервисов в этом формате.
- Скиллы AI-агента для генерации и ревью спеки — настройка:
ucp-spec-design(по бизнес-описанию),ucp-spec-tier-0(из кода),ucp-spec-review(design-критик). - Уровни зрелости — Use Case Pattern (1–3).
- Стратегические паттерны DDD — границы контекстов и Context Map.