Перейти к содержимому

Структура проекта FDA

Проект на FDA можно узнать по дереву каталогов ещё до чтения кода: бизнес-логика живёт в src/routes/, инфраструктура — в src/lib/, и внутри доменов одинаковый набор файлов. Этот раздел — карта территории: что лежит в каждой папке и по каким правилам туда попадает.

Верхнеуровневая структура

src/
├── routes/ # Бизнес-логика: домены
│ ├── +layout.svelte # корневой layout приложения
│ ├── +page.svelte # главная страница
│ ├── cart/ # домен «корзина»
│ │ ├── +page.svelte # страница: разметка
│ │ ├── +page.server.ts # server load
│ │ ├── +server.ts # HTTP-роут: действия корзины
│ │ ├── rpc.ts # публичное API для других доменов
│ │ ├── client.ts # браузерные вызовы API модуля
│ │ ├── model.server.ts # операции с данными
│ │ ├── controller.svelte.ts # реактивное состояние
│ │ ├── types.ts # типы домена
│ │ ├── constants.ts # константы, enum
│ │ ├── index.ts # публичные экспорты модуля
│ │ └── ui/ # внутренние компоненты домена
│ ├── auth/ # домен «авторизация»
│ └── dashboard/ # домен «панель»
│
├── lib/ # Инфраструктура: без бизнес-логики
│ ├── ui/ # переиспользуемые компоненты
│ │ ├── Button.svelte # примитивы без привязки к доменам
│ │ └── Input.svelte
│ ├── universal/ # клиентский код вне доменов
│ │ └── stores/ # глобальное состояние (тема, локаль)
│ └── server/ # серверные утилиты
│ └── repo/ # внешние источники данных
│ ├── db/ # база данных (Drizzle ORM)
│ ├── redis/ # кэш и сессии
│ ├── vault/ # секреты и credentials
│ └── keto/ # авторизация (OpenFGA)
│
├── scripts/ # скрипты: миграции, сиды, утилиты
└── setup/ # сценарии запуска проекта

Здесь живут домены — верхний уровень фрактальной структуры. Каждый домен соответствует странице или разделу приложения: cart, auth, dashboard. Структура внутри домена одинаковая и описана в разделе 04 (уровни вложенности) и разделе 05 (контракты файлов).

Папки доменов меняются вместе с бизнесом: добавляется раздел «заказы» — появляется routes/orders/, переделывается корзина — изменения не выходят за пределы routes/cart/.

Код, который не отвечает на вопросы бизнеса. Он меняется редко и живёт отдельно от доменов, чтобы не перемешиваться с часто меняющейся бизнес-логикой:

  • lib/ui/ — переиспользуемые компоненты: Button, Input, Modal. Тест на попадание: компонент можно скопировать в другой проект, и он продолжит работать. Привязан к домену — значит, это ui/ внутри домена, а не здесь.
  • lib/server/repo/ — клиенты внешних источников. Каждая папка названа по источнику, а не по домену: db/ не знает, что его данные уйдут в корзину, — он просто умеет ходить в базу.
  • lib/universal/ — клиентский код вне доменов: глобальные сторы темы оформления, локали, сессии.
  • scripts/ — утилиты для разработки: миграции базы, генерация сидов, вспомогательные скрипты.
  • setup/ — сценарии, которые прогоняются при запуске проекта: инициализация окружения, проверка доступности внешних сервисов.

Самый частый вопрос при работе с любой архитектурой. У FDA ответ складывается из одного вопроса и таблицы:

«Отвечает ли код на вопрос бизнеса?» Да — домен. Нет — инфраструктура. Дальше уточняем по типу:

Что добавляетеКудаПример
Новая фича или страницаroutes/<домен>/корзина, страница оплаты
Логика существующей фичифайл в том домене, к которому относитсяподсчёт суммы — cart/model.server.ts
Компонент для одного доменаroutes/<домен>/ui/cart/ui/CartItemCard.svelte
Компонент для многих доменовlib/ui/Button, Input
Работа с внешним источникомlib/server/repo/<источник>/клиент ClickHouse
Глобальное состояниеlib/universal/stores/тема, локаль
Утилита только для модуляroutes/<домен>/utils.tsформат цены корзины
Утилита для всего проектаlib/формат даты
Миграция, сидыscripts/накат схемы базы

Дерево из репозитория example-sveltekit — минимальный домен cart в FDA-проекте:

src/
├── lib/
│ └── server/
│ └── repo/
│ ├── db.ts # коннектор базы (переэкспорт)
│ └── db.mock.ts # мок для разработки
└── routes/
├── +layout.svelte
├── +page.svelte # главная страница
└── cart/ # домен «корзина»
├── +page.server.ts # load: отдаёт корзину
├── +page.svelte # разметка страницы
├── +server.ts # POST: действия с корзиной
├── client.ts # fetch-обёртки для браузера
├── model.server.ts # операции с данными
├── model.fixtures.ts # фикстуры для примеров
├── stores.ts # реактивное состояние
├── types.ts # CartItem, Cart
├── constants.ts # лимиты корзины
└── ui/
└── CartItemCard.svelte # карточка товара

Обратите внимание: model.fixtures.ts и ui/CartItemCard.svelte не входят в обязательный набор — они появились, потому что задаче это понадобилось. FDA задаёт скелет, а необязательные файлы добавляются по необходимости.

→ Домены и субдомены — как выделять домены и вкладывать субдомены

→ Контракты файлов — роль и экспорты каждого файла