Add CP→CA→PI platform foundation on MapMil monorepo.

Unify parsing workers, analytics API with PostgreSQL, map UI, and PI distribution into centers/ with Docker Compose.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-30 11:43:27 +03:00
co-authored by Cursor
commit 9dfe713668
88 changed files with 6587 additions and 0 deletions
+153
View File
@@ -0,0 +1,153 @@
# 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. Откройте карту: [http://localhost:8080](http://localhost:8080)
## Сохранение Telegram-сессии
**Важно:** существующий файл сессии **не удаляется и не пересоздаётся**.
- Оригинал: `SocialParser/data/telegram.session`
- В репозитории MapMil: `data/telegram.session` — симлинк для локальной разработки
- В Docker `cp-workers`: файл монтируется напрямую как `../SocialParser/data/telegram.session:/data/telegram.session:ro`
- Путь в контейнере: `/data/telegram.session`
- Переменные из `.env`: `TELEGRAM_API_ID`, `TELEGRAM_API_HASH`, `TELEGRAM_SESSION_PATH=/data/telegram.session`
> Симлинк не работает внутри Docker — compose монтирует исходный файл из SocialParser.
Файл сессии и `.env` добавлены в `.gitignore` и не коммитятся.
## API
### Карта (совместимость MapMil)
| Метод | Путь | Описание |
|-------|------|----------|
| GET | `/api/health` | Health check |
| GET | `/api/objects` | Объекты на карте (включая события с координатами) |
| POST | `/api/objects` | Создать объект вручную |
### ЦА Admin
| Метод | Путь | Описание |
|-------|------|----------|
| POST | `/admin/jobs` | Создать задание парсинга (ставится в Redis) |
| GET | `/admin/jobs` | Список заданий |
| GET | `/admin/events` | Все события |
| POST | `/admin/consumers` | Создать подписчика ПИ |
Пример задания 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/`.