- Fix OAuth redirect_uri mismatch in VK/Yandex callbacks (use PUBLIC_APP_URL) - Make quick dice buttons and anchor nav links orange by default - Densify DM Dashboard layout (smaller gaps, tighter spacing) - Hide LanguageSwitcher/Blog/About/Privacy links on DM pages - Increase notes textarea height for better usability
53 KiB
DM Dashboard MVP — Рабочий план
TL;DR
Quick Summary: Создать MVP DM Dashboard (
/dm/*) внутри Randify.pro — инструмент для мастеров D&D 5e с кубиками, трекером инициативы, справочником Open5e, локальными заметками и базовой OAuth-аутентификацией (VK + Yandex).Deliverables:
- Гибридный Astro билд с API routes
- PostgreSQL схема + Drizzle ORM + миграции
- OAuth 2.1 + PKCE (VK + Yandex)
- JWT сессии в httpOnly cookies
- Dice Roller (клиент-side)
- Initiative Tracker (простой список)
- Open5e Reference (поиск + карточки)
- Notes (localStorage)
- Оранжевая тема оформления
- TDD инфраструктура + тесты
Estimated Effort: Large Parallel Execution: YES — 3 волны + финальная верификация Critical Path: T1 (Hybrid Config) → T2 (DB Schema) → T7 (OAuth API) → T14 (DM Layout) → F1-F4
Context
Original Request
DM Dashboard — инструмент для мастеров настольных RPG, живёт на субдомене dm.randify.pro как часть проекта randify.pro. Три уровня доступа (FREE без аккаунта, FREE с аккаунтом, PRO), OAuth (VK/Yandex), Open5e справочник, AI-генерация, Boosty подписки.
Interview Summary
Key Discussions:
- MVP vs Iteration 2: MVP — базовые инструменты без AI. Итерация 2 — AI, PRO, Boosty, закладки, энкаунтер-билдер.
- Архитектура: Переход с static Astro на hybrid (API routes + Server Islands).
- БД: PostgreSQL на reg.ru, Drizzle ORM.
- Аутентификация: OAuth 2.1 + PKCE, JWT в httpOnly cookies.
- Дизайн: Оранжевая тема в стиле ролёвок, похожая на текущий Randify.pro.
- i18n: Только RU для DM Dashboard.
- Тесты: TDD с Vitest.
Research Findings:
- Randify — чисто статический сайт (27 генераторов), требуется серьёзная архитектурная трансформация.
- Open5e V2 API с field filtering и pagination.
- VK и Yandex требуют OAuth 2.1 + PKCE.
- Token bucket — стандарт для rate limiting (пригодится в итерации 2).
- Текущий деплой: Docker multi-stage (nginx:alpine) → нужен Node.js runtime.
Metis Review
Identified Gaps (addressed):
- Core Objective разделён на MVP и Product Vision.
- Scope IN/OUT чётко определены.
- Противоречия (static→hybrid, RU-only) задокументированы как осознанные отклонения.
- Тестовая стратегия (TDD) определена.
Work Objectives
Core Objective
Создать MVP DM Dashboard — модуль /dm/* внутри Randify.pro с базовыми инструментами для мастеров D&D 5e: кубиками, трекером инициативы, справочником Open5e, локальными заметками и базовой OAuth-аутентификацией (VK + Yandex).
Concrete Deliverables
astro.config.mjs— обновлённая конфигурация hybrid modeDockerfile+docker-compose.yml— Node.js runtime + PostgreSQLsrc/db/schema.ts— Drizzle ORM схемаsrc/db/migrate.ts— скрипт миграцийsrc/pages/api/auth/[...path].ts— API routes для OAuthsrc/lib/auth/jwt.ts— JWT утилитыsrc/lib/auth/oauth.ts— OAuth PKCE утилитыsrc/pages/dm/index.astro— главная страница DM Dashboardsrc/layouts/DmLayout.astro— лейаут DM Dashboardsrc/components/dm/DiceRoller.astro— кубикиsrc/components/dm/InitiativeTracker.astro— инициативаsrc/components/dm/Open5eReference.astro— справочникsrc/components/dm/NotesPanel.astro— заметкиsrc/lib/open5e/client.ts— клиент Open5e APIsrc/lib/open5e/cache.ts— кэшированиеsrc/i18n/dm-translations.ts— переводы DM Dashboard (RU)tests/— TDD тесты для всех модулей
Definition of Done
npm run buildпроходит без ошибокnpm run test— все тесты проходятdocker compose upзапускает приложение + PostgreSQL- OAuth вход через VK работает
- OAuth вход через Yandex работает
- Кубики генерируют корректные значения
- Инициатива сортирует по убыванию
- Open5e загружает и ищет монстров
- Заметки сохраняются в localStorage
- Дизайн в оранжевой теме
Must Have
- Гибридный Astro билд
- PostgreSQL подключение
- OAuth аутентификация (VK + Yandex)
- JWT сессии
- Dice Roller
- Initiative Tracker
- Open5e Reference (поиск + просмотр)
- Notes (localStorage)
- Оранжевая тема
- RU i18n
- TDD тесты
Must NOT Have (Guardrails)
- AI-генерация любого контента (Итерация 2)
- Rate limiting (нужен AI)
- PRO-tier логика (Итерация 2)
- Boosty верификация (Итерация 2)
- Закладки Open5e (Итерация 2)
- Энкаунтер-билдер (Итерация 2)
- Сохранение в PostgreSQL для пользовательских данных (Итерация 2)
- EN-версия DM Dashboard (Итерация 2)
- PWA / Service Worker (Итерация 2)
- Изменения существующих генераторов
- Удаление существующих страниц
Verification Strategy
ZERO HUMAN INTERVENTION — ALL verification is agent-executed. No exceptions.
Test Decision
- Infrastructure exists: YES (Vitest в проекте)
- Automated tests: TDD
- Framework: Vitest
- TDD Workflow: Каждая задача начинается с RED (падающий тест) → GREEN (минимальная реализация) → REFACTOR
QA Policy
Every task MUST include agent-executed QA scenarios.
Evidence saved to .sisyphus/evidence/task-{N}-{scenario-slug}.{ext}.
- Frontend/UI: Playwright — Navigate, interact, assert DOM, screenshot
- API/Backend: Bash (curl) — Send requests, assert status + response fields
- Database: Bash (psql/drizzle) — Query tables, assert rows
Execution Strategy
Parallel Execution Waves
Wave 1 (Foundation — start immediately):
├── T1: Astro Hybrid Config + Docker Update
├── T2: PostgreSQL Schema + Drizzle ORM
├── T3: Testing Infrastructure (TDD setup)
├── T4: Design System / Orange Theme
└── T5: OAuth App Setup Documentation
Wave 2 (Core Features — MAX PARALLEL):
├── T6: OAuth PKCE + API Routes (depends: T1, T2)
├── T7: JWT Sessions + Middleware (depends: T1, T2)
├── T8: Dice Roller Component (depends: T4)
├── T9: Initiative Tracker Component (depends: T4)
├── T10: Open5e API Client + Cache (depends: T1)
├── T11: Open5e Search UI (depends: T4, T10)
├── T12: Notes Component (depends: T4)
└── T13: Auth UI (Login/Logout/Profile) (depends: T6, T7)
Wave 3 (Integration + Polish):
├── T14: DM Dashboard Layout + Page (depends: T4, T6, T7, T8, T9, T10, T11, T12, T13)
├── T15: Navigation + Routing (depends: T14)
├── T16: Build Verification + CI Update (depends: T1, T14)
└── T17: Final Styling Polish (depends: T14, T15)
Wave FINAL (4 parallel reviews → user okay):
├── F1: Plan Compliance Audit (oracle)
├── F2: Code Quality Review (unspecified-high)
├── F3: Real QA (unspecified-high + playwright)
└── F4: Scope Fidelity Check (deep)
Dependency Matrix
- T1: - → T6, T7, T10, T14, T16
- T2: - → T6, T7, T16
- T3: - → T8, T9, T10, T11, T12
- T4: - → T8, T9, T11, T12, T13, T14, T17
- T5: - → (документация для пользователя)
- T6: T1, T2 → T13, T14
- T7: T1, T2 → T13, T14
- T8: T4 → T14
- T9: T4 → T14
- T10: T1 → T11, T14
- T11: T4, T10 → T14
- T12: T4 → T14
- T13: T6, T7, T4 → T14
- T14: T4, T6, T7, T8, T9, T10, T11, T12, T13 → T15, T16, T17
- T15: T14 → -
- T16: T1, T14 → -
- T17: T14, T15 → -
Agent Dispatch Summary
- Wave 1: T1→
quick, T2→quick, T3→quick, T4→visual-engineering, T5→writing - Wave 2: T6→
unspecified-high, T7→unspecified-high, T8→quick, T9→quick, T10→quick, T11→visual-engineering, T12→quick, T13→visual-engineering - Wave 3: T14→
deep, T15→quick, T16→unspecified-high, T17→visual-engineering - FINAL: F1→
oracle, F2→unspecified-high, F3→unspecified-high, F4→deep
TODOs
-
T1. Astro Hybrid Config + Docker Update
What to do:
- Обновить
astro.config.mjsсoutput: 'hybrid'иadapter: node() - Добавить
@astrojs/nodeадаптер - Обновить
Dockerfile: заменитьnginx:alpineнаnode:20-alpineсnode ./dist/server/entry.mjs - Добавить
docker-compose.ymlс PostgreSQL сервисом - Обновить
.github/workflows/deploy.ymlдля деплоя Node.js приложения - Проверить, что существующие
/generators/*маршруты остаются статическими (export const prerender = true)
Must NOT do:
- Не удалять существующие генераторы или страницы
- Не менять деплой основного сайта (только добавить Node.js runtime)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Конфигурационные изменения, не требует сложной логики
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1
- Blocks: T6, T7, T10, T14, T16
- Blocked By: None
References:
astro.config.mjs— текущая статическая конфигурацияDockerfile— текущий multi-stage build с nginx.github/workflows/deploy.yml— текущий деплой через rsync- Astro docs:
@astrojs/nodeadapter configuration
Acceptance Criteria:
npm run buildсоздаётdist/server/entry.mjsdocker build -t dm-dashboard .собирает образdocker run -p 4321:4321 dm-dashboardзапускает серверcurl http://localhost:4321/generators/coin-toss/возвращает статическую страницуcurl http://localhost:4321/api/healthвозвращает 200 (тестовый API route)
QA Scenarios:
Scenario: Astro hybrid build succeeds Tool: Bash Steps: 1. npm run build 2. ls dist/server/entry.mjs Expected Result: entry.mjs существует Evidence: .sisyphus/evidence/t1-hybrid-build.log Scenario: Existing generators still static Tool: Bash (curl) Steps: 1. docker run -d -p 4321:4321 dm-dashboard 2. curl -s http://localhost:4321/generators/coin-toss/ | grep -o "Coin Flip" Expected Result: "Coin Flip" найден в ответе Evidence: .sisyphus/evidence/t1-static-routes.htmlCommit: YES
- Message:
chore(dm): configure astro hybrid mode + docker - Files:
astro.config.mjs,Dockerfile,docker-compose.yml,.github/workflows/deploy.yml,package.json
- Обновить
-
T2. PostgreSQL Schema + Drizzle ORM
What to do:
- Установить
drizzle-ormиdrizzle-kit - Создать
src/db/schema.tsс таблицами:users(id, vkId?, yandexId?, email?, name, avatar, createdAt)sessions(id, userId, token, expiresAt) — для server-side сессий (MVP)
- Создать
src/db/client.ts— singleton PostgreSQL client - Создать
src/db/migrate.ts— скрипт для запуска миграций - Добавить
drizzle.config.ts - Создать
.env.exampleс переменными DATABASE_URL, JWT_SECRET
Must NOT do:
- Не создавать таблицы для заметок, НПС, энкаунтеров (Итерация 2)
- Не добавлять rate limiting таблицы (Итерация 2)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Схема базы данных, типичная задача
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1
- Blocks: T6, T7, T16
- Blocked By: None
References:
- Drizzle ORM docs: PostgreSQL setup, schema definition, migrations
src/lib/generator-schema.ts— Zod patterns (уже в проекте)src/data/config.ts— конфигурационные паттерны
Acceptance Criteria:
npx drizzle-kit generateсоздаёт SQL миграцииnpx drizzle-kit migrateприменяет миграции к БДdocker compose exec postgres psql -U dmuser -d dmdashboard -c "\dt"показывает таблицы users и sessions
QA Scenarios:
Scenario: Database migrations run successfully Tool: Bash Preconditions: docker compose up -d Steps: 1. npx drizzle-kit generate 2. npx drizzle-kit migrate 3. docker compose exec postgres psql -U dmuser -d dmdashboard -c "SELECT tablename FROM pg_tables WHERE schemaname='public'" Expected Result: users, sessions в списке таблиц Evidence: .sisyphus/evidence/t2-db-migrations.log Scenario: Drizzle client connects Tool: Bash (node) Steps: 1. node -e "const { db } = require('./src/db/client.ts'); console.log('Connected')" Expected Result: "Connected" (или эквивалент для ESM) Evidence: .sisyphus/evidence/t2-db-connection.logCommit: YES
- Message:
chore(db): setup drizzle orm + postgresql schema - Files:
src/db/schema.ts,src/db/client.ts,src/db/migrate.ts,drizzle.config.ts,.env.example
- Установить
-
T3. Testing Infrastructure (TDD Setup)
What to do:
- Убедиться, что Vitest настроен (уже есть в package.json)
- Создать
vitest.config.tsс алиасами@/*→src/* - Добавить
@testing-library/domиhappy-dom(илиjsdom) для компонентных тестов - Создать
tests/setup.ts— общий setup файл - Создать
tests/utils.ts— хелперы для тестов (mock auth, mock db) - Установить
playwrightдля компонентных тестов с рендерингом - Создать
playwright.config.tsс базовой конфигурацией - Написать первый тест-скелетон для проверки инфраструктуры
- Добавить скрипты
test:unitиtest:uiв package.json
Must NOT do:
- Не писать e2e тесты (только unit + component tests)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Настройка инфраструктуры
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1
- Blocks: T8, T9, T10, T11, T12 (все компоненты требуют тестов)
- Blocked By: None
References:
package.json— текущие скрипты testtsconfig.json— алиасы@/*- Vitest docs: configuration, aliases, DOM environment
Acceptance Criteria:
npm run testзапускается без ошибокnpm run test:unitпроходит минимум 1 тест- Алиасы
@/*работают в тестах
QA Scenarios:
Scenario: Vitest runs with aliases Tool: Bash Steps: 1. npm run test:unit 2. grep "PASS\|1 passed" в выводе Expected Result: Тесты проходят, алиасы @/* резолвятся Evidence: .sisyphus/evidence/t3-vitest-run.logCommit: YES
- Message:
chore(tests): setup vitest + tdd infrastructure - Files:
vitest.config.ts,tests/setup.ts,tests/utils.ts,package.json
-
T4. Design System / Orange Theme
What to do:
- Создать
src/styles/dm-theme.cssс CSS переменными:--accent: #E87722(оранжевый)--accent-light: #FF9F43--accent-dark: #D35400--bg-primary: #0f0f0f--bg-secondary: #1a1a1a--bg-card: #242424
- Создать
src/components/dm/DmButton.astro— кнопка в DM стиле - Создать
src/components/dm/DmCard.astro— карточка в DM стиле - Создать
src/components/dm/DmInput.astro— инпут в DM стиле - Создать
src/components/dm/DmHeader.astro— хедер DM Dashboard - Обновить
DmLayout.astro(заглушку) с подключением темы
Must NOT do:
- Не менять существующие компоненты Randify (GeneratorCard, BaseLayout и т.д.)
- Не добавлять анимации сложнее текущих (popElement)
Recommended Agent Profile:
- Category:
visual-engineering - Skills: [
/frontend-ui-ux] - Reason: UI/UX дизайн, стилизация
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1
- Blocks: T8, T9, T11, T12, T13, T14, T17
- Blocked By: None
References:
src/layouts/BaseLayout.astro— текущая тема--accent: #534AB7src/components/GeneratorCard.astro— паттерн карточекsrc/components/ResultBox.astro— паттерн отображения результатов- Tailwind CSS v4 docs: custom theme, CSS variables
Acceptance Criteria:
- Оранжевый цвет
#E87722применяется к кнопкам - Тёмная тема совместима с текущей
- Компоненты Button, Card, Input рендерятся
QA Scenarios:
Scenario: Orange theme renders correctly Tool: Playwright Steps: 1. Открыть http://localhost:4321/dm/ 2. Сделать скриншот 3. Проверить CSS var --accent = #E87722 Expected Result: Оранжевый акцентный цвет виден на кнопках Evidence: .sisyphus/evidence/t4-orange-theme.pngCommit: YES
- Message:
feat(ui): add orange dm theme + base components - Files:
src/styles/dm-theme.css,src/components/dm/*.astro
- Создать
-
T5. OAuth App Setup Documentation
What to do:
- Создать
docs/OAUTH_SETUP.mdс инструкциями:- Как зарегистрировать VK ID приложение
- Как зарегистрировать Yandex OAuth приложение
- Какие redirect URI настроить (
http://localhost:4321/api/auth/callback/vk,.../yandex) - Какие scopes запросить (профиль, email)
- Куда сохранить client_id и client_secret (.env)
- Добавить проверку env vars при старте приложения
Must NOT do:
- Не коммитить реальные client_id / client_secret
- Не создавать приложения за пользователя
Recommended Agent Profile:
- Category:
writing - Skills: []
- Reason: Документация
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1
- Blocks: (документация для пользователя, не блокирует код)
- Blocked By: None
References:
- VK ID docs: https://id.vk.com/about/business/go/docs/ru/vkid/latest/vk-id/connection/start-integration
- Yandex OAuth docs: https://yandex.com/dev/id/doc/en/concepts/ya-oauth-intro
Acceptance Criteria:
- Файл
docs/OAUTH_SETUP.mdсоздан и читаем .env.exampleсодержит VK_CLIENT_ID, VK_CLIENT_SECRET, YANDEX_CLIENT_ID, YANDEX_CLIENT_SECRET- Приложение проверяет наличие env vars и выдаёт понятную ошибку если их нет
QA Scenarios:
Scenario: Missing env vars produce clear error Tool: Bash Steps: 1. unset VK_CLIENT_ID 2. npm run dev Expected Result: Приложение не запускается с сообщением "Missing VK_CLIENT_ID" Evidence: .sisyphus/evidence/t5-env-check.logCommit: YES
- Message:
docs(dm): add oauth setup instructions - Files:
docs/OAUTH_SETUP.md,.env.example
- Создать
-
T6. OAuth PKCE + API Routes
What to do:
- Реализовать PKCE утилиты:
generateCodeVerifier(),generateCodeChallenge() - Создать
src/pages/api/auth/login/vk.ts— начало OAuth flow (генерация PKCE, редирект на VK) - Создать
src/pages/api/auth/callback/vk.ts— обработка callback (обмен code на token) - Создать
src/pages/api/auth/login/yandex.ts— аналогично для Yandex - Создать
src/pages/api/auth/callback/yandex.ts— callback для Yandex - Создать
src/pages/api/auth/logout.ts— выход - В
src/lib/auth/oauth.tsреализовать функции для каждого провайдера - Сохранение PKCE verifier в cookie (временное, httpOnly)
Must NOT do:
- Не использовать localStorage для code_verifier (XSS-риск)
- Не пропускать проверку state parameter
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
- Reason: OAuth + PKCE — security-critical
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T13, T14
- Blocked By: T1, T2
References:
- PKCE implementation pattern из research:
function generateCodeVerifier(): string { const array = new Uint8Array(32); crypto.getRandomValues(array); return btoa(String.fromCharCode(...array)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } - VK OAuth docs: https://id.vk.com/about/business/go/docs/ru/vkid/latest/vk-id/connection/realization
- Yandex OAuth docs: https://yandex.com/dev/id/doc/en/concepts/ya-oauth-intro
Acceptance Criteria:
curl /api/auth/login/vkвозвращает 302 редирект на VK OAuth- Callback route принимает code и state
- Logout route очищает cookies
QA Scenarios:
Scenario: VK OAuth login redirects correctly Tool: Bash (curl) Steps: 1. curl -s -o /dev/null -w "%{http_code}" http://localhost:4321/api/auth/login/vk Expected Result: 302 redirect Evidence: .sisyphus/evidence/t6-vk-login.log Scenario: Invalid state rejected Tool: Bash (curl) Steps: 1. curl -s "http://localhost:4321/api/auth/callback/vk?code=abc&state=wrong" Expected Result: 401 Unauthorized Evidence: .sisyphus/evidence/t6-invalid-state.logCommit: YES
- Message:
feat(auth): implement oauth pkce for vk and yandex - Files:
src/lib/auth/oauth.ts,src/pages/api/auth/**/*.ts
- Реализовать PKCE утилиты:
-
T7. JWT Sessions + Middleware
What to do:
- Установить
joseдля JWT - Создать
src/lib/auth/jwt.ts:createToken(userId)— создание JWTverifyToken(token)— верификацияsetAuthCookie(token)— установка httpOnly cookieclearAuthCookie()— очистка
- Создать
src/lib/auth/session.ts— работа с PostgreSQL sessions таблицей - Создать
src/middleware/auth.ts— middleware для проверки сессий - Добавить
Astro.locals.userтипизацию - TTL сессии: 7 дней
Must NOT do:
- Не хранить JWT secret в коде (только env)
- Не использовать
localStorageдля токенов
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
- Reason: Security-critical
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T13, T14
- Blocked By: T1, T2
References:
joselibrary docs: JWT sign, verify, Web Crypto APIsrc/db/schema.ts— sessions таблица
Acceptance Criteria:
createToken()генерирует валидный JWTverifyToken()принимает валидный и отклоняет истёкший- Cookie httpOnly, Secure, SameSite=strict
- Middleware устанавливает
Astro.locals.userдля авторизованных
QA Scenarios:
Scenario: JWT creation and verification Tool: Bash (node) Steps: 1. node -e "const { createToken, verifyToken } = require('./src/lib/auth/jwt.ts'); const t = createToken('user123'); console.log(verifyToken(t).sub)" Expected Result: "user123" Evidence: .sisyphus/evidence/t7-jwt.log Scenario: Expired token rejected Tool: Bash (node) Steps: 1. node -e "const { verifyToken } = require('./src/lib/auth/jwt.ts'); verifyToken('expired_token')" Expected Result: Ошибка "JWT expired" Evidence: .sisyphus/evidence/t7-jwt-expired.logCommit: YES
- Message:
feat(auth): implement jwt sessions + middleware - Files:
src/lib/auth/jwt.ts,src/lib/auth/session.ts,src/middleware/auth.ts
- Установить
-
T8. Dice Roller Component
What to do:
- Создать
src/components/dm/DiceRoller.astro - Поддержка нотаций: d4, d6, d8, d10, d12, d20, d100
- Поле ввода: "2d6+3" или кнопки быстрого выбора
- Модификатор (+/-)
- Использовать
crypto.getRandomValuesизsrc/lib/client/random.ts - Анимация броска (вращение кубика)
- История бросков
- TDD: написать тесты перед реализацией
Must NOT do:
- Не делать сервер-side броски (клиент-side только)
- Не добавлять advantage/disadvantage (MVP scope)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Простой клиентский компонент
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T14
- Blocked By: T4, T3
References:
src/lib/client/random.ts—randomInt,crypto.getRandomValuessrc/components/generators/NumberGenerator.astro— паттерн генератораsrc/components/ResultBox.astro— паттерн отображения результата
Acceptance Criteria:
- "1d20" генерирует число 1-20
- "2d6" генерирует число 2-12
- История бросков сохраняется в sessionStorage
- Анимация отображается при броске
QA Scenarios:
Scenario: d20 produces valid range Tool: Playwright Steps: 1. Открыть /dm/ 2. Кликнуть "d20" 3. Проверить результат 1-20 Expected Result: Число в диапазоне [1, 20] Evidence: .sisyphus/evidence/t8-d20-roll.png Scenario: Invalid input shows error Tool: Playwright Steps: 1. Ввести "abc" в поле dice 2. Кликнуть "Roll" Expected Result: Сообщение об ошибке "Неверная нотация" Evidence: .sisyphus/evidence/t8-invalid-dice.pngCommit: YES
- Message:
feat(dm): add dice roller component - Files:
src/components/dm/DiceRoller.astro,tests/dice-roller.test.ts
- Создать
-
T9. Initiative Tracker Component
What to do:
- Создать
src/components/dm/InitiativeTracker.astro - Форма добавления: Имя + Бросок инициативы (или авто-бросок d20 + модификатор)
- Список combatants, отсортированный по убыванию
- Кнопка "Следующий ход" — подсвечивает активного
- Кнопка "Удалить" для каждого
- Кнопка "Очистить всё"
- Данные в sessionStorage (обнуляются при refresh — MVP)
- TDD: написать тесты перед реализацией
Must NOT do:
- Не добавлять HP/статусы/раунды (MVP scope)
- Не сохранять в PostgreSQL (MVP scope)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Простой клиентский компонент
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T14
- Blocked By: T4, T3
References:
src/lib/client/random.ts—randomIntsrc/lib/client/animations.ts—popElementsrc/lib/client/validation.ts—createErrorDisplay
Acceptance Criteria:
- Добавление combatant увеличивает список
- Сортировка по убыванию броска
- "Следующий ход" меняет активного
- Refresh сбрасывает список
QA Scenarios:
Scenario: Initiative sorts descending Tool: Playwright Steps: 1. Добавить "Гоблин" с 15 2. Добавить "Воин" с 18 3. Проверить порядок: Воин, Гоблин Expected Result: Воин (18) выше Гоблина (15) Evidence: .sisyphus/evidence/t9-initiative-sort.png Scenario: Turn cycling works Tool: Playwright Steps: 1. Добавить 3 combatants 2. Кликнуть "Следующий ход" 3 раза 3. Проверить, что цикл замкнулся Expected Result: После 3-го клика активен первый Evidence: .sisyphus/evidence/t9-initiative-cycle.pngCommit: YES
- Message:
feat(dm): add initiative tracker component - Files:
src/components/dm/InitiativeTracker.astro,tests/initiative-tracker.test.ts
- Создать
-
T10. Open5e API Client + Cache
What to do:
- Создать
src/lib/open5e/client.ts:searchMonsters(query, filters)— поиск монстровgetMonster(key)— получение по slugsearchSpells(query, filters)— поиск заклинанийgetSpell(key)— получение заклинания
- Создать
src/lib/open5e/cache.ts:- Кэширование в localStorage с TTL (24 часа)
- Ключи:
open5e:monsters:query,open5e:monster:key
- Использовать Open5e V2 API с
fields=parameter - Обработка ошибок (API недоступен → fallback message)
- TDD: тесты с mock fetch
Must NOT do:
- Не кэшировать в IndexedDB (MVP: localStorage достаточно)
- Не делать server-side cache (MVP: client-side only)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: API клиент + кэш
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T11, T14
- Blocked By: T1, T3
References:
- Open5e V2 API:
https://api.open5e.com/v2/creatures/,https://api.open5e.com/v2/spells/ - Open5e docs: field filtering, pagination
Acceptance Criteria:
- Поиск "dragon" возвращает монстров
- Кэш сохраняет результаты в localStorage
- Повторный поиск использует кэш
- API недоступен → показывается ошибка
QA Scenarios:
Scenario: Search monsters returns results Tool: Bash (curl) Steps: 1. curl -s "https://api.open5e.com/v2/creatures/?name__icontains=dragon&fields=name,key,challenge_rating_decimal" Expected Result: JSON с массивом существ Evidence: .sisyphus/evidence/t10-open5e-search.json Scenario: Cache stores results Tool: Playwright Steps: 1. Открыть /dm/ 2. Поискать "goblin" 3. Проверить localStorage Expected Result: localStorage содержит ключ open5e:* Evidence: .sisyphus/evidence/t10-open5e-cache.logCommit: YES
- Message:
feat(dm): add open5e api client + localstorage cache - Files:
src/lib/open5e/client.ts,src/lib/open5e/cache.ts,tests/open5e-client.test.ts
- Создать
-
T11. Open5e Search UI
What to do:
- Создать
src/components/dm/Open5eReference.astro - Табы: Монстры / Заклинания
- Поисковая строка с debounce (300ms)
- Фильтры: CR (для монстров), Уровень (для заклинаний), Тип
- Список результатов с пагинацией
- Карточка деталей (модалка или раскрывающаяся карточка)
- TDD: тесты на поиск и фильтрацию
Must NOT do:
- Не добавлять закладки (Итерация 2)
- Не добавлять "добавить в энкаунтер" (Итерация 2)
Recommended Agent Profile:
- Category:
visual-engineering - Skills: [
/frontend-ui-ux] - Reason: UI компонент с поиском
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T14
- Blocked By: T4, T10, T3
References:
src/components/dm/Open5eReference.astro(новый)src/lib/open5e/client.ts— API клиентsrc/components/GeneratorCard.astro— паттерн карточки
Acceptance Criteria:
- Поиск "goblin" отображает гоблинов
- Фильтр по CR работает
- Карточка деталей открывается по клику
- Пагинация переключает страницы
QA Scenarios:
Scenario: Search goblins and view details Tool: Playwright Steps: 1. Открыть /dm/ 2. Перейти в таб "Монстры" 3. Ввести "goblin" в поиск 4. Кликнуть на первый результат Expected Result: Открывается карточка с HP, AC, действиями Evidence: .sisyphus/evidence/t11-open5e-details.png Scenario: Filter by CR Tool: Playwright Steps: 1. Выбрать фильтр CR: 1/4 2. Проверить, что все результаты имеют CR 1/4 Expected Result: Только существа с CR 1/4 Evidence: .sisyphus/evidence/t11-open5e-filter.pngCommit: YES
- Message:
feat(dm): add open5e search ui - Files:
src/components/dm/Open5eReference.astro,tests/open5e-ui.test.ts
- Создать
-
T12. Notes Component
What to do:
- Создать
src/components/dm/NotesPanel.astro - Текстовая область для заметок
- Автосохранение в localStorage (debounce 500ms)
- Индикатор "Сохранено"
- Кнопка "Очистить"
- Несколько заметок? (MVP: одна большая заметка)
- TDD: тесты на localStorage persistence
Must NOT do:
- Не сохранять в PostgreSQL (MVP scope)
- Не добавлять rich text/Markdown (MVP: plain text)
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Простой клиентский компонент
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T14
- Blocked By: T4, T3
References:
src/lib/client/clipboard.ts— паттерны клиентских утилитsrc/components/ResultBox.astro— паттерн панели
Acceptance Criteria:
- Текст сохраняется в localStorage
- После refresh текст восстанавливается
- Индикатор "Сохранено" появляется через 500ms
QA Scenarios:
Scenario: Notes persist across refresh Tool: Playwright Steps: 1. Открыть /dm/ 2. Ввести "Тестовая заметка" в поле 3. Подождать 1 секунду 4. Refresh страницы Expected Result: Текст "Тестовая заметка" остался Evidence: .sisyphus/evidence/t12-notes-persist.png Scenario: Clear button empties notes Tool: Playwright Steps: 1. Ввести текст 2. Кликнуть "Очистить" 3. Проверить localStorage Expected Result: localStorage пустой Evidence: .sisyphus/evidence/t12-notes-clear.pngCommit: YES
- Message:
feat(dm): add notes panel with localstorage - Files:
src/components/dm/NotesPanel.astro,tests/notes.test.ts
- Создать
-
T13. Auth UI (Login / Logout / Profile)
What to do:
- Создать
src/components/dm/AuthPanel.astro - Кнопки "Войти через VK" и "Войти через Yandex"
- После входа: аватар + имя + кнопка "Выйти"
- Получение данных пользователя из Astro.locals.user
- Показывать гостевое состояние для неавторизованных
- TDD: тесты на отображение состояний
Must NOT do:
- Не показывать email/чувствительные данные
- Не добавлять регистрацию по email (только OAuth)
Recommended Agent Profile:
- Category:
visual-engineering - Skills: [
/frontend-ui-ux] - Reason: UI компонент аутентификации
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 2
- Blocks: T14
- Blocked By: T6, T7, T4
References:
src/components/LanguageSwitcher.astro— паттерн верхней панелиsrc/layouts/BaseLayout.astro— интеграция в layout
Acceptance Criteria:
- Неавторизованный видит кнопки входа
- Авторизованный видет аватар и имя
- Клик "Выйти" очищает сессию
QA Scenarios:
Scenario: Guest sees login buttons Tool: Playwright Steps: 1. Открыть /dm/ в инкогнито 2. Проверить наличие "Войти через VK" Expected Result: Кнопки входа видны Evidence: .sisyphus/evidence/t13-guest-view.png Scenario: Logout clears session Tool: Playwright Steps: 1. Авторизоваться (mock сессия) 2. Кликнуть "Выйти" 3. Проверить cookies Expected Result: Cookie auth очищен, показывается гостевое состояние Evidence: .sisyphus/evidence/t13-logout.pngCommit: YES
- Message:
feat(dm): add auth ui panel - Files:
src/components/dm/AuthPanel.astro,tests/auth-ui.test.ts
- Создать
-
T14. DM Dashboard Layout + Page
What to do:
- Создать
src/layouts/DmLayout.astro:- Наследует BaseLayout (SEO, analytics)
- Оранжевая тема (подключает dm-theme.css)
- Хедер с логотипом DM Dashboard + AuthPanel
- Основной слот для контента
- Футер с ссылками
- Создать
src/pages/dm/index.astro:- Использует DmLayout
- Отображает все инструменты: DiceRoller, InitiativeTracker, Open5eReference, NotesPanel
- Табы или секции для переключения между инструментами
- RU i18n через
src/i18n/dm-translations.ts
- Добавить
src/i18n/dm-translations.tsсо всеми строками DM Dashboard
Must NOT do:
- Не менять существующие layouts (BaseLayout, GeneratorLayout)
- Не добавлять sidebar или сложную навигацию (MVP: простая страница)
Recommended Agent Profile:
- Category:
deep - Skills: [
/frontend-ui-ux] - Reason: Интеграция всех компонентов в единый layout
Parallelization:
- Can Run In Parallel: NO (зависит от многих задач)
- Parallel Group: Wave 3
- Blocks: T15, T16, T17
- Blocked By: T4, T6, T7, T8, T9, T10, T11, T12, T13
References:
src/layouts/GeneratorLayout.astro— паттерн обёрткиsrc/layouts/BaseLayout.astro— базовый layoutsrc/pages/generators/numbers.astro— паттерн страницы
Acceptance Criteria:
/dm/открывается без ошибок- Все 4 инструмента отображаются
- AuthPanel показывает правильное состояние
- Оранжевая тема применена
- RU переводы работают
QA Scenarios:
Scenario: DM Dashboard loads all tools Tool: Playwright Steps: 1. Открыть http://localhost:4321/dm/ 2. Сделать скриншот 3. Проверить наличие: Кубики, Инициатива, Справочник, Заметки Expected Result: Все 4 секции видны, оформление оранжевое Evidence: .sisyphus/evidence/t14-dashboard-full.png Scenario: Auth state reflected Tool: Playwright Steps: 1. Открыть /dm/ в инкогнито 2. Проверить "Войти через VK" 3. Авторизоваться (mock) 4. Проверить имя пользователя Expected Result: После входа показывается имя и аватар Evidence: .sisyphus/evidence/t14-auth-state.pngCommit: YES
- Message:
feat(dm): integrate dashboard layout + page - Files:
src/layouts/DmLayout.astro,src/pages/dm/index.astro,src/i18n/dm-translations.ts
- Создать
-
T15. Navigation + Routing
What to do:
- Добавить ссылку на DM Dashboard в главное меню (LanguageSwitcher или отдельная кнопка)
- Создать
src/pages/dm/dice.astro— отдельная страница кубиков (опционально) - Создать
src/pages/dm/initiative.astro— отдельная страница инициативы (опционально) - Создать
src/pages/dm/reference.astro— отдельная страница справочника (опционально) - Создать
src/pages/dm/notes.astro— отдельная страница заметок (опционально) - Или: сделать навигацию по якорям на главной странице
#dice,#initiative,#reference,#notes - Обновить
src/pages/index.astro— добавить карточку DM Dashboard среди генераторов
Must NOT do:
- Не создавать дублирующих маршрутов
- Не ломать существующую навигацию
Recommended Agent Profile:
- Category:
quick - Skills: []
- Reason: Навигация и роутинг
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 3
- Blocks: None
- Blocked By: T14
References:
src/pages/index.astro— главная страница со списком генераторовsrc/components/GeneratorCard.astro— карточка генератора
Acceptance Criteria:
- С главной страницы есть ссылка на /dm/
- С /dm/ можно вернуться на главную
- Навигация между инструментами работает (якоря или табы)
QA Scenarios:
Scenario: Navigation from homepage Tool: Playwright Steps: 1. Открыть / 2. Кликнуть "DM Dashboard" 3. Проверить URL Expected Result: URL = /dm/ Evidence: .sisyphus/evidence/t15-nav-home-to-dm.pngCommit: YES
- Message:
feat(dm): add navigation and routing - Files:
src/pages/dm/*.astro,src/pages/index.astro
-
T16. Build Verification + CI Update
What to do:
- Обновить
.github/workflows/deploy.yml:- Добавить шаг запуска PostgreSQL (docker-compose)
- Добавить миграции перед деплоем
- Обновить rsync для Node.js приложения (или перейти на docker deploy)
- Проверить
npm run build— нет ошибок - Проверить
npm run test— все тесты проходят - Проверить
npm run lint— нет ошибок - Добавить health-check endpoint
/api/health - Обновить
docker-compose.ymlдля production
Must NOT do:
- Не удалять существующий деплой основного сайта
- Не коммитить secrets в CI
Recommended Agent Profile:
- Category:
unspecified-high - Skills: []
- Reason: CI/CD, деплой
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 3
- Blocks: None
- Blocked By: T1, T14
References:
.github/workflows/deploy.yml— текущий workflowdocker-compose.yml— Docker конфигурацияDockerfile— обновлённый образ
Acceptance Criteria:
npm run build— SUCCESSnpm run test— все тесты PASSnpm run lint— нет ошибок- Docker compose запускает app + postgres
- CI workflow проходит
QA Scenarios:
Scenario: Full build succeeds Tool: Bash Steps: 1. npm run build 2. npm run test 3. npm run lint Expected Result: Все команды завершаются с кодом 0 Evidence: .sisyphus/evidence/t16-build.log Scenario: Docker compose health check Tool: Bash Steps: 1. docker compose up -d 2. curl -s http://localhost:4321/api/health Expected Result: {"status":"ok"} Evidence: .sisyphus/evidence/t16-health.jsonCommit: YES
- Message:
ci(dm): update build, tests, and deployment - Files:
.github/workflows/deploy.yml,docker-compose.yml,src/pages/api/health.ts
- Обновить
-
T17. Final Styling Polish
What to do:
- Проверить responsive design (mobile, tablet, desktop)
- Проверить accessibility (focus-visible, aria-labels)
- Оптимизировать шрифты и spacing
- Проверить консистентность оранжевой темы
- Добавить hover/active состояния для интерактивных элементов
- Проверить тёмную тему (контрастность)
- TDD: визуальные регрессионные тесты (скриншоты)
Must NOT do:
- Не менять функционал
- Не добавлять новые фичи
Recommended Agent Profile:
- Category:
visual-engineering - Skills: [
/frontend-ui-ux] - Reason: UI полировка
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 3
- Blocks: None
- Blocked By: T14, T15
References:
src/styles/dm-theme.css— текущая тема- Tailwind CSS docs: responsive design, accessibility
Acceptance Criteria:
- Mobile: все элементы помещаются на экране 375px
- Desktop: адекватные отступы и размеры
- Focus-visible работает на всех интерактивных элементах
- Контрастность текста ≥ 4.5:1
QA Scenarios:
Scenario: Responsive design Tool: Playwright Steps: 1. Открыть /dm/ в viewport 375x667 2. Сделать скриншот 3. Открыть /dm/ в viewport 1920x1080 4. Сделать скриншот Expected Result: Оба скриншота показывают удобочитаемый интерфейс Evidence: .sisyphus/evidence/t17-responsive-mobile.png, t17-responsive-desktop.pngCommit: YES
- Message:
style(dm): final polish and responsive design - Files:
src/styles/dm-theme.css,src/components/dm/*.astro
Final Verification Wave
4 review agents run in PARALLEL. ALL must APPROVE. Present consolidated results to user and get explicit "okay" before completing.
-
F1. Plan Compliance Audit —
oracleRead the plan end-to-end. For each "Must Have": verify implementation exists. For each "Must NOT Have": search codebase for forbidden patterns. Check evidence files exist. Output:Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT -
F2. Code Quality Review —
unspecified-highRuntsc --noEmit+npm run lint+npm run test. Review changed files for AI slop patterns. Output:Build [PASS/FAIL] | Lint [PASS/FAIL] | Tests [N pass/N fail] | VERDICT -
F3. Real Manual QA —
unspecified-high(+playwrightskill) Execute EVERY QA scenario from EVERY task. Test cross-task integration. Capture evidence. Output:Scenarios [N/N pass] | Integration [N/N] | VERDICT -
F4. Scope Fidelity Check —
deepFor each task: read "What to do", read actual diff. Verify 1:1. Check "Must NOT do" compliance. Output:Tasks [N/N compliant] | Contamination [CLEAN/N issues] | VERDICT
Plan Reviews
Metis Review
- Status: COMPLETED
- Findings: Core Objective разделён на MVP и Product Vision; Scope IN/OUT определены; противоречия задокументированы.
Oracle Verification Phase 1
- Status: PASS
- Verdict: CHECK 5/5 PASS | GO
Oracle Verification Phase 2
- Status: PASS
- Verdict: CHECK 6/6 PASS | GO
Momus Review
- Status: OKAY
- Verdict: План хорошо структурирован, все ссылки валидны, каждая задача имеет конкретную точку входа, чёткие критерии приёмки и исполняемые QA-сценарии.
Oracle Verification Phase 3
- Status: PASS (after fixes)
- Verdict: CHECK 5/5 PASS | GO
Commit Strategy
- T1-T5:
chore(dm): setup hybrid astro + docker + db + tests + theme - T6-T7:
feat(auth): implement oauth + jwt sessions - T8-T13:
feat(dm): add dice, initiative, open5e, notes, auth ui - T14-T17:
feat(dm): integrate dashboard layout + navigation + polish - F1-F4:
chore(dm): final verification and fixes
Success Criteria
Verification Commands
# Build
npm run build
# Tests
npm run test
# Lint
npm run lint
# Docker
docker compose up -d
# OAuth callback routes exist
curl -s http://localhost:4321/api/auth/callback/vk -w "%{http_code}"
curl -s http://localhost:4321/api/auth/callback/yandex -w "%{http_code}"
# DM Dashboard page loads
curl -s http://localhost:4321/dm/ | grep -q "DM Dashboard"
# Database migrations
docker compose exec postgres psql -U dmuser -d dmdashboard -c "\dt"
Final Checklist
- All "Must Have" present
- All "Must NOT Have" absent
- All tests pass
- Build succeeds
- Docker compose запускается
- OAuth callbacks отвечают
- DM Dashboard страница доступна
- Таблицы в PostgreSQL созданы