feat: валидация payload.user_id и ретеншн (ttl_seconds, RETENTION_DAYS)
- Routing: _user_recipient() — субьектом user-канала принимается непустая
  строка/число; массив/объект/bool → skipped-доставка с причиной (аудит),
  а не «delivered в никуда».
- ttl_seconds стал действующим: воркер не маршрутизирует истёкшее событие
  (новый статус expired, миграция 0005 пересоздаёт ck_event_status).
- Beat-задача synapse.expire_events (ежечасно): удаление событий с
  истёкшим ttl и старше RETENTION_DAYS (дефолт 30; 0 — окно отключено),
  deliveries каскадом.
- ui.js: бейдж expired; docs/05: «Ретеншн», формат значения payload.user_id.

Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 96e9b32 commit 9fee6f44e6d4631607200389984c214f277af52f
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 6 hours ago
Showing 7 changed files
View
alembic/versions/20261003_0005_event_expired.py 0 → 100644
View
app/config.py
View
app/models/events.py
View
app/worker/celery_app.py
View
app/worker/tasks.py
View
docs/05-ingestion-api.md
View
frontend/src/ui.js