feat: add example

This commit is contained in:
2026-08-01 09:31:08 +03:00
parent 15805e28df
commit 26b59686a5
434 changed files with 34975 additions and 4995 deletions

View File

@@ -0,0 +1,102 @@
# 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:
```bash
cd ../demo-backend
npm install
npm run dev:simple
```
Затем запустите frontend:
```bash
npm install
npm run dev
```
Откройте `http://localhost:3000`. Backend по умолчанию доступен на `http://localhost:3001`.
Чтобы изменить URL backend, создайте `.env.local` рядом с `package.json`:
```bash
NEXT_PUBLIC_SIMPLE_API_URL=http://localhost:3001
```
## Demo accounts
| Email | 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:
```text
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:
```bash
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.
## Проверка
```bash
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 и циклы.