1d6d54ab9f60619c52c09763c18c65dfacadd104
Add filtered map API, creamy-caprice-style toolbar (dates, layers, search), Yandex ru tiles, and store Telegram session in MapMil/data instead of mounting SocialParser. Co-authored-by: Cursor <cursoragent@cursor.com>
MapMil Platform (ЦП → ЦА → ПИ)
Единая платформа: ЦА (аналитика и карта) + ЦП (парсинг Telegram).
Архитектура
flowchart LR
CA[ЦА Analytics Center]
CP[ЦП Parsing Center]
PI[ПИ External Consumers]
CA -->|jobs via Redis| CP
CP -->|POST /internal/ingest| CA
CA -->|GET /api/v1/events| PI
| Центр | Контейнеры | Назначение |
|---|---|---|
| ЦА | ca-db, ca-api, ca-frontend |
PostgreSQL, ingest API, карта, distribution API |
| ЦП | cp-workers |
Парсинг Telegram (centers/parsing/workers) |
| Общее | redis |
Очередь заданий ЦА → ЦП |
Структура monorepo
MapMil/
├── centers/
│ ├── analytics/
│ │ ├── api/ # CA backend (FastAPI + PostgreSQL)
│ │ └── frontend/ # CA admin UI (Vue + Leaflet)
│ └── parsing/
│ └── workers/ # CP workers (Telethon)
├── contracts/ # Shared schemas (ingest, jobs)
├── data/ # telegram.session (локально, не в git)
├── docker-compose.yml
└── .env # TELEGRAM_API_ID, TELEGRAM_API_HASH, …
Быстрый старт
- Создайте
.envиз примера и укажите ключи Telegram:
cp .env.example .env
# отредактируйте TELEGRAM_API_ID и TELEGRAM_API_HASH
- Положите сессию Telegram в
data/telegram.session(файл Telethon SQLite). Если мигрируете со старого SocialParser:
cp ../SocialParser/data/telegram.session data/
- Запуск:
docker compose up --build
- Откройте UI: http://localhost:8080
Admin UI
Веб-интерфейс ЦА доступен по тем же адресу. Навигация в шапке:
| Раздел | Путь | Описание |
|---|---|---|
| Карта | / |
Интерактивная карта событий: навигация по датам (flatpickr), пресеты периода, фильтры региона/темы/источника, подложки Яндекс/OSM/Topo/ESRI, линейка, полноэкранный режим, центрирование по координатам и городам, поиск населённых пунктов (Nominatim). CRUD для ручных объектов (ПКМ). Поддерживает ?eventId= |
| Парсеры | /parsers |
Создание заданий Telegram-парсинга, таблица статусов с автообновлением (5 с), повтор failed-заданий |
| События | /events |
Фильтрация, пагинация, просмотр деталей, ссылка «На карте» для событий с координатами |
| Аналитика | /analytics |
KPI-карточки, график динамики ingest за 30 дней, топ населённых пунктов и регионов |
| ПИ | /consumers |
CRUD подписчиков distribution API, ротация ключей, тест среза через /api/v1/events |
Сохранение Telegram-сессии
Важно: существующий файл сессии не удаляется и не пересоздаётся.
- Локально:
data/telegram.session(SQLite Telethon, в.gitignore) - В Docker
cp-workers: каталог./dataмонтируется как/data(read-write) - Путь в контейнере:
/data/telegram.session - Переменные из
.env:TELEGRAM_API_ID,TELEGRAM_API_HASH,TELEGRAM_SESSION_PATH=/data/telegram.session
Файл сессии и .env не коммитятся.
API
Карта
| Метод | Путь | Описание |
|---|---|---|
| GET | /api/health |
Health check |
| GET | /api/map/objects |
Объекты на карте с данными события; фильтры: date_from, date_to, on_date, region, topic, source_type, search, event_id |
| GET | /api/map/filters |
Справочники для фильтров: regions, topics, source_types, available_dates, date_bounds |
| GET | /api/objects |
Объекты (legacy, без фильтров события) |
| POST | /api/objects |
Создать объект вручную |
Инструменты карты (UI)
- Даты: кнопки ❮❮/❮/❯/❯❯, календарь flatpickr, пресеты периода (1 неделя — 1 год / день)
- Фильтры: регион, тема, источник (из
/api/map/filters) - Подложки: Яндекс Карты / Спутник (ru_RU), OpenStreetMap, OpenTopoMap, ESRI Satellite
- Инструменты: линейка (PolylineMeasure), полноэкранный режим, координаты/города, поиск Nominatim
- Точки: маркеры из ingest + popup; ручные объекты — CRUD и drag
- Обновление: polling
/api/map/objectsкаждые 30 с
ЦА Admin
| Метод | Путь | Описание |
|---|---|---|
| POST | /admin/jobs |
Создать задание парсинга (ставится в Redis) |
| GET | /admin/jobs |
Список заданий |
| POST | /admin/jobs/{id}/retry |
Повторить failed-задание |
| GET | /admin/events |
События с фильтрами ({ items, total }) |
| GET | /admin/analytics/summary |
KPI-сводка |
| GET | /admin/analytics/timeline?days= |
Динамика ingest по дням |
| GET | /admin/analytics/top-localities?limit= |
Топ населённых пунктов |
| GET | /admin/analytics/top-regions?limit= |
Топ регионов |
| GET | /admin/consumers |
Список подписчиков ПИ |
| POST | /admin/consumers |
Создать подписчика ПИ |
| PATCH | /admin/consumers/{id} |
Обновить подписчика |
| POST | /admin/consumers/{id}/rotate-key |
Сменить API-ключ |
Пример задания Telegram:
curl -X POST http://localhost:8080/admin/jobs \
-H 'Content-Type: application/json' \
-d '{"source_type":"telegram","source_config":{"channel":"creamy_caprice","limit":50}}'
ЦП → ЦА (internal)
| Метод | Путь | Описание |
|---|---|---|
| POST | /internal/ingest |
Приём batch событий (заголовок X-Internal-Token) |
ПИ Distribution API
| Метод | Путь | Описание |
|---|---|---|
| GET | /api/v1/events |
События с фильтром по API-ключу |
Тестовый consumer test-pi создаётся при старте с ключом из TEST_PI_API_KEY (по умолчанию test-pi-api-key-change-me):
curl http://localhost:8080/api/v1/events \
-H 'Authorization: Bearer test-pi-api-key-change-me'
Поток данных
- Аналитик создаёт задание:
POST /admin/jobs ca-apiставит задание в Redis (cp:jobs)cp-workersзабирает задание, парсит Telegram через существующую сессию- Результаты отправляются в
POST /internal/ingest - События с координатами автоматически появляются на карте как
MapObject - Внешние ПИ получают отфильтрованный срез через
/api/v1/events
Миграция EventRecord → Event
| SocialParser | CA Event |
|---|---|
event |
description / title |
date (dd.mm.yy) |
event_date |
geolocation |
latitude, longitude |
locality |
locality, region |
source_url |
source_url |
| — | source_type = "telegram" |
Остановка
docker compose down
Данные PostgreSQL сохраняются в volume pgdata.
Legacy
Старые каталоги backend/ и frontend/ в корне оставлены для справки; активная разработка — в centers/.
Languages
Vue
46.5%
Python
38.2%
TypeScript
10.6%
CSS
3.7%
HTML
0.5%
Other
0.5%