Демка · 8 сентября 2026

Fullstack Test Shop

Что где лежит в коде, как запускается и что проверялось.
Версия 767226bf3c2f · подготовлено 8 сентября 2026

О проекте

В рамках тестового задания требовалось собрать магазин цифровых товаров с каталогом, оформлением заказа и оплатой. Я расширил исходный сценарий до эксплуатационного: добавил идемпотентный inbox webhook, конкурентно безопасную выдачу ключей, повтор этапов и наблюдаемые состояния ошибок.

Тестовое задание реализовано как полный контур цифрового магазина: Angular-витрина, NestJS API, PostgreSQL через Prisma, webhook оплаты, два поставщика ключей и фоновый worker выдачи. В интерфейсе можно пройти покупку, повторить событие оплаты и проверить восстановление заказа после нехватки товара или сбоя поставщика.

Что отличает реализацию

Выдача выполняется однократно даже при повторных и параллельных webhook. Стабильный provider request ID переживает неоднозначный timeout; out_of_stock и delivery_failed восстанавливаются повторным worker-проходом. Ограничения БД и выборка FOR UPDATE SKIP LOCKED удерживают инварианты на уровне хранилища, а не только контроллера.

Состав прикладного кода

Angular / TypeScript 32%NestJS 30.4%Prisma / PostgreSQL 18.4%Node.js delivery worker 12.5%Node.js provider adapters 3.8%TypeScript contracts 2.9%

Доли по размеру прикладных файлов Git в закреплённой версии. Каждый файл отнесён к одной подсистеме по правилам scripts/generate-stack-share.mjs; тесты, ассеты, зависимости и generated-файлы исключены. Округление — до 0,1%. Это состав кода, а не уровень владения технологиями.

  • Оплата и поставщики — явные моки; деньги не списываются, коды учебные.
  • До 20 заказов на сессию и 1000 новых демонстрационных заказов суммарно. TTL один час, очистка каждые пять минут.
  • Пример восстановления намеренно завершает первую попытку одного заказа ошибкой. Он не меняет глобальные режимы поставщиков.

Скриншоты, схемы и исходные материалы сохранены на языке оригинала; подписи и описание переведены.

Архитектура и схемы

  • Цена и скидка вычисляются на сервере и фиксируются в заказе.
  • Idempotency-Key защищён уникальным индексом; входные данные повтора сверяются с исходным намерением.
  • Webhook сначала сохраняется в durable inbox. Отдельный worker обрабатывает платёж и очередь выдачи.
  • Стабильный requestId поставщика сохраняется при повторе. Неоднозначный timeout не разрешает немедленно выдать второй код.
Компоненты опубликованного демо
Компоненты опубликованного демо · Mermaid ↓
Основной сценарий
Основной сценарий · Mermaid ↓
Размещение опубликованной версии
Размещение опубликованной версии · Mermaid ↓
Состав данных и границы хранения
Состав данных и границы хранения · Mermaid ↓

Code-map: файлы и связи

Карта привязана к версии 767226bf3c2f. В таблице — экран или API, связанный модуль и данные.

ФункцияЭкран / APIМодульДанные / проверка
ПокупкаStorefront / POST ordersstorefront.component; ShopService.createOrderorders, products, promocodes; race tests
ОплатаPOST payments/simulate → webhooks/paymentPaymentsController; acceptWebhookpayment_events; повтор event_id
ВыдачаOrder / GET orders/:idworker.service processDeliveryJobdelivery_jobs, provider_requests, fulfillments; recovery
СессияGuard всех публичных заказовportfolio-demo PortfolioGuardHMAC cookie, prefix owner; tests/portfolio/run.ts
Сброс / TTLPOST demo/reset / timerPortfolioCleanup.clearтолько portfolio orders; ownership / expiry tests

Как работать с картой

  1. Перед изменением найти функцию и пройти связи до API, состояния и хранилища.
  2. Проверить входы, ошибки, повторные события и зависимые сценарии.
  3. После изменения обновить карту и затронутые схемы вместе с кодом.
  4. Выполнить связанные проверки и привязать новые материалы к версии исходников.

Сценарии и API

  1. Выберите товар и выполните успешную тестовую оплату. Дождитесь кода и просмотрите историю.
  2. Повторите то же платёжное событие: код и выдача должны остаться единственными.
  3. Создайте заказ через сценарий сбоя, оплатите и нажмите «Восстановить мой заказ».
  4. Проверьте отказ оплаты, чужой UUID в другой сессии и сброс своего примера.

Проверка опубликованной версии

CI: CI ↗ · 767226bf · версия этого демо · 2026-09-07T00:49:05Z

CI: Portfolio immutable image ↗ · 767226bf · версия этого демо · 2026-09-07T00:49:05Z

  • Real HTTP webhook, durable inbox, worker, single fulfillment preserved on event replay
  • Foreign GET/recover return 404; other session reset preserves first order
  • Payment failure; isolated first-attempt delivery fault; own recovery succeeds

Эти проверки относятся к указанной версии. Коммерческие показатели и качество моделей на независимой выборке здесь не измерялись.

Измерения

Суммарные ресурсы контейнеров проекта · 2026-09-07T01:08:27 — 01:11:22 UTC
Суммарные ресурсы контейнеров проекта · 2026-09-07T01:08:27 — 01:11:22 UTC · Исходные данные ↓
Измеренные повторения сценария через HTTPS · 2026-09-07T01:08:36 UTC; ограничения методики в JSON
Измеренные повторения сценария через HTTPS · 2026-09-07T01:08:36 UTC; ограничения методики в JSON · Исходные данные ↓
  • Сохранено 14 содержательных кадров фактического интерфейса.
  • Дата, сценарий и версия указаны у каждого кадра.
  • Максимум RAM контейнеров в коротком тесте: 218.56 MiB. Общие службы учитываются отдельно; магазин включает свою БД.
  • Измерено 6 повторений сценария; медиана 129.0 мс, максимум 1939 мс. Время включает браузер и HTTPS; методика и ограничения приложены.

Запуск и эксплуатация

У демки и исходного приложения одна модель заказов. Демо-guard включается через PORTFOLIO_DEMO=true. Без этого флага действуют исходные контракты API.

Сборка выполняется GitHub Actions из закреплённого commit SHA. На VPS загружается готовый GHCR-образ. База магазина остаётся отдельной от новых приложений.

Запуск: docker compose --env-file .env.production -f compose.production.yaml up -d. До переключения выполнить prisma migrate deploy. Секреты хранятся только на сервере. Seed нельзя использовать как безусловный сброс данных работающего магазина.

Readiness: /api/health/ready проверяет PostgreSQL. Во время инцидента сравнить историю заказа, inbox и delivery job; повторять выдачу по исходному orderId, не создавать новую покупку.

Сборка вне VPS, на сервер уходят готовые файлы и образы с фиксированной версией. Секреты отдельно. Логи ротируются; после изменения log options контейнер нужно пересоздать. Общий docker prune не используется.

Code-map связывает экран или API с модулем и данными. При правке нужно проверить эти связи, обновить карту и прогнать затронутые сценарии: обычный проход, ошибку, повтор, сброс. Схема может устареть, поэтому её версия указана рядом.

Откат проверен 2026-09-07T01:07:46.255650+00:00: 20260907-verified → 20260907 → 20260907-verified. После каждого переключения подтверждены HTTPS, readiness и SHA. Это проверка конфигурации и артефактов на одном проверенном SHA; обратная миграция БД не выполнялась.

Стек

Angular / TypeScriptВитрина, сигналы состояния, HTTP-клиент и polling заказа.
NestJSКонтракты, валидация, webhook, операции восстановления и границы демо.
PostgreSQL / PrismaСнимки денег, inbox, очередь с lease, уникальные индексы и транзакции.
Node.js workerHTTP-вызовы поставщиков вне короткой транзакции, retry и финальная выдача.

Материалы и исходники

История реализации: 1–3 сентября 2026. Подготовка портфолио: 7 сентября 2026.

Архив материалов на языке оригинала.