# MapMil Platform (ЦП → ЦА → ПИ) Единая платформа на базе MapMil (ЦА — аналитика) и SocialParser (ЦП — парсинг). ## Архитектура ```mermaid 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 (код из SocialParser) | | **Общее** | `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 (symlink → SocialParser) ├── docker-compose.yml └── .env # TELEGRAM_* из SocialParser ``` ## Быстрый старт 1. Скопируйте `.env` из SocialParser (или создайте из `.env.example`): ```bash cp ../SocialParser/.env .env ``` 2. Убедитесь, что сессия Telegram доступна: ```bash ls -la data/telegram.session # symlink → ../SocialParser/data/telegram.session ``` 3. Запуск: ```bash docker compose up --build ``` 4. Откройте UI: [http://localhost:8080](http://localhost:8080) ## Admin UI Веб-интерфейс ЦА доступен по тем же адресу. Навигация в шапке: | Раздел | Путь | Описание | |--------|------|----------| | **Карта** | `/` | Интерактивная карта с объектами, таймлайном и CRUD. Поддерживает `?eventId=` для перехода к событию | | **Парсеры** | `/parsers` | Создание заданий Telegram-парсинга, таблица статусов с автообновлением (5 с), повтор failed-заданий | | **События** | `/events` | Фильтрация, пагинация, просмотр деталей, ссылка «На карте» для событий с координатами | | **Аналитика** | `/analytics` | KPI-карточки, график динамики ingest за 30 дней, топ населённых пунктов и регионов | | **ПИ** | `/consumers` | CRUD подписчиков distribution API, ротация ключей, тест среза через `/api/v1/events` | ## Сохранение Telegram-сессии **Важно:** существующий файл сессии **не удаляется и не пересоздаётся**. - Оригинал: `SocialParser/data/telegram.session` - В репозитории MapMil: `data/telegram.session` — симлинк для локальной разработки - В Docker `cp-workers`: каталог `../SocialParser/data` монтируется как `/data` (read-write; Telethon обновляет SQLite-сессию) - Путь в контейнере: `/data/telegram.session` - Переменные из `.env`: `TELEGRAM_API_ID`, `TELEGRAM_API_HASH`, `TELEGRAM_SESSION_PATH=/data/telegram.session` > Симлинк не работает внутри Docker — compose монтирует каталог `SocialParser/data` целиком. Файл сессии и `.env` добавлены в `.gitignore` и не коммитятся. ## API ### Карта (совместимость MapMil) | Метод | Путь | Описание | |-------|------|----------| | GET | `/api/health` | Health check | | GET | `/api/objects` | Объекты на карте (включая события с координатами) | | POST | `/api/objects` | Создать объект вручную | ### ЦА 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: ```bash 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`): ```bash curl http://localhost:8080/api/v1/events \ -H 'Authorization: Bearer test-pi-api-key-change-me' ``` ## Поток данных 1. Аналитик создаёт задание: `POST /admin/jobs` 2. `ca-api` ставит задание в Redis (`cp:jobs`) 3. `cp-workers` забирает задание, парсит Telegram через существующую сессию 4. Результаты отправляются в `POST /internal/ingest` 5. События с координатами автоматически появляются на карте как `MapObject` 6. Внешние ПИ получают отфильтрованный срез через `/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"` | ## Остановка ```bash docker compose down ``` Данные PostgreSQL сохраняются в volume `pgdata`. ## Legacy Старые каталоги `backend/` и `frontend/` в корне оставлены для справки; активная разработка — в `centers/`.