# C4: четыре уровня архитектуры

> Как описывать архитектуру AI-продукта: от контекста к контейнерам и компонентам, только PlantUML, только as-code

_Источник: https://sii.sergeivolchkov.ru/materials/architecture/c4-levels_



Право «нормально вертеть проект» зарабатывается пониманием архитектуры:
если ты свободно переходишь между уровнями C4 — от «кто нами пользуется»
до «какой модуль за что отвечает», — любое изменение проекта перестаёт
быть страшным.

В 2026 у архитектуры as-code есть второй заказчик: **агент**. Диаграмма
в PlantUML, лежащая в репозитории, — это карта проекта, которую читает
и человек, и Claude Code, и Vibe. Агент с актуальной container-диаграммой
делает на порядок меньше архитектурного бреда.

## Правила игры [#правила-игры]

1. **Только as-code.** Исходник `.puml` лежит в `docs/diagrams/`,
   сгенерированный `.svg` — рядом, оба закоммичены. Figma и Miro
   не используются.
2. **Диаграмма отражает то, что есть**, а не то, что мечталось.
   Разъехались — чинишь диаграмму в том же PR, что и код.
3. **Один уровень — одна диаграмма.** Не смешивай контейнеры с
   компонентами на одной картинке: это главный источник каши.

Генерация SVG:

```bash
plantuml -tsvg docs/diagrams/*.puml
```

## Три уровня — от мира к модулям [#три-уровня--от-мира-к-модулям]

Пролистай: диаграмма закрепляется, а по мере чтения детализируется —
от системы среди внешнего мира до модулей внутри одного контейнера.

<C4Scrollytelling />

## Уровень 4 — Code: не рисуем [#уровень-4--code-не-рисуем]

Диаграммы классов устаревают быстрее, чем их успевают дорисовать. Уровень
кода — это сам код: структура папок, типы и сигнатуры. Если очень нужно показать связи —
генерируй из кода, не рисуй руками.

## Процедура: от описания к модели [#процедура-от-описания-к-модели]

Порядок из [скилла aact-architect](https://github.com/ChS23/aact-architect-skill) —
строго по шагам, не забегая вперёд:

1. **Назови систему** — одна система, одна `System_Boundary`.
2. **Люди и внешние системы** — кто пользуется (`Person`), от чего
   зависим (`System_Ext`: LLM-провайдер, Langfuse — тоже сюда).
3. **Запускаемые единицы и хранилища** — каждая проходит тест
   «запускается отдельно или хранит данные».
4. **Связи** — каждая с подписью *что* течёт и *как*:
   `Rel(web, api, "fetches orders", "JSON/HTTPS")`, а не `Rel(web, api)`.
5. **Границы** — только если контекстов реально больше одного.
6. **Стоп.** На уровень компонентов — только когда понадобилось
   разобрать внутренности одного контейнера.

## Связка с ADR: решение, диаграмма и цена [#связка-с-adr-решение-диаграмма-и-цена]

Каждое значимое изменение диаграммы — следствие решения, а у решения
есть цена. Берём
[шаблон ADR из aact](https://github.com/ChS23/aact/blob/refactor/v3-foundations/ADRs/ADR%20template.md)
и добавляем одно обязательное поле:

```markdown title="docs/adr/ADR-002-model-choice.md"
# Выбор модели для генерации вопросов

## Контекст
<в каких условиях принимается решение: объём, бюджет, требования к качеству>

## Краткое описание решения и его обоснование

### Схема
<фрагмент C4-диаграммы, на который влияет решение>

### Решение
Используем <модель> через <провайдера>, деградация на <дешёвую модель>.

### Обоснование
<почему так, что рассматривали ещё и почему отказались>

## Цена решения
<какой долг берём: стоимость запроса, привязка к провайдеру, лимиты>

## Как покрыть тестами
<какая проверка поймает, что решение перестало соблюдаться>

### Примеры тестов
<ссылки на тесты или evals>
```

Два раздела здесь делают всю работу. &#x2A;*«Как покрыть тестами»*&#x2A; — из
шаблона aact, и это его лучшая идея: решение, которое нечем проверить,
через два спринта существует только на бумаге. &#x2A;*«Цена решения»** — наше
добавление и условие DoD: ADR с пустым полем цены не принимается. Так
технический долг остаётся видимым, а не растворяется в «ну мы же
обсуждали».

Диаграмма показывает «как», ADR отвечает «почему именно так и что нам
это стоит». Живые примеры —
[в ADRs репозитория](https://github.com/ChS23/aact/tree/refactor/v3-foundations/ADRs).
Файл называй по решению, а не по технологии: «Anti-corruption Layer.md»,
а не «Добавили Kafka.md» — через полгода искать будут первое.
