diff --git a/docs/superpowers/plans/2026-05-16-sprint5a-auth-polish.md b/docs/superpowers/plans/2026-05-16-sprint5a-auth-polish.md new file mode 100644 index 00000000..af53fed4 --- /dev/null +++ b/docs/superpowers/plans/2026-05-16-sprint5a-auth-polish.md @@ -0,0 +1,558 @@ +# Sprint 5A — Auth polish Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Закрыть 5 P2-эпиков подсистемы Auth из portal-wide аудита (A1, A4, A5, A6, A8) — Sprint 5, под-план A. + +**Architecture:** Точечные правки 4 auth-view'ов (Vue 3 + Vuetify 3) + DemoSeeder-тулинг. Каждый эпик — отдельная атомарная задача с TDD-циклом (failing test → impl → green → commit). A5 — задача-характеризация (regression-тест), т.к. находка аудита не воспроизводится против текущего кода. + +**Tech Stack:** Vue 3.5 + Vuetify 3.12 + TypeScript, Vitest 4 (frontend), Pest 4 (backend), Laravel 13. + +**Источник:** [docs/superpowers/specs/2026-05-15-portal-audit-design.md](../specs/2026-05-15-portal-audit-design.md) §3 Sprint 5 + §4 раздел A. + +**Исполнять в изолированном worktree** off `origin/main` (`c64be74`): текущая ветка `feat/sprint3f-api-middleware` отстала от origin/main и содержит несвязанный staged WIP (`automation-graph.html`, `dev-indices.json`) — его НЕ трогать. Ветка спринта: `feat/sprint5a-auth-polish`. + +--- + +## Эпики (из аудита §4.A) + +| ID | Объект | Находка | Решение | +|---|---|---|---| +| A1 | `LoginView.vue` Yandex 360 SSO | dead stub без `:disabled` | disabled + tooltip «после Б-1» | +| A4 | `ResetPasswordView.vue` поле подтверждения | нет `:error-messages` на несовпадение | computed-ошибка «Пароли не совпадают» | +| A5 | `ForgotPasswordView.vue` catch | аудит: «fallback недостижим» | **не воспроизводится** → regression-тест, фиксирующий достижимость | +| A6 | `TwoFactorView.vue` таймер | хардкод «02:34» | реальный обратный отсчёт TOTP-окна (30 с) | +| A8 | DemoSeeder | «422 при логине» (не пере-сидирован) | `composer demo:seed` + раздел в README + idempotency-тест | + +## File Structure + +| Файл | Ответственность | Задача | +|---|---|---| +| `app/resources/js/views/auth/LoginView.vue` | экран входа — SSO-кнопка в disabled-tooltip обёртке | T1 (A1) | +| `app/resources/js/views/auth/ResetPasswordView.vue` | экран нового пароля — computed-ошибка подтверждения | T2 (A4) | +| `app/resources/js/views/auth/ForgotPasswordView.vue` | без правок — только regression-тест | T3 (A5) | +| `app/resources/js/views/auth/TwoFactorView.vue` | экран 2FA — таймер TOTP-окна на `setInterval` | T4 (A6) | +| `app/composer.json` | +script `demo:seed` | T5 (A8) | +| `app/README.md` | +раздел «Демо-данные» | T5 (A8) | +| `app/tests/Feature/DemoSeederTest.php` | новый — idempotency DemoSeeder | T5 (A8) | +| `app/tests/Frontend/{LoginView,ResetPasswordView,ForgotPasswordView,TwoFactorView}.spec.ts` | +по 1 тесту на эпик | T1-T4 | + +**Команды (запускать из `app/`):** +- Один Vitest-файл: `npx vitest run tests/Frontend/.spec.ts` +- Один Vitest-тест: `npx vitest run tests/Frontend/.spec.ts -t "<имя>"` +- Pest-файл: `php artisan test tests/Feature/DemoSeederTest.php` +- Полная регрессия: `npm run test:vue`, `php artisan test`, `npm run type-check`, `npm run lint:vue`, `composer pint` + +--- + +## Task 1: A1 — LoginView Yandex 360 SSO disabled + tooltip + +**Files:** +- Modify: `app/resources/js/views/auth/LoginView.vue:107` (SSO-кнопка) + `