Правила Документирования CQRS
Назначение
Pin использует CQRS поверх микросервисной архитектуры. Документ фиксирует поведенческие инварианты
операций-команд, операций-запросов, event-consumers и background jobs — те правила, которые спека обязана
отразить в разделе ## Алгоритм и в описании поведения. Это не про имена классов, хендлеров и валидаторов и
не про файловую раскладку: уровень изложения задан Уровнем изложения ТЗ,
детали реализации в ТЗ не описываются.
Command
Операция, меняющая состояние:
- меняет только owned state своего сервиса;
- имеет явную границу согласованности (что меняется атомарно), правила идемпотентности и конкурентного доступа (optimistic concurrency);
- не вызывает другой сервис внутри локальной транзакции;
- возвращает именованную response-модель, а не сырой агрегат;
- аудит, результат идемпотентности и публикацию интеграционных событий (через outbox) фиксирует в той же границе согласованности, если они относятся к изменению.
Операция не должна держать транзакцию во время долгого внешнего вызова без отдельного обоснования, timeout, retry и reconciliation.
Query
Операция чтения:
- не меняет operational state;
- описывает source of truth или read model, фильтры, сортировку, пагинацию, tenant trimming и masking;
- если читает stale-проекцию, указывает freshness SLA и поведение при stale/missing проекции;
- не возвращает сырую коллекцию, а использует именованную response-модель;
- не читает чужую БД напрямую.
Read model не становится source of truth. Если для текущего решения нужна гарантированная актуальность (публикация лота, доступность брони, начисление комиссии агенту), запрос читает source of truth владеющего сервиса или выполняет явно описанный owner API lookup.
Event Consumer
Consumer описывается поведенчески:
| Поле | Что Описать |
|---|---|
| Consumed event | Тип события, версия, топик, ключ. |
| Inbox key | Как обнаруживаются повторы (идемпотентность). |
| Changed data | Owned entities, реплики, read models, cache/search indexes. |
| Produced events | Что публикуется через outbox после успешной обработки. |
| Replay behavior | Как consumer ведёт себя при replay/backfill. |
Consumer идемпотентен: повторная доставка одного события не даёт двойного эффекта. Consumer не должен синхронно спрашивать producer-сервис, если payload события обязан содержать достаточный snapshot.
Микросервисная Граница
- Микросервис изменяет только свои owned entities.
- Cross-service foreign keys запрещены.
- Cross-service consistency строится через Kafka-события, Inbox/Outbox, saga, компенсации и reconciliation.
- Internal API lookup допустим только когда ответ нужен для текущего решения; такой вызов описывает timeout, retry/circuit breaker, fallback и stale behavior.
- Distributed transaction между микросервисами запрещена без отдельного ADR.
DoR И DoD
Задача не готова (DoR), если для операции не зафиксирован бизнес-контракт: актор и доступ, входные и выходные модели, бизнес-правила и инварианты, коды ошибок, публикуемые/потребляемые события и acceptance criteria. Задача не завершена (DoD), если реализованное поведение (изменяемое состояние, события, ошибки), тесты и наблюдаемость расходятся с этим контрактом.
Связанные документы
- Уровень изложения: spec-authoring-altitude-rules.md.
- Общие требования: cross-cutting-document-requirements.md.
- Структура алгоритма: algorithm-documentation-rules.md.