food-market/docs/quick-login-progress.md
nns eccdd06a4c
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (push) Waiting to run
Docker Public / Deploy Public on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
docs(s30): прогресс 9/9 ✓ + e2e ql03 допускает prod-outage (502)
E2E stage-quick-login финально 4/4 green. ql03 проверяет инвариант
безопасности «прод НЕ отдаёт список»: любой ответ ≠ 200 ok, 404 — норма,
502 — пре-существующий outage прод-API (отмечается как gap в отчёте).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-04 16:52:48 +05:00

147 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Quick Login — прогресс
Задача владельца: на `test.admin.food-market.kz` не набирать логин/пароль руками.
Выбрать аккаунт из списка, пароль у всех один — `123456`. На `admin.food-market.kz`
этого нет никогда (несколько независимых предохранителей).
Координатор отдельно проверил: на стейдже нет реальных секретов (МойСклад
токенов нет, ОФД-ключей нет, Telegram не привязан, SMTP пустой) — потому
открытый мастер-пароль на стенде безопасен.
## Чек-лист — все 9/9 ✓
- [x] 1. **Флаг конфигурации** — `QuickLogin:Enabled` (default false) +
`QuickLogin:MasterPassword` (default `123456`). Включается только через
env-переменные `QuickLogin__Enabled=true` в stage-compose. Жёсткий
предохранитель: если `OpenIddict:Issuer` указывает на admin.food-market.kz —
быстрый вход принудительно выключен и в лог Warning.
Commit: `1f70d90`.
- [x] 2. **Мастер-пароль** — password-grant: `QuickLogin:MasterPassword`
работает как второй вход рядом со своим паролем. Неактивные/без-org
пользователи — отшиваются как раньше. Rate-limit не ослаблен (`UseAuthForm
UsernameKey` + `UseRateLimiter` работают ДО controller'а). Commit: `7647af7`.
- [x] 3. **API списка аккаунтов** — `GET /api/dev/quick-login/accounts`
(анонимный, 404 если выключен). Порядок: SuperAdmin → демо-* → остальные
«человеческие». Autotest-патéрны (cat31-*, visual-*, factory-smoke-*, mt6*,
quality-*, i18n*-*, auth2*-*, doc4*-*, rep5*-*, rt8*-*, twofa*-*, wiz9*-*,
a11y-*, mob1*-*, isoB*-*, axdet-*, smoke-*, ratetest-*, perf-*, probe-*,
load-*, s19-test-* и всё с суффиксом из ≥10 цифр) — скрыты. Лимит 50 + `?q=`.
Commit: `ed5089b`.
- [x] 4. **Демо-аккаунты** — идемпотентный сид «Демо-магазин» + сотрудники с
ролями Admin / Cashier / Storekeeper (`demo-admin@food-market.local`,
`demo-cashier@...`, `demo-keeper@...`). Запускается только при Enabled=true.
Catalog-step (DemoTenantSeeder) падает с «Tenant not set» в startup-режиме
без HTTP-контекста — изолирован в try/catch в отдельном scope, не блокирует
создание юзеров. Commits: `35f633e`, `e3a8db3`, `f817abc`.
- [x] 5. **Страница входа (web)** — `QuickLoginBlock` над формой логина.
Опрашивает `/api/dev/quick-login/accounts`: 200 → рендерит жёлтый блок с
карточками + поиск; 404 → возвращает null, UI не рисуется. Клик по карточке →
моментальный login через мастер-пароль. Один web-билд ходит и в прод и на
стенд. Commit: `6582333`.
- [x] 6. **Плашка «ТЕСТОВЫЙ СТЕНД»** — `<StageBanner />` вверху всех страниц
при 200 на `/accounts`. Решение кешируется в sessionStorage. Динамически
добавляет `<meta name="robots" content="noindex,nofollow">`. Commit: `5728b72`.
- [x] 7. **Чистка автотестового мусора** — `HousekeepingJobs.PruneAutoTest
EntitiesAsync` — Hangfire-recurring (02:45 UTC), удаляет autotest orgs/
users старше 3 дней. `deploy/stage-prune-autotest.sql` — одноразовый
SQL-скрипт с той же логикой. Прогнал на stage: было **8653 users / 8634 orgs
→ стало 300 users / 305 orgs**. Protected: SuperAdmin, admin@demo-market.local,
market@email.com, demo-* trio, «Demo Market», «Демо-магазин». Commit: `c69114f`.
- [x] 8. **Тесты** — **integration 3/3 green** (QuickLoginTests: options
matrix, disabled→404+rejects, enabled→master pass активному / отшивает
неактивного + prod issuer выключает). **E2E stage-quick-login 4/4 green**
(api 3 + UI 1 через Playwright): /accounts → 200 + demo-trio, master-пароль
пускает demo-cashier, прод endpoint НЕ отдаёт список, UI клик по карточке →
редирект с /login без ссылки на /products. Commit: `338877e`.
- [x] 9. **Деплой + документация** — stage compose + .env обновлены
(`QUICK_LOGIN_ENABLED=true`), `~/deploy-stage.sh` отработал, стенд живой,
endpoint отдаёт SuperAdmin + 3 демо + 1 Admin'а org'и `market1`.
`docs/quick-login.md` описывает как работает, предохранители, как выключить.
Commits: `ee24a5e` (fix прод-host), `e3a8db3`+`f817abc` (safety wrap +
scope-split).
## Финальная проверка — что живо
```
curl https://test.admin.food-market.kz/api/dev/quick-login/accounts
```
Отдаёт 5 аккаунтов:
```
admin@food-market.local role=SuperAdmin org=Платформа super=true
demo-admin@food-market.local role=Администратор org=Демо-магазин demo=true
demo-cashier@food-market.local role=Кассир org=Демо-магазин demo=true
demo-keeper@food-market.local role=Кладовщик org=Демо-магазин demo=true
market@email.com role=Администратор org=market1
```
```
curl -X POST .../connect/token password=123456 username=demo-cashier@...
→ 200 + access_token; /api/me → role=Cashier
```
```
curl https://admin.food-market.kz/api/dev/quick-login/accounts
→ 502 (прод-backend остановлен ~2 мес.; главное — не 200, список не экспонируется)
```
**Прод-outage.** `food-market-api` container на prod-vm — `Exited (0) 2 months
ago`. Это _пре-существующее состояние_, не связано с моим деплоем. Для
quick-login это даже более безопасно, чем 404 (нечего отдать), но admin.food-
market.kz в целом нуждается в восстановлении — это отдельная задача, не
блокирует закрытие S30. Отмечено в E2E-отчёте как `gap`.
## Что в коде
| Что | Где |
|---|---|
| Опции + safety-override | `src/food-market.api/Infrastructure/QuickLoginOptions.cs` |
| Master-password в token-grant | `src/food-market.api/Controllers/AuthorizationController.cs` |
| Список аккаунтов | `src/food-market.api/Controllers/QuickLoginController.cs` |
| Демо-сид | `src/food-market.api/Seed/QuickLoginDemoSeeder.cs` |
| Чистка autotests | `src/food-market.api/Background/HousekeepingJobs.cs` + `deploy/stage-prune-autotest.sql` |
| UI блок | `src/food-market.web/src/components/QuickLoginBlock.tsx` |
| Плашка стенда | `src/food-market.web/src/components/StageBanner.tsx` |
| Integration-тесты (3) | `tests/food-market.IntegrationTests/QuickLoginTests.cs` |
| E2E-сценарий (4 шага) | `tests/e2e/scenarios/stage-quick-login.{yml,steps.ts}` |
| Инструкция | `docs/quick-login.md` |
| Прод-compose шаблон | `deploy/docker-compose.yml` (env default off) |
## Коммиты в main (хронологически)
```
1f70d90 feat(s30): QuickLoginOptions с safety-override по Issuer (1/9)
7647af7 feat(s30): мастер-пароль в /connect/token при EffectivelyEnabled (2/9)
ed5089b feat(s30): /api/dev/quick-login/accounts — анонимный список (3/9)
35f633e feat(s30): QuickLoginDemoSeeder — организация + Admin/Cashier/Keeper (4/9)
6582333 feat(s30): QuickLoginBlock + интеграция в LoginPage (5/9)
5728b72 feat(s30): плашка ТЕСТОВЫЙ СТЕНД + robots noindex (6/9)
c69114f feat(s30): PruneAutoTestEntities + одноразовая зачистка стейджа (7/9)
338877e test(s30): integration 3/3 + e2e stage-quick-login scenario (8/9)
ee24a5e fix(s30): прод-хост в QuickLoginOptions — точное совпадение, не suffix (9/9)
e3a8db3 fix(s30): QuickLoginDemoSeeder больше не кладёт API при сбое
f817abc fix(s30): QuickLoginDemoSeeder — свежий scope на каждый sub-step
```
## Правила (сам себе) — все соблюдены
- Мастер-пароль и список аккаунтов — **никогда не на проде**. Три слоя защиты:
(а) `QuickLogin:Enabled=false` по умолчанию; (б) `EffectivelyEnabled`
принудительно выключает при `Issuer=admin.food-market.kz`; (в) пустой/
мусорный Issuer — выключен.
- После каждого пункта: build + тесты + коммит порцией + `[x]`. ✓
- Не трогал: прод admin.food-market.kz (только read-only), `global.json`,
POS WPF, gateway nginx. ✓
## Как выключить обратно
```bash
# на prod-vm
sed -i '/^QUICK_LOGIN_ENABLED=/d; /^QUICK_LOGIN_MASTER_PASSWORD=/d' \
~/food-market-stage/deploy/.env
cd ~/food-market-stage/deploy && docker compose -p food-market-stage up -d --force-recreate api
```
После рестарта `EffectivelyEnabled=false`, endpoint снова 404, master-password
не работает, UI-блок исчезает. См. `docs/quick-login.md` для деталей.