Files
healthlog/README.md
T
av 2070ef438c docs: план обрезан до порядка, отложенное переехало в беклог
- содержимое шагов не перечисляется: список работ жил в плане и в беклоге и расходился с каждой закрытой задачей
- десять пунктов «Отложено» заведены задачами [idea]; два из них (ретеншен, алерт) уже были в беклоге — в плане лежал дубль
- обоснование порядка расписано по шагам: это единственное, чего беклог структурно не вмещает
2026-08-02 07:02:07 +03:00

121 lines
7.4 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.
# healthlog
Коллектор данных Apple Health. Принимает выгрузки из
[Health Auto Export](https://www.healthyapps.dev/apps/health-auto-export/),
складывает их в единое хранилище и отдаёт другим моим проектам через HTTP API.
## Зачем
Данные о здоровье и тренировках нужны сразу нескольким приложениям: анализ
здоровья, разбор тренировок, мотиватор по активности. Интегрировать каждое
из них с Health Auto Export по отдельности — значит в каждом писать приём,
дедупликацию и хранение заново.
healthlog делает это один раз. Телефон шлёт данные в него, все остальные
проекты берут данные из него.
## Границы
Это **хранилище**, а не аналитика. healthlog принимает, дедуплицирует,
хранит и отдаёт. Он не переименовывает поля Apple и не интерпретирует
значения — этим занимается тот, кто данные читает.
Одну уступку хранилище всё же делает: оно умеет свести метрику к запрошенной
сетке («шаги по дням»). Иначе каждый из клиентов повторял бы одну и ту же
логику выбора слоя, а ошибиться в ней легко — просуммировать не тот разрез и
получить завышение втрое. Но род свёртки не проставлен вручную, а **измерен**
сверкой слоёв между собой; где измерить не вышло, свёртка не предлагается
вовсе.
Источников два: Health Auto Export (куплен, пожизненный премиум) — ежедневный
поток, и родной экспорт Apple Health раз в 2–3 месяца — источник истины для
нижнего слоя.
## Как устроено
```
экспорт Apple ────────┐ снапшот всей истории, раз в 2–3 месяца
iPhone ──HTTPS POST──► healthlog ──► журнал доставок (.json.gz)
│ │
│ └── события поверх снапшота
SQLite ──┬──► HTTP read API ──► мои приложения
(свёртка по │
журналу) └──► MCP ───────────► агенты
```
Приём сначала кладёт тело запроса на диск как есть и только потом разбирает.
Значит, ошибка в разборе не теряет данные: состояние всегда пересобирается
свёрткой `import(экспорт) + replay(доставки)`. Отсюда и главный инвариант —
точки хранятся дословно: журнал, из которого что-то выброшено, перестаёт быть
журналом.
Подробности — [docs/architecture.md](docs/architecture.md).
## Состояние
В разработке. Готовы каркас и приём, большая часть разбора: сервис принимает
пакеты, складывает их в сырой архив и **разбирает метрики в часовые объекты**
— с выводом слоя из данных, канонизацией содержимого и слиянием точек по
полноте. Секции, которых разбор пока не покрывает (`workouts`, `stateOfMind`
половина потока), принимаются, хранятся и честно помечаются как неразобранные.
Чего ещё нет: пересборки хранилища из архива (`reindex`), каталога метрик с
измеренным родом агрегации и **read API** — данные наружу пока не отдаются
никак. План в [docs/plan.md](docs/plan.md).
Разведка формата закончена: 50 находок на живом потоке, половина расходится с
документацией Health Auto Export — [docs/local-research.md](docs/local-research.md).
## Команды
```
healthlog serve приём + read API + MCP
healthlog import родной экспорт Apple Health (в планах)
healthlog reindex пересборка хранилища из архива (в планах)
healthlog healthcheck проверка живости для docker HEALTHCHECK
```
## Локальный запуск
Конфиг необязателен — без него берутся умолчания (`:8080`, `./healthlog.db`,
`./raw`). Для своих значений скопируй `config.example.toml` в `config.toml`.
```
task run
```
Проверка:
```
curl localhost:8080/healthz
curl -X POST localhost:8080/api/v1/ingest -d '{"data":{"metrics":[]}}'
```
### Подключение телефона по локальной сети
Сервис слушает все интерфейсы (`addr = ":8080"`), так что телефон в той же
сети достучится по IP машины. В Health Auto Export заводится одна
автоматизация: **REST API**, формат **JSON**, минимальная гранулярность
(«Summarize Data» выключен), URL вида `http://<ip-машины>:8080/api/v1/ingest`.
Если `auth.write_tokens` пуст, проверка токена выключена — для доверенной
локальной сети этого достаточно, сервис пишет об этом `write auth disabled`
на старте. Для доступа снаружи понадобится и токен, и TLS — это шаг «Деплой».
## Документация
- [docs/passport.md](docs/passport.md) — цель проекта, типовые сценарии
работы, референсы: чужие проекты, у которых смотрим решения, прежде чем
придумывать своё
- [docs/architecture.md](docs/architecture.md) — устройство, схема данных, API, принятые решения
- [docs/conventions.md](docs/conventions.md) — как пишем код
- [docs/plan.md](docs/plan.md) — шаги и обоснование их порядка
- [docs/backlog](docs/backlog/README.md) — что брать следующим, включая
отложенные идеи
- [docs/local-research.md](docs/local-research.md) — что показал реальный поток
Health Auto Export; источник истины по формату, документация приложения
местами расходится с тем, что оно шлёт