- Открыть портал (
/) — без сохранённого состояния Mi Fitness синхронизация будет падать с ошибкой авторизации. - Ввести email и пароль Xiaomi через
POST /api/auth/login(portal/routers/auth.py:41). - При обычном логине сервер сразу получает
passTokenиserviceTokenи сохраняет их вMI_FITNESS_STATE_PATH(auth.json). - Если Xiaomi требует капчу, push-подтверждение в приложении или
двухшаговую проверку —
loginвернёт{"success": false, "action": "captcha" | "verification" | "step2", "verification_url": ...}(format_auth_error,portal/routers/auth.py:70); подтверждение нужно пройти вне портала (поverification_url) и повторить логин.
- Вручную — кнопка «↻ Синхронизировать» в навигации
(
POST /api/sync), либо автоматически по расписанию (AUTO_SYNC_INTERVAL_HOURS,MORNING_SYNC_TIME). - Портал запрашивает у Mi Fitness активности с даты последней сохранённой пробежки (при пустой БД — за последние 90 дней), отфильтровывает не-бег и дистанции короче 300 м.
- Каждая активность сохраняется (
INSERT OR REPLACE) — новые учитываются вadded, уже существующие — вupdated. - Если
serviceToken/passTokenистёк (Xiaomi отвечает401), портал один раз пробует обновить сессию: сначала «тихим» рефрешемpassToken, а еслиMI_FITNESS_PASSWORDзадан в.env— ещё и повторным логином по паролю (refresh_auth_state,portal/sync.py:170). Без пароля в.envистёкшую сессию нужно обновлять вручную через/api/auth/login. - Если за синхронизацию добавилась ровно одна новая пробежка — её детали (GPS-трек, посекундные пульс/темп) подгружаются сразу же. Если добавилось несколько — детали остаются недогруженными до ручного действия.
- Если после синхронизации что-то реально изменилось (
added > 0илиupdated > 0) и ошибок не было — портал сразу пересчитывает «ответ на сегодня».
/ показывает (каждая карточка включается/выключается в /settings):
- Ответ на сегодня — последняя сохранённая рекомендация AI-тренера, с кнопками «промпт» (посмотреть использованный текст) и «обновить» (пересчитать без ожидания синхронизации).
- Ключевые метрики, Прогресс формы (Efficiency Factor по
неделям + scatter «темп vs пульс» в модалке), Цель на месяц с
прогрессом и статусом (
on_track/slightly_behind/behind), Дистанции последних 20 пробежек, Последние пробежки — постраничная таблица.
Кнопка «Загрузить все детали» на дашборде вызывает
POST /api/activities/details/load-all: находит все активности без
сохранённых деталей и последовательно догружает их одну за другой
(portal/routers/activities.py:215). Долгая операция — выполняется
синхронно в теле запроса, без прогресс-бара на бэкенде (только счётчик
loaded/failed в ответе).
/activity/{activity_id}:
- Показывает сохранённые метрики и (если детали ещё не загружены)
кнопку «Загрузить детали», вызывающую
GET /api/activities/{id}/detail. - График «Пульс и скорость по времени» переключается на «по
дистанции» (
chart-mode-toggle), плюс полоска Efficiency Factor по ходу тренировки. - Пульсовые зоны — по длительностям
hrm_*_duration. - Карточка «AI тренер» — кнопка «Получить анализ» запускает потоковый (SSE) разбор конкретной пробежки; готовый разбор кэшируется и переоткрывается мгновенно при следующем визите, кнопка «Пересчитать анализ» форсирует новый запрос.
GET /api/goals/monthly— текущая цель (если задана) и прогресс.GET /api/goals/monthly/suggest— просит AI (или, при сбое, эвристику по истории) предложитьkm_goal/runs_goalвместе с консервативным и амбициозным вариантом.POST /api/goals/monthly— сохраняет выбранную (или отредактированную вручную) цель на конкретныйyear/month.
/health — список записей с периодом действия (started_at,
опционально ended_at) и свободным текстовым описанием. Записи можно
добавлять, редактировать и удалять
(POST/PUT/DELETE /api/health-states...). Последние три активные/недавние
записи автоматически попадают во все три AI-промпта — отдельно
подтверждать это на каждом экране не нужно.
Когда AI-функции начинают падать с истёкшей OAuth-сессией CLI,
дашборд показывает ошибку с кнопкой «Войти в Claude», ведущей на
/claude-auth:
- Через логин-URL —
POST /api/claude-auth/login-urlзапускаетclaude auth loginкак subprocess, вычитывает из его stdout OAuth-ссылку и возвращаетsession_id+login_url; после перехода по ссылке и получения кода —POST /api/claude-auth/login-codeдописывает код в stdin того же процесса и завершает вход. - Вручную —
POST /api/claude-authс готовымclaudeAiOauthтокеном напрямую перезаписывает~/.claude/.credentials.json(запасной путь, если первый способ недоступен).
Подробности потоков и рисков — в docs/ai-assistant.md.
/settings — редактирование двух из трёх prompt-шаблонов (для
«ответа на сегодня» и для разбора пробежки; шаблон предложения цели на
месяц не редактируется через UI), целевой пульсовой зоны для графика
детальной страницы и видимости карточек дашборда. Сохранение —
POST /api/settings, применяется к следующей генерации промпта, уже
сгенерированные и закэшированные ответы не пересчитываются
автоматически.