Demo frontend
Полноценное Next.js 16 приложение поверх меньшего из двух fixture API: ../demo-backend/openapi/simple.json.
Пример показывает SLM Level 1 на каталоге: public data, JWT login/refresh/logout, persisted cart, checkout, protected orders, RBAC, admin CRUD, optimistic locking и детерминированные network outcomes.
Запуск
Требуются Node.js 20+, npm 10+ и современный browser с Web Locks API. Auth и cart transitions работают fail-closed без cross-tab lock; localhost считается secure context для локальной разработки.
Сначала запустите Simple API:
cd ../demo-backend
npm install
npm run dev:simple
Затем запустите frontend:
npm install
npm run dev
Откройте http://localhost:3000. Backend по умолчанию доступен на http://localhost:3001.
Чтобы изменить URL backend, создайте .env.local рядом с package.json:
NEXT_PUBLIC_SIMPLE_API_URL=http://localhost:3001
Demo accounts
| Password | Role | Scenarios | |
|---|---|---|---|
admin@demo.local |
demo1234 |
admin | Product CRUD, all orders |
customer@demo.local |
demo1234 |
customer | Cart, checkout, own orders |
Routes
| Route | Composition responsibility |
|---|---|
/ |
Product search, category filter, sorting and pagination |
/products/[productId] |
Product detail and add-to-cart |
/cart |
Multi-domain checkout coordination |
/orders |
Protected order history and cancellation |
/sign-in |
JWT session lifecycle and account selection |
/admin/products |
RBAC-gated CRUD and optimistic locking |
Плавающий Demo controls widget переключает X-Demo-Scenario: slow, timeout, 500, 429, empty, expired auth, forbidden и conflict. Отдельное действие Seed 250 загружает настоящий большой seed с интерактивными product IDs; synthetic large-dataset header намеренно не используется для mutation UI.
SLM boundary
src является SLM root:
src/
├── app/ Next.js bootstrap and route entries
├── compositions/ Layout, screens and demo widget
├── domains/ Auth, catalog, cart, orders and demo-control
├── infra/ Generated REST client, JWT storage and browser storage
├── ui/ Product-agnostic button, form field and feedback panel
└── shared/ Deterministic predicates, formatting and Result type
Пример использует Level 1 осознанно: у каждого домена одна browser runtime integration. Дополнительные factories, adapters и assemblies Level 2 не окупили бы стоимость. Checkout остаётся в composition, поэтому orders не импортирует cart, а module graph остаётся ацикличным.
State и lifecycle распределены по владельцам:
authвладеет пользовательской сессией;infra/simple-auth-sessionхранит technical JWT pair, стабильныйsessionIdи CAS revision.cartвладеет строками, totals и persisted snapshot validation; monotonic revision и conditional clear сериализованы между вкладками.- SWR cache принадлежит REST infra module, создаётся отдельным provider и remount-ится при смене logical auth session.
- React providers создаются один раз в application scope и очищают свои subscriptions при unmount.
- Route entries только адаптируют Next.js params и подключают public APIs compositions.
- Reset, seed, role и request-scenario transitions синхронизируют cache, auth, cart и route-local pagination между вкладками.
REST client
Split SDK генерируется из committed OpenAPI:
npm run codegen:simple-rest-api
Generated-код живёт только в src/infra/simple-rest-api/generated и не редактируется вручную. GET hooks вызывают точечные operations через simpleHttpClient; submit-сценарии используют полный simpleRestApi. Внешний код импортирует REST capability только через @/infra/simple-rest-api.
OpenAPI fixture описывает числовые page и limit как object. Исправление generated type изолировано в types/to-generated-query.ts; runtime query остаётся числовым.
JWT refresh выполняется в transport onError, ограничен одним retry и дедуплицирует конкурентные refresh requests одной revision. CAS не позволяет позднему refresh воскресить logout или перезаписать новый login. Хранение refresh token в localStorage допустимо только для этой архитектурной fixture; production-приложение должно выбрать threat model и более безопасную session strategy.
Checkout привязан к captured auth session и persisted cart revision. Backend атомарно проверяет product version, unit price, USD currency, aggregate stock и уникальность product lines. Timeout-сценарий откладывает mutation handler и отменяет его при disconnect, поэтому frontend timeout не скрывает завершившийся POST.
Проверка
npm run check
npm run build
npm run check запускает architecture constraints, ESLint, TypeScript и Vitest. Architecture script строит import graph через TypeScript AST и явный module manifest, затем проверяет направление слоёв, public module imports, side-effect/dynamic imports, запрет утечки generated SDK и циклы.