Основные концепции FDA
FDA строится на трёх концепциях, которые объясняют всё остальное: фрактальность задаёт форму, слои задают порядок, контракты задают границы. Разберём каждую — и посмотрим, как вместе они отвечают на вопрос, который возникает в любом большом проекте: «куда положить этот код и откуда его импортировать».
🌀 Фрактальность
Заголовок раздела «🌀 Фрактальность»Фрактальность — это одинаковая структура на всех уровнях: компонент → субдомен → домен → приложение.

Практически это работает так. Корзина — домен cart. Список товаров в корзине — субдомен cart/items/, и внутри него та же структура, что и у самого домена: своя модель, свой контроллер, свои типы. Ещё глубже — карточка товара, компонент в cart/items/ui/. На каждом уровне вы находите те же роли файлов в тех же местах.
Зачем это нужно:
- Навигация без карты. Открыв любой модуль FDA-проекта, вы уже знаете, где модель, а где разметка. Не нужно читать весь проект, чтобы найти одно место.
- Порог входа ниже. Новому разработчику достаточно показать структуру одного домена — остальные устроены так же.
- Масштабирование без деградации. Проект растёт в ширину (новые домены), и вглубь по мере нарастания функционала. Сложность логики одного модуля имеет лимит и при превышении бьется на субдомены.
| Термин | Что это | Пример |
|---|---|---|
| Домен | Верхний уровень бизнес-логики, соответствует странице или разделу приложения | cart, auth, dashboard |
| Модуль | Единица функциональности; модуль — тоже домен | cart |
| Субдомен | Модуль внутри модуля; _sub не имеет своего URL (роута), sub — имеет. Также является доменом | cart/_checkout, cart/items |
Подробнее о доменах и субдоменах — в разделе 04.
🧱 Бизнес-логика и инфраструктура
Заголовок раздела «🧱 Бизнес-логика и инфраструктура»Весь код проекта делится на две категории, и это первое решение, которое вы принимаете для любого нового файла:
| Категория | Путь | Что там | Как меняется |
|---|---|---|---|
| Инфраструктура | src/lib/* | Код без бизнес-логики: компоненты-примитивы, клиенты внешних сервисов, утилиты | Редко и мелкими правками |
| Бизнес-логика | src/routes/* | Домены и всё, что относится к задачам бизнеса | Постоянно, целыми фичами |
Правило выбора простое. Задайте вопрос: «что делает этот код?»
- Отвечает на вопрос бизнеса — «оформить заказ», «показать корзину», «разрешить доступ» — это бизнес-логика, ей место в домене.
- Работает в любом проекте без изменений, атомарный компонент, клиент Redis, валидатор email — это инфраструктура, ей место в
lib/.
src/├── lib/ # инфраструктура: меняется редко│ ├── ui/ # Button, Input, Modal — без бизнес-логики│ └── server/ # клиенты внешних сервисов└── routes/ # бизнес-логика: меняется часто ├── cart/ # домен «корзина» └── auth/ # домен «авторизация»Внутри каждого модуля данные проходят один и тот же путь. Пять слоёв, направление строго сверху вниз:
| Слой | Файлы | Отвечает за | Не знает про |
|---|---|---|---|
| Repo | lib/server/repo/* | Подключение к внешним источникам: база, кэш, секреты | Бизнес-правила домена |
| Model | model.server.ts, schema.ts | Операции с данными и правила домена: «в корзине не больше 50 товаров» | HTTP, интерфейс, состояние UI |
| RPC | rpc.ts, +server.ts, client.ts | Обработку запросов: парсинг, вызов модели, формат ответа | Как хранятся данные |
| Controller | controller.ts, stores.ts, state.ts | Реактивное состояние и реакцию на действия пользователя | Прямой доступ к источникам данных |
| UI | +page.svelte, ui/ | Отображение и ввод | Запросы, расчёты, хранение |
Правила импортов
Заголовок раздела «Правила импортов»Слои — это не только роли, но и направление зависимостей:
- Импорты смотрят только вниз. UI использует контроллер, контроллер — RPC и клиентские вызовы, RPC — модель, модель — repo. Обратных импортов не существует.
- UI никогда не импортирует
model.server.ts. Модель живёт на сервере и тянет за собой repo с подключением к базе — такой импорт утянет серверный код в клиентский бандл. - Model не знает про HTTP. Модель вызывают из load-функции, из RPC или из фонового скрипта — результат одинаков.
- Repo — единственное место, где живёт подключение к источнику данных. Поменяете базу — правите один слой, остальной домен не замечает подмены.
Как это выглядит в живом коде — на примере одного клика по кнопке «удалить товар» в корзине:
Полный разбор домена cart по файлам — в разделе 08, где тот же код разбирается по шагам.
🤝 Явные контракты
Заголовок раздела «🤝 Явные контракты»Каждый файл в домене имеет одну роль и один набор экспортов: types.ts экспортирует только типы, model.server.ts — только операции с данными, policy.ts — только правила доступа.
Это правило экономит время в трёх местах:
- Поиск. Нужна валидация формы? Она не в
types.tsи не в разметке — она вtemplates.tsили в модели. Поиск по ролям, а не по всему коду. - Ревью. Нарушение контракта видно без чтения диффа целиком: логика в
constants.tsбросается в глаза. - Генерация. AI-агентам контракты дают каркас: агент знает, какой файл создавать и что в него писать, — и не перемешивает слои.
Контракты каждого файла с примерами кода — в разделе 05.
🧭 Framework-agnostic
Заголовок раздела «🧭 Framework-agnostic»Слои и контракты не привязаны к мета-фреймворку. Меняются имена файлов и место папки по конвенции роутинга — роли остаются теми же:
| Концепция | SvelteKit | Next.js | Nuxt |
|---|---|---|---|
| Страница | +page.svelte | page.tsx | index.vue |
| Layout | +layout.svelte | layout.tsx | layout.vue |
| Server load | +page.server.ts | page.server.tsx | setup.ts |
| Server actions | +page.server.ts | actions.ts | server/ |
| API-роуты | +server.ts | route.ts | /server/api/ |
| RPC | rpc.ts | rpc.ts | rpc.ts |
| Model | model.server.ts | model.ts | model.ts |
Обратите внимание на последние две строки: RPC-слой и модель во всех фреймворках называются одинаково. Это ядро FDA — то, что переносится между стеками без изменений.
🔗 Следующие шаги
Заголовок раздела «🔗 Следующие шаги»→ Структура проекта — как выглядит дерево каталогов и куда кладётся новый код
→ Контракты файлов — роль и экспорты каждого файла