npp-web
npp-web — защищённый frontend платформы на Nuxt 3 + TypeScript + Tailwind CSS + Apollo GraphQL.
Он отвечает не за сбор или расчёт данных, а за то, чтобы пользователь мог безопасно читать и управлять контуром через единый кабинет.
За что отвечает
- страница входа и сессионный UX;
- дашборд;
- аналитические разделы;
- список закупок и карточки;
- источники, запуски и административные экраны;
- отчёты и профиль пользователя;
- визуальная интерпретация GraphQL-контракта.
Что не должен делать frontend
- ходить напрямую в базу;
- читать очереди или артефакты напрямую;
- считать бизнес-метрики, если они уже должны приходить с backend;
- знать детали внешнего HTML/JSON конкретных источников.
Основные маршруты
| Маршрут | Назначение |
|---|---|
/login | вход в систему |
/dashboard | сводный экран платформы |
/procurements | список закупок |
/procurements/:id | карточка закупки |
/sources | источники и их состояние |
/jobs | журнал запусков |
/reports | список и просмотр отчётов |
/analytics/* | аналитические разделы |
/profile | профиль текущего пользователя |
/users | управление пользователями |
Как устроен frontend
Верхнеуровнево проект состоит из:
pages/— маршруты Nuxt;components/— UI-компоненты и аналитические секции;composables/— запросы и клиентская orchestration-логика;graphql/— документы и типы;utils/— форматирование и вспомогательные правила;layouts/иmiddleware/— auth и каркас приложения.
Работа с GraphQL
Frontend зависит от backend через Apollo.
Обычно поток такой:
- документ запроса лежит в
graphql/documents.ts; - типы лежат в
graphql/types.ts; - composable вызывает запрос;
- страница или аналитический компонент отображает данные.
Это важно, потому что удобнее менять frontend через composables и типизированные документы, а не через ad-hoc запросы внутри компонентов.
Типовой клиентский слой выглядит так:
const httpLink = new HttpLink({
uri: config.public.graphqlEndpoint,
fetch
});
const authLink = new ApolloLink((operation, forward) => {
const accessToken = import.meta.client
? window.localStorage.getItem(AUTH_STORAGE_KEYS.accessToken)
: null;
operation.setContext(({ headers = {} }) => ({
headers: {
...headers,
...(accessToken ? { authorization: `Bearer ${accessToken}` } : {})
}
}));
return forward(operation);
});Здесь важно, что frontend не знает ничего о Prisma, очередях или raw-событиях. Он работает только через GraphQL и ролевую модель.
Аналитические экраны
Frontend отображает несколько разных аналитических срезов:
- общий overview;
- поставщики;
- атомный контур;
- отчёты;
- operational health по источникам.
Если аналитика выглядит пустой, это не всегда frontend-баг. Часто причина в том, что backend-агрегат зависит от более узкого доменного слоя, чем кажется по UI.
Ролевая модель как часть UX
Frontend NPPWEB устроен не как “один интерфейс для всех”, а как ролевой кабинет:
USERвидит только базовый контур;ANALYSTполучает закупки, аналитику, источники и бизнес-отчёты;DEVELOPERработает с источниками, jobs, parser-runs и parser-admin;ADMINобъединяет оба контура и управление пользователями.
Маршрутизация защищается глобальным middleware:
export default defineNuxtRouteMiddleware(async (to) => {
const auth = useAuthSession();
await auth.initialize();
if (!auth.isAuthenticated.value) {
return navigateTo(`/login?redirect=${encodeURIComponent(to.fullPath)}`);
}
const roles = Array.isArray(to.meta.roles) ? (to.meta.roles as UserRole[]) : [];
if (roles.length > 0 && !roles.includes(auth.user.value?.role ?? "USER")) {
return navigateTo(`/forbidden?from=${encodeURIComponent(to.fullPath)}`);
}
});То есть frontend отвечает не только за отображение, но и за безопасную навигацию по ролям.
Переменные окружения
NUXT_PUBLIC_GRAPHQL_ENDPOINTNUXT_GRAPHQL_PROXY_TARGET
Пример:
NUXT_PUBLIC_GRAPHQL_ENDPOINT=/graphql
NUXT_GRAPHQL_PROXY_TARGET=http://localhost:3000Локальный запуск
cd npp-web
npm install
npm run devПо умолчанию dev-сервер обычно доступен на http://localhost:4173.
Production-сценарий
npm run typecheck
npm run build
node .output/server/index.mjsЧто чаще всего меняют в этом репозитории
- новый экран или секцию аналитики;
- таблицы, фильтры, карточки и маршруты;
- Apollo/composable слой;
- UX авторизации;
- форматирование и визуальную интерпретацию метрик.
Как правильно читать frontend-проблемы
Если экран ведёт себя странно, полезно задавать вопросы в таком порядке:
- GraphQL-ответ вообще пришёл?
- У пользователя есть нужная роль?
- Правильно ли подключён composable?
- Это проблема пустых данных или проблема отображения?
- Не сломан ли layout / route meta / auth middleware?
Так проще отличить настоящий UI-баг от backend- или role-based ограничения.
Когда проблема почти точно не здесь
Если:
SourceRunпадают;- backend
healthне готов; - GraphQL отдаёт пустую агрегацию;
- в доменной модели нет нужных связей;
то менять frontend рано. Сначала нужно проверить scrape-helper, processing-worker или npp-backend.
Качество
npm run typecheck
npm run buildДля локальной smoke-проверки полезно:
- поднять backend;
- войти в интерфейс;
- открыть
dashboard,analytics,procurements; - убедиться, что нет GraphQL runtime-ошибок и layout-регрессий.