Skip to content

About

Self-hosted portal for analyzing orienteering races: georeferenced maps, GPX tracks, race protocols, split analysis and an AI coach

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Orienteering Portal

License: MIT

English · Русская версия ниже

A self-hosted web portal for analyzing orienteering races: georeferenced map scans, GPS tracks (GPX), official race protocols and split-by-split analysis, with an optional AI coach for each problem split.

It was built to answer one question after every start: where exactly was the time lost, why, and does the same problem repeat?

Split analysis: map with the track, pace chart and AI coach chat

What it does

  • Map georeferencing. Upload a scanned orienteering map, match at least three points against a base map (affine transform, least squares), then click start, controls and finish to get a digital course.
  • Track to splits. Upload a GPX file; it is cut into splits at the point where the track passes closest to each control, with manual correction of the markers for GPS drift.
  • Race protocols. Import results by URL from orgeo.ru, sportident.online and o-site.spb.ru-based sites (including SportOrg PDF protocols) and compare every split with the whole group.
  • Ideal Leader. For each split, the best time actually posted by any participant; problem splits are highlighted against it.
  • Single-split view. Map section, actual track, straight line between controls and a pace chart for one split, plus a reason for the loss that you pick from an editable list.
  • Statistics. A dashboard of recurring causes, splits still worth reviewing, and positions across starts.
  • AI coach (optional). For one split, the portal sends the map image with the track and the numeric parameters to the Claude Code CLI and shows a short analysis. Replies are in Russian.

Good to know before you try it

  • It is a personal/family tool: the user list is fixed in code and login is a simple user pick without a password. It is not a public service.
  • The interface and the AI coach replies are in Russian; the supported protocol sources are Russian orienteering sites.
  • Status: active development.

Quick start

pip install -e ".[dev]"
cp .env.example .env
uvicorn portal.main:app --reload --port 8002

Python 3.12+ is required. On the first start the app creates its directories, the SQLite schema and default data. Tests: python -m pytest tests/ -v. Configuration, architecture and deployment are described in the sections below and in docs/ (in Russian).

Stack: FastAPI, Jinja2 with vanilla JS/CSS (no bundler), SQLite via aiosqlite, pytest; Docker/Coolify for deployment.

The code was written by a coding agent; the author set the tasks and checked every result on real races. The story behind the project: From a Paper Map to a Problem Split.


На русском

Локальный веб-портал для разбора тренировок и стартов по спортивному ориентированию: сканы карт с привязкой к координатам, GPS-треки, протоколы соревнований и разбор сплитов, вплоть до диалога с персональным AI-тренером по каждому отдельному этапу дистанции.

Проект личный (family/staff use, без публичной регистрации): список пользователей фиксирован в коде, вход — простой выбор пользователя без пароля. Технологический стек и структура сознательно повторяют соседний проект running-portal.

Статус: активная разработка. Разделы, для которых не нашлось материала в коде, отмечены как «требует уточнения».

Что делает портал

  1. Тренировки. Мастер создания тренировки: скан карты, геопривязка по контрольным точкам, GPS-трек (GPX), тип дистанции и заметки.
  2. Плеер трека. Проигрывание движения по карте с изменяемой скоростью, перемоткой, отображением текущего темпа и обрезкой трека.
  3. Протоколы соревнований. Импорт результатов по ссылке на orgeo.ru, sportident.online или сайты на движке o-site.spb.ru (включая PDF-протоколы SportOrg), сохранение и сравнение со всеми участниками группы.
  4. Разбор сплитов. Автоматический расчёт сплитов по КП, подсветка проблемных этапов, сравнение с лидером/идеальными сплитами, дашборд «дороже всего по времени».
  5. AI-тренер. Диалог по конкретному сплиту: в модель уходит снимок карты с треком и КП плюс параметры этапа, ответ — короткий разбор на русском для юной спортсменки.
  6. Опрос причин ошибок и аналитика. Для каждого проблемного сплита можно сохранить причину потери времени (справочник причин настраивается в /settings/error-reasons); дашборд считает частоту причин, тренд по стартам и позиции в протоколах по датам.

Полный неформальный список возможностей (глазами владельца) — в ВОЗМОЖНОСТИ_ПОРТАЛА.md.

Скриншоты

Дашборд

Дашборд: проблемные сплиты, причины ошибок, позиции на соревнованиях

Плеер тренировки

Плеер тренировки: карта, трек, таблица сплитов и график темпа

Разбор сплита с AI-тренером

Разбор сплита: карта сплита с треком, график темпа и чат с AI-тренером справа

Технологический стек

  • Backend: Python 3.12+, FastAPI, uvicorn (ASGI-сервер).
  • Шаблоны/frontend: Jinja2 (templates/) + ванильный JS/CSS (static/), без сборки (no bundler); графики — Chart.js (CDN).
  • База данных: SQLite через aiosqlite, схема и миграции — вручную в коде (portal/db.py), без ORM и без Alembic.
  • Геопривязка карт: собственная реализация affine-преобразования (наименьшие квадраты) — portal/services/georef.py.
  • Парсинг GPX: xml.etree.ElementTree (без внешней GPX-библиотеки).
  • Парсинг протоколов соревнований: ручные regex/HTML-парсеры под шесть форматов источников + pypdf для PDF-протоколов — portal/services/race_protocol.py.
  • AI-тренер: не прямой вызов Anthropic API, а системный вызов установленного в контейнер claude (Claude Code CLI) как subprocess — подробности в docs/ai-coach.md.
  • Тесты: pytest + pytest-asyncio + httpx (FastAPI TestClient), ~109 тестов в tests/.
  • Деплой: Docker (multi-stage: Node-слой для Claude CLI + Python 3.12-slim), рассчитан на Coolify — см. docs/deployment.md.

Быстрый старт

Требования

  • Python 3.12+
  • (опционально, для AI-тренера) установленный и авторизованный Claude Code CLI

Установка

pip install -e ".[dev]"
cp .env.example .env

Конфигурация (.env)

Переменная Назначение По умолчанию (dev)
ORIENTEERING_PORTAL_DB_PATH Путь к файлу SQLite ./data/orienteering.sqlite3
ORIENTEERING_PORTAL_UPLOAD_DIR Каталог загрузок (карты импорта, снимки сплитов) ./data/uploads
ORIENTEERING_PORTAL_MAP_DIR Каталог карт (зарезервирован, отдельно от maps-таблицы) ./data/maps
ORIENTEERING_PORTAL_AUTO_LOGIN Имя пользователя, под которым логинить автоматически без cookie (пусто — обязателен вход через /login) не задано
CLAUDE_CLI_PATH Путь к бинарю claude для AI-тренера /home/<user>/.local/bin/claude (dev, зависит от машины разработчика) / /usr/local/bin/claude (Docker)
ANTHROPIC_API_KEY Резервная авторизация Claude CLI (продакшн-пример) не задано
HOME В продакшн-примере переопределяется, чтобы Claude CLI искал креды в /data/orienteering/.claude —
PORT Порт uvicorn в контейнере 8000

.env.production.example — шаблон для деплоя (Coolify), с портом 8000 и путями /data/orienteering/... вместо ./data/....

Запуск

uvicorn portal.main:app --reload --port 8002

При старте (lifespan в portal/main.py) приложение само создаёт нужные каталоги, инициализирует схему SQLite и сеет данные по умолчанию: трёх пользователей (двух обычных и одного админа — в коде под настоящими именами владельца портала, здесь обезличено) и справочник причин ошибок из 9 пунктов — см. docs/data-model.md.

Тесты

python -m pytest tests/ -v

Структура репозитория

portal/
  main.py                 # FastAPI-приложение, middleware авторизации, дашборд
  auth.py                 # модель пользователя, работа с cookie-сессией
  db.py                   # схема SQLite, миграции, вся работа с данными (~2100 строк)
  infrastructure/
    config.py             # чтение переменных окружения
    media.py              # построение публичных /uploads-URL для картинок карт
  routers/
    auth.py                # /login, /logout
    imports.py              # мастер создания/редактирования тренировки, геопривязка карт
    race_results.py         # импорт/просмотр протоколов, сравнение сплитов
    georef.py                # /api/georef/fit — расчёт affine-преобразования
    ai.py                    # /api/split-analysis/chat — AI-тренер
    settings.py              # управление пользователями и причинами ошибок (admin)
  services/
    georef.py               # least-squares affine-геопривязка
    gpx.py                   # парсинг GPX-трека
    race_protocol.py          # парсинг протоколов (6 форматов) + запрос по сети
    race_grabber.py           # поиск стартов участника на o-site.spb.ru
templates/                 # Jinja2-страницы и partials
static/                    # JS/CSS без сборки, по одному файлу на экран/фичу
data/                       # SQLite-файл, загруженные карты/треки/снимки (в .gitignore, кроме .example-конфигов)
tests/                      # pytest, ~109 тестов
docs/                        # архитектура, модель данных, сценарии, интеграции, деплой
Dockerfile                  # multi-stage сборка (Node/Claude CLI + Python)

Подробности — в docs/:

Лицензия

MIT

About

Self-hosted portal for analyzing orienteering races: georeferenced maps, GPX tracks, race protocols, split analysis and an AI coach

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages