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

FAQ и Checklist

Здесь собраны вопросы, которые возникают при первых доменах, — и чеклист, по которому стоит прогонять каждый модуль перед мержем. Чеклист короткий: восемь пунктов, минута на проверку. Он же — критерий готовности для AI-агента со скиллом FDA.

schema.ts относится к слою Model, но живёт он не в домене, а рядом с repo: lib/server/repo/db/schema.ts. Причина: таблицы описывают источник данных целиком, а не отдельный домен. Нужен, если в проекте есть ORM (Drizzle, Prisma); в домене без своей таблицы файла не будет.

// lib/server/repo/db/schema.ts — пример на Drizzle
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
email: text("email").unique().notNull(),
createdAt: timestamp("created_at").defaultNow(),
});
// ❌ schema.ts — не для логики
export const users = pgTable("users", { ... });
export const getUserById = async (id: string) => { ... }; // это модель

Это имена одной роли — реактивного состояния и обработчиков ввода. Контракт не меняется, выбирается имя:

  • controller.svelte.ts — раны Svelte 5 (предпочтительно для новых проектов);
  • stores.ts — классические сторы Svelte 4;
  • composables.ts — Nuxt.

Внутри одного проекта договоритесь об одном варианте — фрактальность работает, когда модули похожи друг на друга.

Да. Это централизованный публичный API: потребители импортируют из папки модуля, а не из его внутренних файлов. Внутренние переименования перестают ломать соседей. Реэкспортирует rpc, контроллер, types, constants — и не реэкспортирует model.server.ts: серверный код не должен утекать через публичный API.

ui/ внутри модуля — для компонентов, которые используются только этим модулем. Компоненты, общие для субдоменов одного домена, — в domain/_shared/. Компоненты, нужные нескольким доменам, — в lib/ui/:

src/
├── lib/
│ └── ui/ # общие для всех доменов
│ └── Button.svelte
└── routes/
└── cart/
├── ui/ # только для cart
│ └── CartItemCard.svelte
└── _shared/ # общие для субдоменов cart
└── QuantityInput.svelte

Тема оформления, локаль, сессия — состояние всего приложения живёт в lib/universal/stores/, а не в доменах. Признак, что стор глобальный: он переживает переход между страницами и не принадлежит ни одной фиче.

Это точка входа серверных данных. Сегодня страница не ждёт ничего с сервера — а завтра понадобится load или actions, и они появятся в уже готовом месте, без переосмысления структуры. Пустой файл стоит копеечку, а якорь для будущего кода — нет.

Отправку форм принимайте в actions серверной части страницы, а не в fetch из разметки. Так валидация и побочные эффекты живут на сервере:

routes/cart/+page.server.ts
import { addToCart } from "./model.server";
export const actions = {
add: async ({ request }) => {
const data = await request.formData();
const productId = String(data.get("productId"));
return { cart: await addToCart(productId, 1) };
},
};

Страницы вида /orders/42 — через подпапку [id]/. Это публичный субдомен со всей обычной структурой: load читает params.id, модель достаёт запись.

Можно ли импортировать код другого домена?

Заголовок раздела «Можно ли импортировать код другого домена?»

Только через его rpc.ts — модель, repo и контроллеры соседей под запретом. Подробности и примеры — в разделе о кросс-доменном взаимодействии.

Да, и за ними полезно следить. Ближе всех по духу — FEOD (Fractal Entity Oriented Design): та же фрактальность и та же строгая однонаправленность импортов, только цепочка слоёв зафиксирована как common → modules → pages → app, а единицей декомпозиции выступают сущности и модули вокруг них. Сходятся FDA и FEOD в главном: границы модулей и направление зависимостей важнее имён файлов, которые диктует фреймворк; расходятся в акцентах — FDA строит домены от требований бизнеса и держит серверную часть (модель, repo) внутри домена, FEOD сильнее ориентирован на сущности и формализацию через ESLint-правила.

Если проект уже живёт по другой архитектуре, FDA не требует переписывания: доменный подход вводят постепенно, начиная с новых фич. А выбирая подход для нового проекта, посмотрите на оба — терминология разная, но отвечают они на одни и те же вопросы: куда положить код, откуда его импортировать и как не сломать границы при росте.

Прогоните модуль по списку. Каждый пункт — проверка одного принципа FDA, поэтому за «мелким» нарушением обычно стоит настоящая проблема.

  1. У каждого модуля есть index.ts — публичный API на месте.
  2. +page.server.ts существует в каждом модуле — пусть даже пустой.
  3. Если есть +layout.server.ts, есть и парный +layout.svelte.
  1. Каждый файл экспортирует только свой контракт: types.ts — типы, constants.ts — константы, модель — операции.
  1. UI не импортирует repo, model.server и rpc напрямую — только контроллер, типы и константы.
  2. model.server.ts и rpc.ts не содержат импортов UI-компонентов.
  3. Кросс-доменные импорты идут только через rpc.ts соседа.
  1. Компоненты, нужные нескольким модулям, живут в lib/ui/, а не в ui/ одного из них.

Остались вопросы — создайте issue в репозитории проекта.