NestJS + GraphQL API для доменной модели платформы мониторинга закупок. Сервис хранит пользователей, сессии, источники, source runs, закупки, отчеты и принимает ingest от processing-worker.
DATABASE_URLJWT_ACCESS_SECRETINGEST_API_TOKEN
Полный локальный пример лежит в .env.example.
- admin:
admin@admin.ru - password:
admin - demo users:
analyst@admin.ru,user@admin.ru - password for demo users:
admin
Seed идемпотентный и безопасно запускается повторно.
cp .env.example .env
npm install
npm run db:setup
npm run start:devЕсли PostgreSQL нужен через Docker из общего infra-репозитория:
cd ../deployment-infra
cp .env.example .env
docker compose up -d postgres
cd ../backend-apiEndpoints по умолчанию:
- health:
http://localhost:3000/api/health - GraphQL:
http://localhost:3000/graphql
npm run prisma:generate
npm run prisma:migrate:deploy
npm run prisma:db:seedloginвыдаетaccessTokenиrefreshTokenrefreshSessionревокает старую refresh-session и выдает новую пару токеновlogoutревокает server-sideUserSession- access token теперь привязан к
UserSession, поэтому после logout текущая сессия становится невалидной по серверной логике
Пример login:
mutation {
login(input: { email: "admin@admin.ru", password: "admin" }) {
accessToken
refreshToken
expiresInSeconds
user {
email
role
}
}
}processing-worker вызывает GraphQL mutation ingestNormalizedItem.
- JWT для ingest не нужен
- mutation публичная только для обхода общего JWT guard
- обязательная авторизация идет через заголовок
x-ingest-token - значение
x-ingest-tokenдолжно совпасть сINGEST_API_TOKEN
Пример:
mutation Ingest($input: IngestNormalizedItemInput!) {
ingestNormalizedItem(input: $input) {
accepted
idempotencyKey
procurementId
}
}dashboardSummary отдает:
totalProcurementsprocurementsByStatusprocurementsOverTimerecentProcurementssourcesSummaryrecentSourceRuns
Для админки дополнительно есть:
procurementItemsprocurementItemsourcessourceRunsreportsusers