NEXX Proxy — Release 1 Progress

Source: NEXX_R1_Delivery_Planning_Baseline_v1_0 + Kostya's NEXX_Roadmap_Developer_Budget.md §4.2 · Updated: 2026-07-02 · Contract v1.7.0 (staging + prod) · Backend: prod platform-api.nexx.beyondhorizon.dev
Stage 1 signed off · Stage 2 R1 scope passed · Stage 3 — delivered & deployed (backend + frontend), ready for acceptance. Audit trail: D1.1–D1.14 · Stage 1 QA · Stage 2 D2.1–D2.14 · Stage 3 D3.1–D3.12.
Backend в проде на platform-api.nexx.beyondhorizon.dev (контракт v1.7.0), фронт v2 в проде на nexx-business-app-v2.vercel.app (demo-персоны, пароль demo-pass-123). Приёмка Stage 3: V2 App · Тестирование ↗.
Prod API live
Swagger OpenAPI Health
Frontend (Vercel) App
old dev nexx-api.srv.acebox.eu — rollback only
V2 App · Тестирование ↗
Stage 1 — Auth, Companies, Tenancy, Mock BACKEND, Ops · Ready
Weeks 1-2+ · 02 May – 20 May 2026 · signed off 2026-05-22 (Stage 1 Ready)
100%
Auth — register, verify, resend, password reset, invite, login, JWT
AUTH-001/002 + AUTH-003 (slices 1-5b + A12 fix) shipped · register/verify/resend/password-reset endpoints live · invite-on-unregistered + invite token lookup · access-token revocation on password change · backend smoke 30/30 green · frontend Playwright 15 passed · human QA 14/14 passed 2026-05-18 by Sasha + Andrei
100%
Companies and memberships
CMP-001, TEN-002 shipped · invite-on-unregistered + auto-attach (AUTH-003 slice 5) · membership list/update/suspend/reactivate + last-admin protected + invite token lookup · FE-COMPANY-UX-008..011 inline feedback + admin-row guardrail · human QA 11/11 (I1-I11) passed 2026-05-19 by Sasha + Andrei
100%
Tenant isolation, active company context
TEN-001 shipped · X-NEXX-Company-ID header in frontend client · reload preserves active company · logout clears session/company state · human QA 5/5 (T1-T5) passed 2026-05-19 by Sasha + Andrei
100%
Mock BACKEND contract seam
ENG-CONTRACT-001 + 3 mock endpoints (D1.9) deployed 2026-05-20 — /api/mock-backend/{health,auth/token,companies}/ · все три curl-проверены зелёные на staging · envelope с contractVersion: mock-v0, live: false · FR / FT N/A by design
100%
Backend / platform ops — staging / deploy / migrations / secrets
Live Docker stack на big-buddy: nexx-app (Django+gunicorn) + nexx-db (Postgres 15) + nexx-status (nginx) + 2 TG bridges · HTTPS через Cloudflare на 3 домена · реальный SMTP (seohost.pl) · миграции авто-применяются через entrypoint.sh при старте · secrets через server-side .env · scripts/deploy.sh = rsync + docker compose · pytest suite + verify_backend.sh локально перед коммитом. Gap: нет backend GitHub Actions CI, нет разделения prod/staging окружений — Stage 2 carry-over.
~60%
Per-module quads — each is 20%: BR Backend Ready — backend код работает и задеплоен FR Frontend Ready — UI работает и задеплоен BT Backend Tests — pytest проходит FT Frontend Tests — Playwright / автоматический smoke QA Human QA — ручной acceptance signoff (Sasha + Andrei) · done · partial · not started · not yet (per plan) · N/A — не применимо для этого модуля
Stage 1 acceptance deliverables — D1.1–D1.14
Source: NEXX_Roadmap_Developer_Budget.md §4.2 (Kostya). Click any row for evidence + curl checkpoints. Acceptance review: Konstantin (PM) + Илья (CTO).
D1.1
Регистрация работает
Пользователь регистрируется → получает email → подтверждает
Done
Endpoints
  • POST /api/internal/v1/auth/register/ — создаёт user + UserProfile, шлёт verification email через SMTP nexx-platform@acebox.eu
  • POST /api/internal/v1/auth/email/verify/ — потребляет one-shot token, помечает email верифицированным
  • POST /api/internal/v1/auth/email/resend/ — повторная отправка (rate-limit 60s)
Checkpoint — curl
curl -X POST https://nexx-api.srv.acebox.eu/api/internal/v1/auth/register/ \
  -H "Content-Type: application/json" \
  -d '{"email":"new.user@example.com","password":"newPass123!"}'
# → 201 {userId, email, emailVerified: false}
Human QA evidence
  • Stage 1 manual QA: A1, A7, A14 — passed 2026-05-18 (Sasha + Andrei)
  • Письма приходят на реальные адреса через seohost.pl SMTP
  • A13: unverified user не может создать компанию (403 EMAIL_NOT_VERIFIED)
D1.2
Login + token refresh работают
Залогиниться, обновить access token, использовать API с Bearer JWT
Done
Endpoints
  • POST /api/internal/v1/auth/token/ — login → access (15min) + refresh (30d)
  • POST /api/internal/v1/auth/token/refresh/ — обмен refresh на новый access
  • POST /api/internal/v1/auth/token/logout/ — revoke refresh token (запись в AuthRefreshToken)
  • GET /api/internal/v1/auth/token/me/ — текущий user из access token
Checkpoint — curl
curl -X POST https://nexx-api.srv.acebox.eu/api/internal/v1/auth/token/ \
  -H "Content-Type: application/json" \
  -d '{"email":"demo.buyer.admin@example.com","password":"demo-pass-123"}'
# → 200 {accessToken, refreshToken, tokenType: "Bearer", expiresIn: 900}

curl https://nexx-api.srv.acebox.eu/api/internal/v1/auth/token/me/ \
  -H "Authorization: Bearer <accessToken>"
# → 200 {userId, email, ...}
Human QA evidence
    Stage 1 manual QA: A1–A6 (login для 4 demo users + active company switcher) — passed 2026-05-18
D1.3
Сброс пароля работает
Запросить сброс → получить письмо → сменить пароль → старые сессии инвалидируются
Done
Endpoints
  • POST /api/internal/v1/auth/password/reset/request/ — создаёт one-shot token, шлёт письмо
  • POST /api/internal/v1/auth/password/reset/confirm/ — потребляет token, меняет password, обновляет password_changed_at
Critical fix (A12)

Старые JWT access tokens с iat ≤ password_changed_at теперь отвергаются (core/auth_tokens.py). Поймано в human QA — Sasha залогинен в браузере A, сменил пароль в браузере B, после refresh в A старый token больше не работает.

Checkpoint — curl
curl -X POST https://nexx-api.srv.acebox.eu/api/internal/v1/auth/password/reset/request/ \
  -H "Content-Type: application/json" \
  -d '{"email":"demo.buyer.admin@example.com"}'
# → 202 (всегда 202, чтобы не раскрывать наличие аккаунта)
Human QA evidence
    Stage 1 manual QA: A8, A9, A10, A11, A12 — passed 2026-05-18 (включая критичный A12 после фикса)
D1.4
Создание компании (manual)
Создать компанию → пользователь становится COMPANY_ADMIN
Done
Endpoint
  • POST /api/internal/v1/companies/onboarding/manual/ — создаёт Company + Membership с ролью COMPANY_ADMIN
  • Gated по EMAIL_NOT_VERIFIED (403 если email не подтверждён)
Human QA evidence
  • A14 — verified new user создаёт первую компанию, получает COMPANY_ADMIN — passed 2026-05-18
  • A13 — unverified user блокируется (403) — passed
D1.5
Приглашение и удаление пользователей
Пригласить → принять → изменить роль → suspend/reactivate; last-admin защищён
Done
Endpoints
  • POST /api/internal/v1/companies/memberships/ — known email → активный member; unknown email → invitation + email
  • PATCH /api/internal/v1/companies/memberships/<id>/ — смена роли, suspend, reactivate
  • GET /api/internal/v1/auth/invitations/<token>/ — публичный lookup для invite registration screen
Human QA evidence
  • I1–I11 — все 11 сценариев passed 2026-05-19 (Sasha + Andrei)
  • Включает: invite-on-unregistered, auto-attach to company, role update, suspend, reactivate
  • I11: last admin / protected admin guardrail — текущий админ не может suspend сам себя
D1.6
Переключение между компаниями
Membership в 2+ компаниях → переключиться → workspace обновился
Done
Mechanism
  • Transitional header X-NEXX-Company-ID на каждом authenticated request
  • Frontend хранит active company в session, persistent через refresh
  • Demo user demo.context.switcher@example.com состоит в 3 компаниях
Human QA evidence
    T1, T2, T4 — passed 2026-05-19 (login → switch → reload preserves selection)
D1.7
Tenant isolation
Попытка доступа к данным чужой компании → 403 Forbidden
Done
Mechanism
  • TEN-001: все internal/v1 view-классы фильтруют queryset по X-NEXX-Company-ID через membership lookup
  • Несоответствие user ↔ company → 403
Human QA evidence
    T3 — switch на другую компанию, данные первой компании визуально не видны — passed 2026-05-19 (Sasha + Andrei)
D1.8
Audit log пишется
Действие → запись в БД с timestamp/user/action — требует уточнения у Кости
Clarify
What we have
  • RequestLog middleware: каждый HTTP request → запись (timestamp, userId, companyId, method, path, statusCode, durationMs, request/response previews с PII redaction)
  • Видно вживую в панели /api/internal/v1/admin/logs/ — фильтрация по method/level/path/status
  • На этом дашборде есть live-просмотр (см. блок "Server request log" ниже)
Possible gap

Если Костя ожидает отдельную AuditLog таблицу для бизнес-событий (`user.created`, `membership.suspended`, ...), а не HTTP-уровень — это Stage 2 задача. Спросить на созвоне: достаточно ли request-log для acceptance, или нужна отдельная business-event таблица.

Checkpoint — UI

Открыть live logs panel ниже на этой странице, нажать Reload.

D1.9
Mock BACKEND отвечает (3 endpoints через curl)
Стаб-эндпоинты с envelope contractVersion: mock-v0, live: false
Done
Endpoints — built 2026-05-20 specifically for D1.9
  • GET /api/mock-backend/health/
  • POST /api/mock-backend/auth/token/
  • GET /api/mock-backend/companies/
Checkpoint — curl (все три ниже зелёные на staging)
curl https://nexx-api.srv.acebox.eu/api/mock-backend/health/
# → 200 {contractVersion: "mock-v0", live: false, data: {status: "ok", service: "nexx-backend-mock"}}

curl -X POST https://nexx-api.srv.acebox.eu/api/mock-backend/auth/token/
# → 200 {data: {accessToken: "mock-access-token", tokenType: "Bearer", expiresIn: 900, ...}}

curl https://nexx-api.srv.acebox.eu/api/mock-backend/companies/
# → 200 {data: {items: [Mock Buyer SIA, Mock Supplier SIA], count: 2}}
Boundary

Это не настоящий backend. Envelope (contractVersion, isFinalContract: false, live: false) явно показывает контракт-стаб. Семантика payload-полей deferred к NEXX BACKEND / 1C.

Source
  • backend/core/mock_backend.py
  • backend/core/engine_contract.py — registry команд + событий
  • docs/NEXX_PLATFORM_BACKEND_MOCK_CONTRACT_v0.md
D1.10
Staging доступен и работает
Открыть staging → залогиниться → действия работают
Done
Live URLs
Note

У Кости в roadmap указан домен staging.nexx.global — мы используем *.srv.acebox.eu (наш инфраструктурный домен). Функционал staging работает; домен — отдельный вопрос про DNS/брендинг.

Checkpoint — curl
curl https://nexx-api.srv.acebox.eu/api/health/
# → 200 {status: "ok"}
Evidence
    Все 30 Stage 1 manual QA сценариев пройдены на этом staging.
D1.11
OpenAPI спецификация (черновик)
Документ в репо + Swagger UI + TS-handoff JSON
Done
Artifacts
Version

v1.2.0 — покрывает auth, companies, memberships, catalog, cart, checkout, orders, admin logs.

D1.12
Контракт PLATFORM ↔ BACKEND (черновик)
Документ согласован Александром и Ильёй
Awaiting signoff
Documents
  • docs/NEXX_PLATFORM_BACKEND_MOCK_CONTRACT_v0.md — описание seam mock-v0
  • backend/core/engine_contract.py — registry COMMAND_FAMILIES + BUSINESS_EVENTS
  • Mock endpoints из D1.9 — реальная демонстрация контракт-формы
Status

Документ существует, нужна формальная подпись Ильи (CTO) и Alex'а на созвоне 21:00.

D1.13
CI/CD работает
Push → lint + tests; merge в main → деплой на staging
Partial
What works
  • Frontend: GitHub Actions + deploy скрипт — auto-deploy на push в main
  • Backend: scripts/deploy.sh — manual rsync + docker compose up
  • Backend tests: ./scripts/verify_backend.sh запускает pytest вручную перед коммитом
Gap

Backend не имеет GitHub Actions — отдельный CI runner и pipeline не настроены. Stage 2 carry-over.

D1.14
Базовое тестовое покрытие
PLATFORM: >50% на критичных модулях; APP: >30% на ключевых компонентах
Measure pending
What exists
  • Backend pytest suite: ~150+ тестов покрывают auth, companies, memberships, catalog, cart, checkout, orders
  • Frontend Playwright smoke: 15 deployed-staging scenarios green
  • Human QA: 30/30 Stage 1 scenarios passed manually
Gap

Измеренного % покрытия (pytest --cov) пока нет. Можно запустить за 2 минуты до созвона если Костя хочет точные цифры.

Stage 1 Human Acceptance — manual QA (30/30 passed)
Staging: nexx-app.srv.acebox.eu · Password for demo users: demo-pass-123 · Passed 2026-05-18 / 2026-05-19 by Sasha + Andrei. Click any scenario for click-by-click steps and pass criteria.
Auth — register, login, password reset, verify, company creation14/14
A1
Login buyer admin
passed
Steps
  1. Открыть nexx-app.srv.acebox.eu
  2. Email: demo.buyer.admin@example.com, Password: demo-pass-123
  3. Нажать Log in
Pass criteria
  • Открылся authenticated workspace
  • Heading: Demo Buyer SIA
  • Active company: Demo Buyer SIA
  • Role badges включают Buyer и Company Admin
A2
Logout
passed
Steps
  1. На workspace нажать Logout
Pass criteria
  • Возврат на public login screen
  • Authenticated workspace больше не виден
  • Refresh не восстанавливает старое state
A3
Login supplier admin
passed
Steps
  1. Logout если нужно
  2. Email: demo.supplier.admin@example.com, Password: demo-pass-123
  3. Log in
Pass criteria
  • Active company: Demo Supplier Food SIA
  • Market role: Supplier
  • Buyer-only controls не выглядят основными
A4
Login both-role admin
passed
Steps
  1. Logout если нужно
  2. Email: demo.both.admin@example.com, Password: demo-pass-123
  3. Log in
Pass criteria
  • Active company: Demo Both Trade SIA
  • Both-role company behavior виден
A5
Company switcher user login
passed
Steps
  1. Logout если нужно
  2. Email: demo.context.switcher@example.com, Password: demo-pass-123
  3. Log in
Pass criteria
  • Active company selector виден
  • В selector 3 seeded companies
  • Current active company отображается
A6
Active company switch
passed
Steps
  1. Войти как demo.context.switcher@example.com
  2. Открыть Active company selector
  3. Выбрать другую company
Pass criteria
  • Heading меняется на выбранную company
  • Active company text обновляется
  • Market role badge меняется
  • Workspace не остаётся со stale context
A7
Resend verification email
passed
Steps
  1. Создать fresh account через Create account, не подтверждать email
  2. Перейти на Verify email
  3. Ввести unverified email → Resend verification email
  4. Проверить inbox
Pass criteria
  • UI: Verification email requested. Check the inbox for that address.
  • Письмо приходит
  • Cooldown 60s между попытками
A8
Password reset request
passed
Steps
  1. На login нажать Forgot password?
  2. Ввести email existing account
  3. Нажать Send reset link
  4. Проверить inbox
Pass criteria
  • UI: If the account exists, a password reset email has been sent.
  • Письмо приходит на existing account
A9
Password reset apply
passed
Steps
  1. Открыть свежий reset link из письма
  2. Token подставился в form
  3. Ввести новый password, подтвердить, submit
  4. Login с новым password
Pass criteria
  • Reset проходит
  • UI сообщает password updated
  • Login с новым password работает
A10
Old password after reset fails
passed
Steps
  1. После A9 вернуться на login
  2. Тот же email, старый password
  3. Log in
Pass criteria
  • Старый password не работает
  • UI: Email or password is invalid
A11
Login with new password after reset
passed
Steps
  1. Email из A9, новый password
  2. Log in
Pass criteria
  • Login успешный
  • User попадает в workspace или Create your company по правилам
A12
Password reset invalidates old sessions (critical)
passed
Steps
  1. Открыть session в browser #1
  2. В browser #2 — password reset для того же user
  3. В browser #1 → refresh
Pass criteria
  • Старая session недействительна
  • Возврат к login или auth error
  • Допустимо: Access token is invalid or expired.
  • Старый password не работает, новый — работает

Этот тест поймал backend issue. Фикс: password_changed_at + iat-check в JWT validation.

A13
Unverified user cannot create company
passed
Steps
  1. Fresh account через Create account
  2. Не подтверждать email
  3. Попробовать пройти к company creation
Pass criteria
  • Company не создаётся
  • UI/backend требуют email verification (EMAIL_NOT_VERIFIED)
A14
Verified new user creates first company
passed
Steps
  1. Fresh account через Create account
  2. Подтвердить email из письма
  3. Login
  4. На Create your company заполнить Registration number, Company name, Legal address, Market role
  5. Create company
Pass criteria
  • Company создаётся
  • User попадает в workspace новой company
  • Header показывает company и signed-in email
Invite / Membership11/11
I1
Existing verified user added as active member
passed
Steps
  1. Login как demo.buyer.admin@example.com
  2. Company → panel Memberships
  3. В Add membership: email existing verified non-member, role Manager
  4. Add membership
Pass criteria
  • UI: Member added: <email> as Manager.
  • Новая строка в membership list, status active, role Manager
I2
Fresh unknown email gets invitation, not active row
passed
Steps
  1. Login как buyer admin → CompanyAdd membership
  2. Fresh unknown email, role Manager
  3. Add membership → проверить inbox
  4. Прокрутить membership list
Pass criteria
  • UI: Invitation sent to <email> as Manager.
  • Invitation email приходит
  • Fresh email НЕ появляется как active row до регистрации
I3
Invitation email content
passed
Pass criteria
  • Sender: NEXX Platform <nexx-platform@acebox.eu>
  • Текст: demo.buyer.admin@example.com invited you
  • Company: Demo Buyer SIA
  • Role: MANAGER
  • Link: /auth/invite?token=…
  • Expires in 7 days
I4
Invitation link opens invite registration screen
passed
Pass criteria
  • Link открывает /auth/invite?token=…
  • Page: Invitation registration
  • Видна summary: company, role, invited email, inviter, expires
  • Нет Preview на live invite lookup
I5
Register by invite and auto-attach
passed
Steps
  1. Открыть invitation link из I3
  2. Зарегистрировать на invited email
  3. Подтвердить email
  4. Login
Pass criteria
  • User попадает сразу в Demo Buyer SIA, не в Create your company
  • Header: invited email
  • Active company: Demo Buyer SIA
  • Badges: Buyer + Manager
I6
Invited member workspace sanity
passed
Steps
  1. Login приглашённым/прикреплённым user после verification
Pass criteria
  • User в правильном active company context
  • Header и role badges соответствуют invited account и роли
I7
Role update + filters + feedback + mobile stability
passed
Steps
  1. Login как admin → CompanyMemberships
  2. Сменить role у другого member через Role selector
  3. Применить status / role / quick find filters
  4. На phone: после смены role — viewport не должен прыгать
Pass criteria
  • Role switching работает
  • Filters работают
  • Membership role updated. внутри affected row
  • На phone viewport остаётся около affected user
I8
Suspend an active non-admin member
passed
Steps
  1. В membership row → Suspend
  2. Confirmation Suspend this member?Confirm suspend
Pass criteria
  • Status row → Suspended
  • Reactivate становится видимой
  • Membership suspended. внутри row
  • Найти suspended member по Suspended status filter
I9
Reactivate a suspended member
passed
Steps
  1. В suspended row → Reactivate
Pass criteria
  • Status → Active
  • Suspend снова видна
  • Membership reactivated. внутри row
  • Member виден под Active filter
I10
Non-admin cannot manage memberships
passed
Steps
  1. Login как invited non-admin user
  2. Открыть CompanyMemberships
Pass criteria
  • Header показывает Demo Buyer SIA
  • Видна Buyer lane
  • НЕТ Add member, role selector, Suspend, Reactivate
I11
Last admin / protected admin guardrail
passed
Steps
  1. Login как demo.buyer.admin@example.com
  2. CompanyMemberships
  3. Найти свою row
Pass criteria
  • Своя row показывает Your current membership is protected.
  • Своя row не имеет role selector
  • Своя row не имеет Suspend / Reactivate
  • Невозможно оставить company без admin
Tenant / Active company5/5
T1
Active company visible after login
passed
Steps
  1. Login как demo.buyer.admin@example.com
Pass criteria
  • Header: Demo Buyer SIA
  • Signed-in user line: demo.buyer.admin@example.com
  • Active company panel: Demo Buyer SIA
  • Role badges соответствуют buyer/admin
T2
Context switcher changes active company
passed
Steps
  1. Login как demo.context.switcher@example.com
  2. Открыть Active company selector → выбрать другую company
Pass criteria
  • Header, active company line, role badges, workspace context обновляются
  • Selector содержит несколько companies
T3
Company-scoped data does not visually leak after switch
passed
Steps
  1. Login как demo.context.switcher@example.com
  2. Switch на Demo Both Trade SIA
Pass criteria
  • Active company marker, header, workflow, workspace data — все принадлежат selected company
  • Нет stale company A rows как company B data
T4
Reload preserves selected active company
passed
Steps
  1. Login как demo.context.switcher@example.com
  2. Выбрать active company
  3. Browser refresh
Pass criteria
  • Selected active company стабильна после refresh
  • User остаётся logged in
  • Authenticated workspace восстанавливается
  • Нет token/session/company invalid error
T5
Logout clears active company / session state
passed
Steps
  1. Logout из authenticated workspace
  2. Browser refresh
Pass criteria
  • Public login shell виден
  • Authenticated company context не виден
  • Refresh не восстанавливает old workspace
  • Logout возвращает к root login route, не к auth deep-link
Stage 2 — Onboarding, Catalog, Price Lists, Supplier Card, Lursoft
Weeks 3-4 · 16 May – 4 Jun 2026 · Stage 2 R1 scope пройден: manual QA D2.1–D2.14 passed, backend evidence закрыт, frontend на Vercel, backend на production API. R1/R2 граница: один default price list на supplier; per-buyer/multi price lists — Phase 2/R2.
R1 100%
Stage 2 — R1 scope пройден
D2.1–D2.14: frontend manual QA passed (Andrey + Codex UI + Sasha verification) + backend verification evidence (incl. D2.13). Все 3 находки закрыты (FIND-1 token-refresh, FIND-3 delete-feedback — frontend; FIND-2 seed default warehouse — backend).
R1/R2 scope-граница (не недоделка): price lists — в R1 один default price list на supplier; per-buyer / personal / multi-price → Phase 2/R2.
D2.3/D2.4: профили сохраняются и читаются через backend (passed). Расширения после R1 — внешний sync/audit профилей и backend cache/audit/env для Lursoft — вынесены в роадмап (Stage 4 / Phase 2), это не хвосты Stage 2. Финальный R1-scope sign-off — за Андреем/Костей.
Logged-in additional company create
COMPANY-MULTI-001 (d41ac65) backend regression test pins customer flow: authenticated email-verified user POSTs /companies/onboarding/manual/ with new registrationNumber → 201, COMPANY_ADMIN, isActive=true; frontend wizard live · QA: Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06, additional-company via switcher)
100%
Stage 2 onboarding wizard (Lursoft + country + verification)
Backend: LURSOFT-001 (2f39628) mock lookup + ONB-002 (5aed004) country/verificationMethod fields. Frontend: FE-STAGE2-ONBOARDING-001 (frontend e3a5bb0) Lursoft onboarding shell deployed staging, mock marked Preview, manual fallback wired. Live Lursoft now ENABLED · QA (D2.1/D2.2): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06)
100%
Buyer + supplier profile CRUD
Backend: PROFILE-BUYER-001 (fef6303) + PROFILE-SUPPLIER-001 (ffbebfe) v1 GET/PATCH role-gated. Frontend: FE-STAGE2-PROFILE-001 (frontend 6a832f4) profile shell deployed staging, role-gated edit controls live · QA (D2.3/D2.4): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06); расширенный external sync/audit — будущий этап
100%
Catalog categories + items CRUD
Backend: CAT-002 (b3c2feb) + CAT-003 (28ef7b5). Frontend: FE-STAGE2-CATEGORIES (cd39c06) + FE-STAGE2-CATALOG-ITEMS-001 (8217049) shell deployed staging — list/create/update/delete categories with delete-blocked UI; item create/update/deactivate/reactivate, SKU locked after create, barcode supported. Photos deferred per knownLimitations · QA (D2.6/D2.7): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06; CRUD). FIND-3 (FE silent on blocked-delete) FIXED by Codex (dbd1f24, deployed)
100%
Default price list (R1 — real endpoint)
Backend: PRICE-002 (86eb9d0) real GET/PUT /api/internal/v1/price-lists/default/ (Option B facade): header ← SupplierProfile, lines ← CatalogItem, gross computed; migration 0025; forwards /price-lists to mock (D2.13). Contract v1.5.0; openapi info.version 0.1.0→1.5.0. Supersedes alt-б. Live smoke green (gross 3.40→4.11). Frontend: D2.8 price-list UI live (GET/PUT 200/200) · QA (D2.8): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06; gross 10.77/27.83/24.60 correct, buyer sees prices)
100%
Supplier card with full profile
Backend: PROFILE-SUPPLIER-001 (ffbebfe) profile block in card + cosmetic fix 7453d85 (country/verificationMethod in supplier object). Frontend: supplier-detail shell consumes new fields via typed v1.5.0 schema. · QA (D2.9): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06; buyer card = profile + catalog + rail)
100%
Buyer preview without prices
Backend: CAT-004 (c94f429) GET /catalog/items/ server-side hides netPrice/vatRate (null + pricesVisible=false) unless buyer has active relationship AND supplier has default_price_list_active=True. Frontend: buyer-facing no-price catalog preview live. · QA (D2.10): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06; NoRel supplier — items visible, prices hidden, backend-confirmed null)
100%
Lursoft live integration (D2.1 / D2.11)
LURSOFT-002 (b8273dc / debe8bd) — live ENABLED on staging 2026-06-05 (DEF-009 lifted). OAuth2 against b2b.lursoft.lv (spec v1.3.69) + explicit User-Agent (Cloudflare 1010 fix), 24h cache, audit, graceful fallback. Live smoke green: real reg number → live data, repeat = cache hit (no extra quota). Demo fixtures always served from mock even in live mode, so QA/demos spend no quota. · QA (D2.11): Andrey/Codex FE fallback ✓, strict cache/audit/env evidence in issue #6; Sasha verify ✓ (2026-06-06; D2.11 FE fallback via D2.2 LV-NOTFOUND/LV-DOWN). cache/audit/env ведётся как backend evidence (не блокирует R1 UI acceptance)
100%
Company structure / warehouses (D2.5)
WAREHOUSE-001 (49f2948, 2026-06-04) — GET/POST /api/internal/v1/companies/{id}/warehouses/; default "Основной склад" auto-created at onboarding; COMPANY_ADMIN can add more; structure only (no stock/accounting); create forwards to mock BACKEND. Published in contract v1.4.0; staging smoke green (GET 200 / POST 201). Frontend Company → Structure UI live. · QA (D2.5): Andrey/Codex UI ✓ + Sasha verify ✓ (2026-06-06; create/list/Primary). FIND-2 (seeded companies had no default warehouse) FIXED — seed now creates it (00f405a). Closes reconciliation gap (issue #6)
100%
Mock BACKEND Stage 2 commands (D2.13)
MOCKBE-STAGE2-001 (49f2948) + PRICE-002 — mock BACKEND accepts all Stage 2 command families; PLATFORM structural writes (company / warehouse / buyer+supplier profile / category / item / relationship / price-list) forward via the engine_contract seam (mock-v0, no field payloads, non-fatal). Backend-internal. Evidence summary in issue #6 (#issuecomment-4633669716) + docs/stage2-d2.13-mock-backend-evidence.md; FE accepted ("Backend evidence accepted / record"). D2.13 = backend evidence, no human-click QA per playbook — accepted both sides.
100%
Stage 2 demo seed + contract bundle
seed_frontend_demo extended (SEED-002..004): per-supplier categories, published default price list on supplier_food+both_trade, 10+ dairy items, no-rel fixture, staff demo operator (SEC-001). Contract now v1.5.0 at /contracts/ (PRICE-002 price-lists endpoint + STAFF_REQUIRED; openapi info.version → 1.5.0). Backend-internal infra
100%
Stage 2 Human Acceptance — ручная QA (D2.1–D2.14) (UI ✓ Andrey/Codex + Sasha verify ✓ 2026-06-06)
Прод-фронт: nexx-frontend.vercel.app (backend platform-api.nexx.beyondhorizon.dev) · Пароль demo-юзеров: demo-pass-123 · Lursoft fixtures: LV-FOUND-1 / LV-NOTFOUND-1 / LV-DOWN-1 · Формат: куда зайти → что нажать → что увидеть → границы R1. Кликните сценарий для шагов. R1 scope: все D2.1–D2.14 passed (UI + backend verification evidence). Главная R1/R2 граница: price lists — в R1 один default price list на supplier; per-buyer/multi price lists — Phase 2/R2.
Онбординг и Lursoft — D2.1, D2.2, D2.113/3
D2.1
Создание компании через Lursoft lookup
passed
Куда зайти
  1. Залогиниться → company switcher вверху → Create new company
  2. Блок Lursoft lookup / Registry lookup
Что нажать
  1. Live: реальный латвийский номер (напр. 40003170000) → Lookup company
  2. Quota-safe: LV-FOUND-1Lookup company → market role → Create company
Что увидеть (pass)
  • Найден match, реальные данные (напр. SIA "LURSOFT IT"); UI честно отличает live от demo-fixture
  • Lookup-карточка читается desktop+mobile; market role выбирается нормально
  • После create — попадание в workspace новой компании, она в switcher, текущий юзер = Company Admin, переключение без потери сессии
Оговорка

Реальный Lursoft тратит quota — для повторов брать fixtures. Доп. backend-настройки (cache/audit/env) ведутся как backend evidence, не часть ручного UI acceptance.

D2.2
Ручное создание компании, если Lursoft не помог
passed
Куда зайти
  1. Тот же экран Create new company
Что нажать
  1. Registration number: LV-NOTFOUND-1 или LV-DOWN-1Lookup company
  2. Заполнить manual fields → country + market role → Create company
Что увидеть (pass)
  • Lookup-state понятно объясняет not-found / недоступность; UI не падает и не запирает
  • Manual path виден и работает, Create company проходит, попадание в workspace
Оговорка

Strict backend verification flags / audit / Platform Admin review — backend/product evidence, не UI-клик.

D2.11
Fallback, если Lursoft не нашёл или недоступен
passed
Куда зайти / что нажать
  1. Create new company → ввести LV-NOTFOUND-1Lookup company
  2. Повторить с LV-DOWN-1
Что увидеть (pass)
  • Нет crash, нет залипшего loading, нет ложного "live success"
  • Manual-форма остаётся доступной и рабочей
R1 / R2 деталь

R1 lookup + fallback — passed. Доп. backend-настройки cache/audit/env ведутся как backend evidence и не блокируют R1 UI acceptance.

Профили и структура — D2.3, D2.4, D2.53/3
D2.3
Редактирование buyer profile
passed
Куда зайти
  1. Buyer company → CompanyProfilesBuyer profile
Что нажать
  1. Изменить Contact person / Phone / Order email / Working hours / Delivery address → Save buyer profile
  2. Refresh или уйти/вернуться в профиль
Что увидеть (pass)
  • Поля ровные desktop, на mobile не разъезжаются и не перекрыты нижней навигацией
  • Working hours — человеческий текст; save-feedback = compact toast
  • После refresh/reopen значения сохранились
R1 / R2 деталь

R1: buyer/supplier profile CRUD через backend — passed. Расширенный external sync / audit — будущий этап (роадмап), не блокирует R1.

D2.4
Редактирование supplier profile
passed
Куда зайти
  1. Supplier / both-role company → CompanyProfilesSupplier profile
Что нажать
  1. Изменить contact + address / buyer-facing поля → сохранить
  2. Опц.: buyer workspace → Catalog → этот supplier → buyer-facing detail
Что увидеть (pass)
  • Copy человеческая, save-success = compact toast
  • Buyer-facing supplier detail не подставляет fake data (пусто, если нет данных)
R1 / R2 деталь

R1 supplier profile CRUD — passed. Strict external sync/audit = R2 / backend-evidence (как D2.3).

D2.5
Структура компании / склады (warehouses)
passed
Куда зайти
  1. CompanyStructure
Что нажать (admin)
  1. Посмотреть список складов → name QA Warehouse <дата> + code QA-WH-<дата> + address → Create warehouse
Что увидеть (pass)
  • Страница объясняет склады как структуру компании (не stock/inventory); форма аккуратная desktop+mobile
  • Созданный склад появился; у default — badge Primary
  • Non-admin видит список/заметку, но без активной формы create
Оговорка

Stage 2 = structure/list/create. Stock balances / accounting / финансовые потоки складов тут не ожидаются. (FIND-2: seed без default-склада — исправлено.)

Каталог, прайс-лист, карточка — D2.6, D2.7, D2.8, D2.9, D2.105/5
D2.6
Категории каталога: create / edit / delete
passed
Куда зайти
  1. CompanyMy catalogSupplier catalog categories
Что нажать
  1. Создать top-level QA Cat <дата> → проверить в списке
  2. Опц.: child через parent selector (только для проверки иерархии)
  3. Edit имя QA-категории
  4. Delete-blocked: попытаться удалить категорию с items (НЕ удалять seeded data)
  5. Успешный delete: создать пустую QA Empty Cat <дата> и удалить её
Что увидеть (pass)
  • Parent selector понятен; success/error = compact toast
  • Delete-blocked состояние понятно, когда есть items; mobile cards читаемы
Оговорка

Optional category description в текущем R1-contract нет — граница R1, не bug. FIND-3 (молчание UI при blocked-delete) — исправлено.

D2.7
Товары каталога: create / edit / deactivate / reactivate
passed
Куда зайти
  1. CompanyMy catalogSupplier catalog items
Что нажать
  1. Add item: уникальный SKU QA-ITEM-<дата>-01, name, category, net price, VAT, опц. barcode → сохранить
  2. Edit: SKU нельзя менять; поменять name/category/price/VAT → сохранить
  3. Deactivate → подтвердить → item inactive → Reactivate → снова active
Что увидеть (pass)
  • Колонки таблицы выровнены, длинные RU-labels не рвутся, mobile cards читаемы
  • В edit-форме есть Back to items; feedback = compact toast
Оговорка

Photos не поддержаны текущим contract — Phase 2/R2. Pagination/filter — story-level границы R1.

D2.8
Default price list поставщика
passed
Куда зайти
  1. CompanyMy catalogDefault price list
Что нажать
  1. Пустое имя → Save price list → должна появиться visible validation
  2. Заполнить name / effective date / active flag; изменить net price + VAT у item → Save price list
  3. Refresh → проверить сохранение; открыть buyer-каталог → изменённые цены видны
  4. Создать новый item (D2.7) → вернуться → он появился строкой; восстановить исходные значения
Что увидеть (pass)
  • R1-модель: один default price list для buyers (без per-buyer); на mobile Net/VAT с labels
  • Error/success видны без скролла; данные backed by live GET/PUT /price-lists/default/
Оговорка

Кнопки "add price row" нет — строки приходят из catalog items. Per-buyer/personal price lists = Phase 2/post-MVP.

D2.9
Карточка supplier для buyer
passed
Куда зайти
  1. Buyer workspace → Catalog → supplier card (напр. Demo Supplier Food SIA)
Что увидеть (pass)
  • Supplier header, status pills, profile card, catalog preview, right rail — читаются desktop
  • На mobile порядок блоков понятный (hero/profile/relationship до списка items)
  • Доступные profile fields показаны честно; нет fake text
Оговорка

У части demo-suppliers профильные данные sparse — это fixture/data limitation, не UI-failure.

D2.10
Просмотр supplier без цен
passed
Куда зайти
  1. Buyer workspace → Catalog → supplier без active relationship (NoRel, если есть в demo)
Что увидеть (pass)
  • Categories/items видны, цены скрыты, cart-controls недоступны/disabled
  • Экран объясняет, почему цены скрыты; Request relationship виден и enabled
  • Mobile-версия читаема
Контракт и полный путь — D2.12, D2.13, D2.143/3
D2.12
OpenAPI / contract coverage (review, не клики)
accepted
Как проверять

Чеклист-ревью во время остальных D2-шагов, не отдельный клик-тест.

Что подтвердить
  • Onboarding, profiles, structure, catalog, price list, buyer preview, cart/checkout/orders — используют live contract-backed API
  • UI не заявляет live там, где mock/preview; mock/fixture промаркированы честно
  • Оговорки видны: no item photos, no category description, no per-buyer/personal price lists
Тех-проверка

При необходимости попросить подтвердить, что frontend-handoff.json + OpenAPI + typed client соответствуют текущему Stage 2 (контракт v1.5.0, /contracts/).

D2.13
Mock BACKEND Stage 2 commands (backend evidence)
accepted
Как проверять

Backend/platform evidence, не клик-сценарий. Открыть: backend issue #6 comment 4633669716 + docs/stage2-d2.13-mock-backend-evidence.md.

Что покрывает evidence
  • Команды company / warehouse / buyer+supplier profile / category / item / relationship
  • Deterministic backend-тесты; non-fatal mock-v0 поведение + boundary notes
Итог

Не доказывать кликами в UI. Принято обеими сторонами как backend-evidence accepted.

D2.14
Полный demo-путь: supplier → buyer → cart → orders
passed
A — supplier source
  1. Как supplier/both admin → CompanyMy catalog: categories/items есть (10+ item demo supplier)
  2. Default price list published/active, цены/VAT заполнены
B — buyer preview
  1. Как buyer admin → Catalog → supplier с видимыми ценами: profile/card, categories/items, prices, Add-to-cart
C — cart → D — checkout → E — orders
  1. Добавить items → Cart (группировка по suppliers, whole-cart submit) → Validate checkout
  2. Delivery address / date / comment → place order → compact success toast
  3. Orders → новые заказы → order detail: lines, totals, status читаемы (и на mobile)
Что увидеть (pass)
  • Связно: supplier data → buyer catalog → cart → checkout → orders; цены/VAT согласованы после refresh
Оговорка

Per-supplier selective checkout в Stage 2/R1 не ожидается (whole-cart submit). Видимы: no photos, no category description, no per-buyer price lists.

Stage 3 — Search, Relationships, Cart, Checkout, Order Creation · delivered & deployed (backend + frontend v2) · ready for acceptance
Weeks 5-6 · 30 May – 12 Jun 2026 · D3.1–D3.12 реализованы + задеплоены (staging + prod), контракт v1.7.0 · автотесты + deployed smoke зелёные · gap-анализ против ТЗ (2026-06-30) закрыт — расхождения были только на фронте, все устранены и в проде · осталась только клиентская приёмка (walkthrough)
95%
Backend Stage 3 — сдан. Все бэкенд-обязательства D3.1–D3.12 реализованы, задеплоены в прод и staging (контракт v1.7.0, live на platform-api.nexx.beyondhorizon.dev), автотесты + deployed smoke зелёные, контракт опубликован в /contracts/.
Gap-анализ против ТЗ (2026-06-30): проверка v2 против MVP User Stories + sitemap показала, что бэкенд уже отдавал всё необходимое — 10 найденных расхождений были только на фронте и все закрыты + задеплоены на v2 prod (cbaac99→8c34f3a).
Сверх Stage 3: PRICE-003 — множественные прайс-листы + назначение по покупателю + bulk-операции (бэкенд миграции 0033/0034 + фронт), задеплоено в прод.
Проверить вживую: nexx-business-app-v2.vercel.app · demo-персоны, пароль demo-pass-123 · сценарии в V2 App · Тестирование.
Search / discovery (D3.1–D3.2)
Catalog + supplier discovery; procurementArea chips + area= filter (BKG-009); 20-supplier HoReCa seed (BKG-016) · BKG-021 price-wording audit covered · фронт-фильтры/сортировка/поиск поставщиков/детальная карточка закрыты в gap-closeout (#6–#8) · в проде на v2 · клиентская приёмка
95%
Buyer–supplier relationship lifecycle (D3.3–D3.6)
Request payload + enrichment + party-scoped detail; supplier reject/suspend/resume + both-side terminate; reuse-row re-request; email-link confirm (v1.6.2–v1.6.4) · страница подтверждения по email-ссылке закрыта в gap-closeout (#5) · в проде на v2 · клиентская приёмка
95%
Selective checkout + gates (D3.7–D3.9)
Selective checkout/validate; price-list / min-order (NET subtotal) / delivery-address gates; role-gates; typed blockers + supplierGroups totals (v1.6.5) · поля адреса/даты доставки на фронте закрыты в gap-closeout (#10) · в проде на v2 · клиентская приёмка
95%
Order creation + supplier split
Selective POST /orders/ (per-supplier set, atomic; omit = all-or-nothing); immutable order snapshots; supplier-specific split · списки заказов buyer/supplier + фильтры статусов на фронте закрыты в gap-closeout (#9) · в проде на v2 · клиентская приёмка
95%
Mock BACKEND order export (D3.10–D3.11)
order.created IntegrationJob + retry/backoff + idempotency; read-only export block in order responses (null for legacy/seed); frontend shows Preview-marked status (v1.6.6). Mock-граница Stage 3 закрыта — live Engine connector + lifecycle events = Stage 4 (по проекту) · в проде · клиентская приёмка
95%
E2E acceptance checkpoint (D3.12)
Deployed Stage 3 checkpoint: discovery → relationship/price gates → selective checkout/order → Preview-marked mock export. Deployed smoke 30 passed / 6 skipped · smoke:a11y 2 passed · verify_frontend.sh green (12 component files / 147 tests). Evidence: memory-bank/tasks/2026-06-17-FE-STAGE3-D3.12-001-e2e-acceptance-checkpoint/ · всё в проде (backend + v2) · остаётся клиентский walkthrough-приём
95%
Stage 4 — Order Lifecycle, Documents, Notifications, Admin, UAT, Live BACKEND
Weeks 7-8 · 13 Jun – 26 Jun 2026
Supplier handling lifecycle
SUP-002 backend confirm/ship/deliver with row-locking + FE-ORDERS-UX-003/006/007 action rail; LIVE-SMOKE-ORDERS-001 passed end-to-end · no human QA
80%
Buyer acceptance and discrepancy
ACC-001 backend (acceptance bounds + discrepancy_note) + FE-ORDERS-UX-008 acceptance draft summary · no human QA
80%
Document references from BACKEND
DOCREF-001 deferred — waiting on final BACKEND return shape; PDFs owned by 1C
0%
Notifications
NOTIF-001 deferred — no model, no email outbox, no in-app feed
0%
Platform admin / support views
ADMIN-001 deferred; Django admin registered for dev only (TOOL-002), no support UI
0%
UAT runbook
No formal UAT runbook; frontend staging deploy runbook exists (NEXX_FRONTEND_STAGING_DEPLOY_RUNBOOK_v1.md) + staging smoke harness at nexx-app.srv.acebox.eu
20%
Live BACKEND connectivity
ENG-001 / ENG-CONTRACT-002 blocked on final 1C contract (external dependency); mock-v0 foundation only · FR / FT N/A
0%

Server request log (live)

click Reload to fetch
TimeLvlMethodPathStatusmsUserCoRequestResponse
No data — click Reload.

Demo users on test API

RoleEmailCompany / id
Buyerdemo.buyer.admin@example.comDemo Buyer SIA — 1
Supplierdemo.supplier.admin@example.comDemo Supplier Food SIA — 2
Both rolesdemo.both.admin@example.comDemo Both Trade SIA — 4
Switcher (3 cos)demo.context.switcher@example.com1 + 2 + 4
Password: demo-pass-123