--- description: MapMil platform architecture, boundaries, and agent workflow alwaysApply: true --- # MapMil Platform Monorepo: **ЦА** (analytics) + **ЦП** (parsing) + **contracts** + **ПИ** (distribution API). ## Data flow ``` CA admin → Redis cp:jobs:{family} → CP adapter → POST /internal/ingest → CA DB → map / ПИ ``` | Center | Path | Role | |--------|------|------| | ЦА API | `centers/analytics/api/` | FastAPI, ingest, scheduler, admin | | ЦА UI | `centers/analytics/frontend/` | Vue + Leaflet admin | | ЦП | `centers/parsing/workers/` | Adapter registry, batch + Telegram listener | | Contracts | `contracts/` | Shared schemas — change first | ## Hard boundaries - ЦП **never** touches CA database — only `POST /internal/ingest` and `PATCH /internal/jobs/{id}` - `source_type` events must match adapter type; stable `source_url` required (CA dedup) - `source_config` validated via `contracts/sources.py` on admin CRUD - Telegram session: `data/telegram.session` — local only, **never commit** - `.env` and secrets — **never commit** ## CP adapter model Each `source_type` implements `SourceAdapter.run(job_id, source_config, *, ctx) -> tuple[list[dict], str | None]`. Output dicts are `IngestEventItem`-shaped. Routing: `contracts/queues.py` (`SOURCE_FAMILY` → `cp:jobs:{telegram|web|nlp}`). Worker images: `cp-workers` (telegram), `cp-workers-web` (crawl4ai), `cp-workers-nlp` (viina). ## Agent workflow 1. **Contracts first** if data shape or routing changes 2. **One zone per task** — do not mix contracts + UI + infra in one unfocused change 3. **Follow existing adapters** — copy `viina.py` or `telegram.py`, not greenfield 4. **Do not touch** Telegram listener unless explicitly asked 5. **Verify**: `docker compose config`, then targeted service rebuild Docs: `README.md`, `centers/parsing/ARCHITECTURE.md`, `AGENTS.md`. For new `source_type`: use skill `add-parser-adapter`.