Files
healthlog/docs/plan.md
T
av 5e2385ba6e добавлены документация проекта и каркас разработки
- README, CLAUDE.md, docs: назначение и границы, архитектура, конвенции, план
- docs/local-research.md — 36 находок по формату Health Auto Export, снятых на
  живых данных; документация приложения местами расходится с тем, что оно шлёт
- Taskfile, .golangci.yml, самодокументируемый config.example.toml
2026-08-01 12:37:03 +03:00

80 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План
Живой документ: шаги отмечаем по мере готовности, отложенное копится внизу.
## Ближайшая цель
Минимальное ядро, которое принимает и сохраняет пакет. Проверяем его
**локально**: сервис поднят на рабочей машине, телефон шлёт на её IP по
локальной сети. Ни деплоя, ни домена, ни TLS для этого не нужно — они
понадобятся, когда сервис поедет на rivendell (шаг 8).
Это шаги 12.
## Шаги
- [x] **1. Каркас.** `Taskfile.yml`, `.golangci.yml`, `CLAUDE.md`, TOML-конфиг
с валидацией на старте, логгер, подкоманда `serve` с `/healthz`.
- [x] **2. Приём без разбора.** `POST /api/v1/ingest`: лимит тела, gzip,
запись тела в архив, строка в `delivery`. Разбора ещё нет.
**подключаем телефон по локальной сети**
- [ ] **3. Разбор и хранилище.** Миграции, часовые объекты метрик
(`bucket`, ключ `метрика + слой + час`) + `workout`/`record` по своим
`id`, вывод слоя из выравнивания меток, канонизация с округлением чисел
и хеш содержимого, слияние точек в объект, два формата дат,
`healthlog reindex`.
- [ ] **4. Read API.** Каталог метрик со слоями и диапазонами, точки с
пагинацией и выбором слоя (сборка из часовых объектов), тренировки,
записи.
- [ ] **5. Самоописание.** Каталог разрезов + выведенные из данных схемы
содержимого со статистикой + статичная схема контракта API.
- [ ] **6. `healthlog import`.** Заливка полной истории кусками по годам.
- [ ] **7. Наблюдаемость.** `/stats`: последняя доставка, счётчики, тишина.
- [ ] **8. Деплой.** `Dockerfile`, сборка образа локально, доставка на
rivendell, конфиг Caddy, поддомен, токены.
Порядок неслучаен. После шага 2 автоматизация в Health Auto Export включена и
копит настоящие пакеты в сыром архиве. Документация формата HAE скудная,
поэтому разбор на шаге 3 пишем по реальным данным, а не по догадкам — и
заодно видим фактический объём и характер потока.
## Отложено
- ~~Отсев идентичных тел доставок по `sha256`.~~ **Вычеркнуто:** находка 2
показала, что порядок ключей в JSON нестабилен, поэтому два пакета с одними
и теми же данными почти никогда не совпадают побайтно — хеш тела не
сработает. Дедупликация возможна только по канонизированному содержимому,
а это и делает хеш часового объекта. Отдельная механика не нужна.
- **Ретеншен сырого архива** (`storage.raw_retention`, 14 дней) — удаление
старых тел. Пока архив не подчищается; включить после того, как разбор
устоится, иначе страховка исчезнет раньше, чем перестанет быть нужна.
- **Порог `sealed`** — с какого возраста час считается запечатанным. Ставим по
факту: сначала пишем `WARN` на изменение старых объектов и смотрим, какая
глубина досчёта встречается в жизни (наблюдалось до 22 минут, находка 10).
- **Алерт «данных нет N часов».** Тихо сломавшаяся автоматизация — главный
эксплуатационный риск коллектора. В v1 факт виден в `/stats`; активное
уведомление добавим после.
- **Аннотации к схемам** — человеческие описания метрик поверх выведенных
схем, либо рукописный каталог. Выбор зависит от того, насколько стабильным
окажется формат; меняться он может только с обновлением Health Auto Export,
а это отслеживается.
- **Схема тренировок** — глубину вывода определим по факту, когда увидим,
как приходят маршруты.
- **Пометка локализованных полей в схемах.** `context`, `value` и подобные
приходят на языке телефона и изменятся при смене языка iOS — клиентам не
стоит завязываться на конкретные строки
([local-research.md](local-research.md), находка 8).
- **Вторая автоматизация без группировки** для `sleep_analysis` и
`heart_rate_variability` — минутная группировка съедает фазы сна и
межударные интервалы ценой ~130 точек в сутки (находка 6).
- **Переход на более грубый нижний слой.** Посекундный слой стоит ~730 МБ в
год против ~20 МБ у минутного. Когда решим, что мелкая подробность не нужна,
достаточно выключить несуммированную автоматизацию — старые данные останутся
в своих слоях, переписывать ничего не придётся. Обратный путь тоже есть:
ручной экспорт из Apple Health + `healthlog import` восстанавливает нижний
слой.
- **NDJSON-поток** для больших выборок из read API.
- **Слой агрегаций** поверх сырья (суточные/недельные срезы).
- **Разворачивание маршрутов тренировок** в отдельную таблицу — если появится
клиент, которому мало отдачи тренировки одним пакетом.