02. Руководство school_admin
Аудитория. Администратор одной школы. Отвечает за преподавателей, каталог курсов, биллинг школы и мониторинг обучения.
Что видит и что делает
- Видит только свою школу (RLS).
- Управляет преподавателями (назначение роли
teacher). - Видит все курсы своей школы (черновики + опубликованные).
- Покупает пакеты / оплачивает счета за свою школу.
- Смотрит аналитику прохождения курсов (/analytics).
- Смотрит LLM-costs школы.
Чего не делает:
- Не редактирует курсы чужих школ.
- Не создаёт новых школ.
- Не видит чужих платежей / студентов других школ.
Доступ
Учётка в dev:school_admin@local / change_me_locally (демо-школа, id a7e42330-b775-4041-a57b-9e0ee9ea7ed9).
Фронт: http://127.0.0.1:3500/login.
Главные страницы
| URL | Что там |
|---|---|
/dashboard |
Обзор школы, видимые школы (1), методик, ссылка на разделы |
/courses |
Каталог курсов школы (published + drafts) |
/courses/[id] |
Просмотр последней версии курса |
/courses/[id]/edit |
Редактор курса (автосейв в course_drafts) |
/courses/[id]/v/[N] |
Историческая версия курса (read-only) |
/billing |
Оплата / выбор провайдера |
/billing/success, /billing/cancel |
Возврат от провайдера |
/analytics |
Completion rate + самые трудные блоки (по course_id) |
/demo/media |
Демонстрация генерации изображений/аудио/видео |
Типовые сценарии
1. Выдать/отозвать роль teacher
UI для этого сейчас нет. Единственные пути:
- Пересоздать dev-учётки —
.venv/bin/python -m scripts.bootstrapсоздаётdemo-school+admin@local,school_admin@local,teacher@local,student@local. - Руками в БД (для выдачи роли реальному пользователю):
INSERT INTO user_memberships (user_id, school_id, role_code) VALUES ('<user-uuid>', '<your-school-uuid>', 'teacher'); -- Отозвать DELETE FROM user_memberships WHERE user_id = '<user-uuid>' AND school_id = '<your-school-uuid>' AND role_code = 'teacher';
Web-форма / email-приглашения — в roadmap (Phase 6).
2. Купить пакет занятий (биллинг, demo-режим)
/billing→ выбор провайдера из списка (stripe / vipps / paypal / mock).- Жмёшь Pay → переход на
/billing/mock-checkout(эмулятор hosted-page). - Три кнопки: Pay / Fail / Cancel → каждая шлёт webhook на
/billing/webhooks/{provider}. - При успехе — редирект на
/billing/success. При отмене —/billing/cancel.
Webhook идемпотентен: повторная доставка вернёт {status:"duplicate", ack:true} и не создаст второй payment_event.
3. Посмотреть аналитику курса
/dashboard→ ссылка «Course completion + hardest blocks».- На
/analyticsвбитьcourse_id(как он записан вpublished_courses.course_id) → «Показать». - Получаешь 2 карточки:
- Сводка — всего событий, учеников, прохождений, попыток, ошибок, completion_rate.
- Самые трудные блоки — топ-10 блоков по fail_rate (
ORDER BY fails/attempts DESC). Блоки с fail_rate ≥ 50% помечаются баннеромrework.
Под капотом:
POST /learner/events (записывает события от студента)
GET /learner/analytics/{course_id} (агрегация, доступ только school_admin / teacher / platform_admin)
Никакие имена студентов в аналитике не раскрываются — только счётчики.
4. Посмотреть LLM-затраты школы
/dashboard → «LLM cost (last 30 days)» → компонент CostReport.
Фильтр по school_id применяется автоматически благодаря RLS (таблица llm_cost_entries).
5. Клонировать курс внутри школы
curl -X POST "http://127.0.0.1:55400/courses/<src_course_id>/copy" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"new_course_id":"clone-001","new_title":"Клон курса"}'
Ответ 201 при успехе, 409 если new_course_id уже занят, 404 если исходник не найден в вашей школе, 422 если новый id совпадает с исходным или пустой.
Полная семантика deep_copy — см. docs/PROJECT_MANIFEST.md §14.
6. Откатиться к предыдущей версии курса
Каждая публикация создаёт новую строку в published_courses с инкрементом version. Перейти на историческую версию можно по URL /courses/[id]/v/[N] — это read-only view.
Если нужно сделать N снова «активной» — опубликовать её ещё раз через редактор / скрипт (обычно teacher).
Что контролировать ежедневно
- Cost-дашборд — чтобы генерация курса не прожгла бюджет.
- /analytics по ключевым курсам — если у блока fail_rate > 50%, дать teacher'у задачу на переработку (или настроить AdaptiveSupplementer).
- Temporal UI (http://127.0.0.1:55480) — убедиться что workflow-публикации не зависли.
- Биллинг — статус активной подписки / баланса.
Чего НЕ нужно делать
- Не пытаться через UI редактировать чужие школы — RLS не даст, но и попытка бессмысленна.
- Не коммитить
.env.local. - Не передавать пароль
change_me_locallyникому — это dev-значение. На проде у каждого своя учётка с настоящим паролем.
Ссылки
- Студенческий взгляд: 04-student.md
- Работа teacher'а: 03-teacher.md
- API для интеграций: 07-api-reference.md