Архитектура реального веб-приложения на Next.js App Router: DAL, авторизация и сквозное тестирование
С выходом Next.js 15 и массовым переходом на App Router веб-разработчики столкнулись с задачей правильной организации структуры проектов. Маршрутизация на основе файловой системы (filesystem-based routing) и React Server Components упрощают создание интерфейсов, но без четкой архитектурной декомпозиции код страниц быстро превращается в монолит из SQL-запросов, проверок авторизации и React-компонентов.
В этом руководстве разбирается декомпозиция промышленного приложения на Next.js App Router на примере архитектуры проекта Taskry. Приложение сочетает локализованные маршруты, изолированный слой доступа к данным (DAL), строгую валидацию через Zod, авторизацию Better Auth и E2E-тестирование в изолированной базе данных.
Архитектурная карта и декомпозиция каталогов
Главный принцип масштабируемой архитектуры на Next.js — папка app отвечает исключительно за маршрутизацию, макеты (layouts) и интерфейс ошибок/загрузки. Бизнес-логика, работа с базой данных, схемы валидации и интеграции выносятся в независимый каталог lib/.
Схема декомпозиции репозитория:
app/
[locale]/
(auth)/ маршруты авторизации с собственным layout
(dashboard)/ защищенная продуктовая зона
(site)/ публичные страницы и лендинг
layout.tsx корневой layout для текущей локали
error.tsx обработчик ошибок уровня маршрута
api/ Route Handlers для внешних API
lib/
data/ Data Access Layer (DAL), DTO и Prisma-запросы
actions/ Server Actions (транспортный слой мутаций)
schemas/ Zod-схемы входных данных и форм
auth.ts серверный экземпляр конфигурации Better Auth
auth-client.ts клиентский API-клиент авторизации
prisma/ схема БД, миграции и сиды (test-seed.ts)
messages/ файлы локализации (next-intl)
cypress/ сквозные E2E-тесты в браузере
Каждый каталог выполняет одну четкую задачу:
app: определяет структуру URL, визуальные оболочки и реакцию на задержки или ошибки.lib/data: проверяет права доступа пользователя на уровне источника данных и возвращает безопасные DTO-модели.lib/schemas: проверяет корректность типов входных данных до их передачи в бизнес-логику.lib/actions: организует вызов серверных функций (Server Actions) из пользовательского интерфейса.
Группы маршрутов (Route Groups) и локализация
Использование групп маршрутов (Route Groups), обозначаемых круглыми скобками (например, (auth) или (dashboard)), позволяет логически разделить приложение на независимые секции без изменения итогового URL.
Преимущества подструктуры:
- Раздельные макеты: продуктовая часть
(dashboard)получает интерфейс с боковым меню и профилем пользователя, а зона(auth)— минималистичный макет без лишней навигации. - Изоляция интерфейсов загрузки: размещение файла
loading.tsxвнутри конкретной группы маршрутов предотвращает появление спиннера на соседних страницах при частичной перерисовке.
Динамический сегмент [locale] организует локализацию через библиотеку next-intl. Префикс языка попадает в URL (/ru/dashboard, /en/dashboard), а корневой app/[locale]/layout.tsx автоматически загружает нужный словарь из каталога messages/.
Слой доступа к данным (DAL), DTO и безопасность
Официальное руководство Next.js по авторизации указывает, что проверка прав только в middleware или layout не гарантирует безопасность. Публичные маршруты и серверные функции могут быть вызваны напрямую. Поэтому основной слой проверки прав должен располагаться в Data Access Layer (DAL) внутри lib/data/.
Порядок безопасного выполнения операции:
- Входная валидация: при вызове Server Action входные данные проверяются Zod-схемой из
lib/schemas/. - Аутентификация: DAL извлекает текущую сессию пользователя через серверный экземпляр
lib/auth.ts. - Авторизация: DAL проверяет права пользователя на запрашиваемый ресурс (например, принадлежит ли задача текущему пользователю).
- Формирование DTO: вместо сырой ORM-модели Prisma со служебными полями DAL возвращает только те данные, которые необходимы UI (Data Transfer Object).
Слой DTO исключает случайную утечку приватных полей (хешей паролей, системных токенов, внутренних ID) на клиентскую сторону.
Интеграция Better Auth: разделение сервера и клиента
При интеграции библиотеки Better Auth в Next.js важно разделять серверный и клиентский контексты:
- Серверный модуль (
lib/auth.ts): содержит секретные ключи, конфигурацию адаптера базы данных Prisma и обработчики сессий. Этот модуль используется только в Server Components, DAL и Route Handlers. - Клиентский модуль (
lib/auth-client.ts): экпортирует облегченный клиентcreateAuthClient(), используемый в Client Components для инициации входа, выхода и получения состояния пользователя в браузере.
Такое разделение гарантирует, что секретные ключи авторизации и код прямого подключения к базе данных не попадут в клиентский JavaScript-бандл.
Сквозное E2E-тестирование в изолированной базе данных
Для проверки критических пользовательских сценариев в репозитории используется связка Cypress и Vitest. Интеграционные тесты на Vitest проверяют методы DAL и Zod-схемы, а E2E-тесты Cypress эмулируют реальные действия пользователя в браузере.
Организация тестового окружения:
- Изолированная БД: для E2E-тестов поднимается отдельный Docker-контейнер с тестовой базой данных PostgreSQL.
- Сброс и сидирование: перед каждым тестовым прогоном Cypress вызывает Node-таски
db:resetиdb:seed(скриптprisma/test-seed.ts), наполняя базу детерминированными пользователями и задачами. - Автономность тестов: сценарии проверяют полный цикл (создание задачи через форму, появление записи в таблице, изменение статуса) и не зависят от результатов выполнения других тестов.
Порядок внедрения и рекомендации
Для построения или рефакторинга архитектуры на Next.js App Router рекомендуются следующие шаги:
- Проектирование структуры: выделите группы маршрутов
(auth),(dashboard)и создайте соответствующие макетыlayout.tsx. - Вынос бизнес-логики: очистите файлы
page.tsxот прямых SQL-запросов и вызовов ORM, перенеся их в функции DAL вlib/data/. - Разделение авторизации: настройте серверный
lib/auth.tsи клиентскийlib/auth-client.ts. - Валидация и DTO: опишите Zod-схемы для всех форм и серверных функций, зафиксировав типы DTO.
- Тестовое окружение: настройте автоматический сброс тестовой базы данных перед прогоном E2E-тестов.
Официальная документация доступна в руководствах Next.js App Router, Project Structure, Authentication Guide, Better Auth Integration и в репозитории примера Taskry on GitHub.
Заключение
Четкое разделение ответственности между маршрутизатором app/ и доменной логикой в lib/ делает веб-приложение на Next.js понятным для поддержки и масштабирования. Вынос авторизации и проверок прав в слой DAL защищает систему от уязвимостей, а автоматизированное E2E-тестирование в чистой базе данных гарантирует стабильность релизов.

![Node.JS [ru]](/api/digests/it_development/daily/20260726/assets/sources/we-use-js.jpg)