0014 — Структура продуктовых модулей в монорепозитории¶
- Дата: 2026-08-22.
- Статус: Принято пользователем.
- Ответственный: владелец проекта.
Контекст¶
Решение 0012 определило продуктовые модули, тарифные module entitlements и права внутри модуля, но не закрепило физическое размещение кода. По мере роста SKUARO код одной функции мог быть разнесён по apps, packages и общим тестам, что усложнило бы управление модулями, правами и тарифами.
Решение¶
Обязательная классификация¶
До создания новой папки, пакета, сервиса или маршрута новая разработка обязательно классифицируется как:
- продуктовый модуль;
- общая возможность платформы;
- внешняя интеграция;
- общий технический пакет;
- runtime-application;
- инфраструктура.
Если класс неоднозначен, размещение обсуждается с владельцем проекта до изменения структуры. Принятая классификация, точки интеграции, зависимости и права фиксируются до реализации.
Физическая структура¶
- Продуктовые модули размещаются в
modules/<module-id>. - Первый каталог —
modules/today; маршрут модуля —/today. - Общие SaaS-возможности размещаются в
platform/. - Адаптеры внешних систем размещаются в
integrations/. packages/содержит только общие технические пакеты без бизнес-логики одного модуля.apps/web,apps/apiиapps/workerявляются точками запуска и композиции, а не хранилищем модульной бизнес-логики.infra/остаётся общим контуром deploy, runtime, backup и reverse proxy.- Пути и идентификаторы используют английские
kebab-caseили принятые в коде имена; русские названия остаются в UI и документации.
Граница продуктового модуля¶
Каталог modules/<module-id> может содержать:
module.yamlс постоянным ID, UI-названием, lifecycle status, маршрутами, permissions и явными зависимостями;contracts/,domain/,server/,web/, опциональныеworker/иdatabase/;tests/для модульных проверок;README.mdиdocs/для связанного с кодом технического описания.
Необязательные папки заранее не создаются. Состав каталога отражает фактическую реализацию.
Связь и зависимости¶
- Модуль раскрывает только явные публичные entrypoints и contracts.
- Прямой импорт внутренних repository, domain implementation или таблиц другого модуля запрещён.
- Межмодульная связь идёт через application services, contracts или события.
- Циклические зависимости запрещены.
- Общие SQL-миграции и OpenAPI собираются центральными runner/aggregator из модульных исходников.
- Cross-module E2E и restore checks остаются в корневом
tests/.
Интеграция как часть модуля¶
Внешняя система не считается продуктовым модулем автоматически. Например:
- если Telegram — только канал доставки уведомлений, Bot API adapter живёт в
integrations/telegram; - если Telegram-бот — отдельная тарифная функция со своими сценариями и permissions, бизнес-часть живёт в
modules/telegram-bot, а транспорт — вintegrations/telegram.
Конкретный Telegram-модуль этим решением не утверждается; перед его разработкой требуется отдельное продуктовое решение.
Последствия¶
- Реализовано 2026-08-22: код
todayперенесён изapps/webиpackages/uiвmodules/today, а общие компоненты UI оставлены вpackages/uiпосле классификации. - Общие Auth/Admin/Account capabilities размещены в
platform/, Gmail adapter — вintegrations/email; apps выполняют только композицию. - Введена автоматическая проверка границ импорта, публичных entrypoints, manifest и циклов; перенос проверяется unit, integration, E2E и visual tests.
- Новый каталог продуктового модуля не создаётся до принятия его назначения, границ, интеграций и матрицы прав.
Откат или замена¶
Изменение верхнеуровневой классификации, отказ от modules/<module-id> или разрешение прямых межмодульных зависимостей требует нового ADR и плана миграции.