Тестовое Angular-приложение с авторизацией и защищенным dashboard-разделом для работы со списком пользователей из DummyJSON API.
Репозиторий: ImDoode/user-dashboard-angular Демо: user-dashboard-angular на GitHub Pages
Проект решает две основные задачи:
- авторизация пользователя и хранение сессии на клиенте;
- отображение списка пользователей с фильтрацией, lazy routing, детальной карточкой и догрузкой данных.
- standalone Angular-приложение без NgModule-архитектуры;
- маршрутизация с разделением на публичную и защищенную зоны;
- guards для доступа авторизованных и неавторизованных пользователей;
- HTTP interceptor для подстановки токена;
- страница пользователей с фильтрами, URL-sync и бесконечный скролл;
- деталка с подробной информацией о пользователе;
- фасад для логики страницы пользователей;
- unit-тесты на ключевые сценарии;
- ESLint и pre-commit hook с автоматической проверкой
lint + test.
- Angular 21
- TypeScript
- RxJS
- Angular CDK (
virtual-scroll) - Vitest
- ESLint
- Husky
Установка зависимостей:
npm installЗапуск dev-сервера:
npm startСборка:
npm run buildПроверка тестов:
npm test -- --watch=falseПроверка линтера:
npm run lintСборка под GitHub Pages:
npm run build:pagesЕсли имя репозитория изменится, локально передай свой base href явно:
npm run build -- --base-href /<repo-name>/Полная локальная проверка качества:
npm run checkДля проекта настроен workflow .github/workflows/deploy-pages.yml, который:
- запускается при push в
masterи вручную черезworkflow_dispatch; - устанавливает зависимости через
npm ci; - прогоняет
npm run check; - собирает production-версию Angular-приложения с
base href, вычисленным из имени GitHub-репозитория; - публикует содержимое
dist/user-dashboard-angular/browserв GitHub Pages.
Основной код находится в src/app.
Ключевые директории:
- src/app/core — cross-cutting слой: guards, interceptors, модели, базовые сервисы.
- src/app/features — feature-модули приложения.
- src/app/features/auth — страница логина.
- src/app/features/users — список пользователей, фильтры, деталка пользователя, фасад и feature routes.
- src/app/layouts — layout-компоненты для auth и dashboard зоны.
Внутри users feature структура разделена на:
pages— контейнерные page-компоненты;components— переиспользуемые UI-блоки внутри фичи;constants— конфигурация фильтров и служебные константы;utils— чистые функции без Angular-зависимостей.
Корневой роутинг описан в src/app/app.routes.ts.
Структура маршрутов:
/login— публичная зона подAuthLayoutComponent, доступна только гостям;/dashboard— защищенная зона подDashboardLayoutComponent, доступна только после авторизации;/dashboard/users— список пользователей;/dashboard/users/:id— деталка пользователя как дочерний маршрут.
Почему так:
- layout-компоненты отделяют каркас страниц от бизнес-логики;
- guards делают правила доступа явными на уровне роутинга;
- users feature загружается лениво, что уменьшает размер бандла.
Проект использует standalone-подход Angular вместо NgModule.
Почему это выбрано:
- меньше инфраструктурного кода;
- проще локально понимать зависимости компонента;
- лучше сочетается с lazy loading и современной Angular-архитектурой.
Код сгруппирован по бизнес-фичам, а не по типам файлов.
Почему это выбрано:
- проще масштабировать проект по сценариям, а не по техническим слоям;
- изменения внутри одной фичи локализованы;
- быстрее навигироваться по коду в реальной продуктовой разработке.
В src/app/features/users/pages/users-page/users-page.facade.ts вынесена orchestration-логика страницы пользователей.
Фасад отвечает за:
- синхронизацию фильтров с URL;
- загрузку данных;
- пересечение результатов фильтрации;
- пагинацию и бесконечный скролл;
- состояние загрузки, ошибок и открытой деталки пользователя.
Компонент src/app/features/users/pages/users-page/users-page.component.ts при этом остается тонким UI-слоем.
Почему это выбрано:
- компонент не перегружен побочными эффектами;
- состояние и сценарии страницы централизованы;
- бизнес-логику проще тестировать и рефакторить отдельно от шаблона.
В src/app/core/models/user.models.ts используются разные типы для разных API-контрактов:
UserListItem— для списков, поиска и фильтрации;UserDetails— для детальной карточки пользователя.
Почему это выбрано:
- список и детальная карточка реально используют разные поля;
- типы отражают контракт API точнее;
- тестовые моки стали короче и менее шумными;
- снижается риск опираться на поля, которых нет в конкретном endpoint.
В тех же моделях определены USER_LIST_SELECT_FIELDS и USER_DETAILS_SELECT_FIELDS, которые используются в src/app/core/services/users.service.ts.
Почему это выбрано:
- список полей
selectбольше не живет отдельной строкой в сервисе; - модель и HTTP-контракт синхронизированы на уровне TypeScript;
- изменение модели сразу подсвечивает возможный разъезд с API-запросом.
src/app/core/services/users.service.ts инкапсулирует HTTP-запросы, сбор всех страниц и кеш для полных списков пользователей.
Почему это выбрано:
- компоненты и фасады не знают деталей HTTP;
- повторные фильтры и поиски не создают лишних одинаковых запросов;
- логика работы с API централизована в одном месте.
Локальное состояние в компонентах и фасаде хранится через Angular Signals.
Почему это выбрано:
- удобно описывать локальное состояние;
- меньше ручной подписочной логики для представления;
- хорошо сочетается с OnPush change detection.
RxJS при этом используется там, где он уместен:
- для HTTP;
- для реактивной работы с router streams;
- для композиции async-потоков и фильтрации.
src/app/core/guards ограничивают доступ к маршрутам, а src/app/core/interceptors/auth-token.interceptor.ts подставляет токен в запросы.
Почему это выбрано:
- правила доступа не размазываются по компонентам;
- HTTP-авторизация не дублируется в каждом запросе;
- поведение безопасности находится в ожидаемых точках расширения Angular.
В проекте настроены базовые quality gates:
- ESLint для TypeScript-кода;
- unit-тесты на Vitest;
- pre-commit hook через Husky.
Перед коммитом выполняется:
npm run checkЭто означает, что коммит блокируется, если не проходят:
npm run lintnpm run test:ci
- добавить интеграционные тесты на роутинг и guards;
- добавить e2e тесты для бизнес логики;
- вынести DTO и доменные модели в отдельные типы, если API начнет усложняться;
Проект собран как небольшое, но инженерно аккуратное приложение:
- современный Angular без NgModules;
- feature-first структура;
- разделение на представление и фасад для сложной страницы;
- типизация, привязанная к реальному API;
- локальные проверки качества кода, достаточные для небольшого проекта.