chore(plan): admin-redesign 6-phase plan

PLAN.md + 6 subplans + CONTEXT.md

Strategy: Incremental | Mode: Automated | Execution: Orchestrator

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-16 21:47:55 +03:00
parent bd7a9dbee2
commit 76e376ee04
8 changed files with 831 additions and 0 deletions
@@ -0,0 +1,151 @@
# Phase 2: Split admin.html → per-section modules
**Status:** ⬜ Not Started
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** frontend
## Objective
Разделить монолит `admin.js` (3500L) на per-section модули в `frontend/js/admin/sections/*.js`. После фазы `admin.js` становится оркестратором (~500-800L): он только подключает router, инициализирует общие виджеты (notif, sidebar) и делегирует загрузку section-данных в соответствующий модуль.
## Tasks
- [ ] Создать `frontend/js/admin/sections/` директорию
- [ ] Определить единый паттерн модуля:
```js
// js/admin/sections/<name>.js
(function () {
'use strict';
let inited = false;
const ctx = { user: null, isAdmin: false }; // прокидываем из admin.js
async function load() { /* существующий loadX код */ }
window.AdminSections = window.AdminSections || {};
window.AdminSections.<name> = {
init: async (sharedCtx) => {
Object.assign(ctx, sharedCtx);
if (inited) return; inited = true; await load();
},
reload: load,
};
})();
```
- [ ] Извлечь 13 секций (в порядке риска — от меньшего к большему):
- [ ] `stats.js` — `loadStats` + связанные функции (small, ~50L)
- [ ] `sublog.js` — submission log (medium)
- [ ] `sims.js`, `games.js`, `tpl.js` — admin-only (small каждая)
- [ ] `subjects.js` — настройка доступных тестов
- [ ] `permissions.js`
- [ ] `shop.js` — items + purchases + award coins
- [ ] `gam.js` — gamification stats + award xp
- [ ] `assignments.js`
- [ ] `tests.js`
- [ ] `questions.js` — самая большая, ~800L (включая Q-modal)
- [ ] `users.js` — users-table + pagination + user-panel (overlay остаётся!)
- [ ] `sessions.js` — sessions-table + session detail
- [ ] Модифицировать `admin.js`:
- Удалить функции, перенесённые в sections
- Заменить inline вызовы (`loadUsers()` → `AdminSections.users.init(ctx)`)
- Добавить генератор route→section маппинга:
```js
const ROUTE_TO_SECTION = {
stats: 'stats', users: 'users', sessions: 'sessions',
questions: 'questions', tests: 'tests', assignments: 'assignments',
subjects: 'subjects', permissions: 'permissions',
shop: 'shop', gam: 'gam', tpl: 'tpl', sims: 'sims', games: 'games', sublog: 'sublog',
};
AdminRouter.on('change', ({ route }) => {
const sec = ROUTE_TO_SECTION[route];
if (sec && AdminSections[sec]) AdminSections[sec].init(sharedCtx);
});
```
- [ ] Все 13 `<script>` тегов добавить в `admin.html` (после router.js, перед admin.js)
- [ ] Глобальные функции, которые используются из onclick HTML, остаются доступными через `window.X`:
- `changeRole`, `openUserPanel`, `goAddQuestion`, `confirmDeleteUser`, etc.
- Каждый section module экспортирует свои onclick-handler'ы через `window.X = X` или через делегацию из admin.js
- [ ] Удалить per-tab `*Inited` флаги из admin.js — они переехали внутрь section modules
## Files to Modify/Create
- `frontend/js/admin/sections/stats.js` — новый
- `frontend/js/admin/sections/users.js` — новый, ~400-500L
- `frontend/js/admin/sections/sessions.js` — новый
- `frontend/js/admin/sections/questions.js` — новый, ~800L
- `frontend/js/admin/sections/tests.js` — новый
- `frontend/js/admin/sections/assignments.js` — новый
- `frontend/js/admin/sections/subjects.js` — новый
- `frontend/js/admin/sections/permissions.js` — новый
- `frontend/js/admin/sections/shop.js` — новый
- `frontend/js/admin/sections/gam.js` — новый
- `frontend/js/admin/sections/tpl.js` — новый
- `frontend/js/admin/sections/sims.js` — новый
- `frontend/js/admin/sections/games.js` — новый
- `frontend/js/admin/sections/sublog.js` — новый
- `frontend/js/admin/admin.js` — сильно ужать (с 3500L до ~500-800L)
- `frontend/admin.html` — добавить 13 `<script>` тегов
## Acceptance Criteria
- `admin.js` ≤ 800L (от 3500L)
- Каждый section-файл ≤ 900L (questions.js самый большой)
- Все 13 табов работают идентично текущему поведению (no regressions)
- Cross-tab handlers (`goAddQuestion`, `confirmDelete*`) работают
- Lazy-load работает: при первом открытии tab делается fetch, при повторном — нет
- F5 на любом `#X` корректно ленево-грузит секцию (через router из Phase 1)
- Browser back/forward работают
- Никаких console errors в Devtools
## Notes
### Стратегия извлечения
Один section за раз, мелкими безопасными шагами:
1. Скопировать функции `loadX, openXModal, deleteX, ...` в новый файл sections/<name>.js, обернуть в IIFE
2. Экспортировать через `window.AdminSections.X`
3. Подключить `<script>` в admin.html
4. В admin.js заменить вызовы (`loadX()` → `AdminSections.X.init(ctx)`)
5. Удалить дубликаты в admin.js
6. Тест: открыть tab — работает?
7. Перейти к следующей секции
### Что НЕ переезжает в sections
- `LS.initPage()` + auth check — остаётся в admin.js
- `switchTab` (helper) — остаётся
- `pctClass`, `fmtDate`, `fmtTime` — общие утилиты, остаются (или переезжают в `admin/_shared.js`)
- Sidebar / notif init — остаётся
- Router setup — остаётся
### Глобальные функции из onclick
Сейчас многие функции вызываются из HTML onclick (`onclick="openUserPanel(...)"`). Чтобы не переписывать HTML на этой фазе, в каждом section module экспортируем нужные функции через `window.X = X` внутри IIFE. Phase 5/6 могут заменить onclick на event delegation, но Phase 2 этого не делает (incremental).
### Тестирование каждой секции
После каждой выделенной секции:
- Открыть `/admin` → переключиться на этот tab → данные загрузились
- Все кнопки/модалки секции работают
- Cross-tab navigation (если есть) работает
- F5 на `#<route>` корректно открывает tab
Если регрессия — откатить эту итерацию, разобраться, починить.
### Совет implementer'у
Если фаза становится огромной — можно сделать несколько коммитов внутри phase branch. Это inscope. Не нужно делать один гигантский коммит на 14 файлов.
## Review Checklist
- [ ] Все 13 секций имеют одинаковую структуру (init/reload)
- [ ] admin.js ≤ 800L, в нём нет дублирования с sections
- [ ] Все window.X экспорты есть для onclick handlers
- [ ] Lazy-init работает (профилировка: при открытии tab → fetch, при повторе → нет)
- [ ] F5 на каждом из 13 routes восстанавливает секцию
- [ ] Build passes: server starts, no errors
## Handoff to Next Phase
<!-- Implementer должен зафиксировать:
- Структуру window.AdminSections.X.init/reload (точное API)
- Какие функции стали глобальными через window.X (список)
- Как Phase 3 (dashboard) должна добавиться: новый sections/overview.js + new route в ROUTE_TO_SECTION
- Где живут shared утилиты (pctClass, fmtDate, esc) — admin.js или вынесены в _shared.js -->