Files
MapMil/README.md
T
gitrusprusandCursor 2c16bc0b56 Add CA admin UI and extend admin API for the unified platform.
Deliver parsers, events, analytics, and PI management in Vue; fix Telegram session mount and map navigation to events by eventId.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 14:40:59 +03:00

174 lines
7.2 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.
# 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/`.