Events «По душе» · Dating «По любви» · для CPO
Конфиденциально · материалы для CPO

Платформа: Events «По душе» + Dating «По любви» — материалы для CPO

2 продуктовых бэка + общий identity · инфраструктура, роадмап, ситуативы, безопасность

Инфраструктура и тех-стек · спецификация и роадмап · быстрая обработка ситуативов · админ-таксономия событий.

Краткое резюме

Платформа из двух бизнесово раздельных продуктов, связанных глубокой интеграцией: Events («По душе» — офлайн-события) и Dating («По любви» — знакомства, существующее приложение plbvi.ru). Архитектура — 2 продуктовых бэкенда (events-backend, dating-backend; у каждого своя БД и домен, разводятся независимо) + общий слой платформенных сервисов, главный из которых — Identity/SSO (единый user_id). Это позволяет легко «развести» продукты потом, но при этом делать cross-app-интеграцию (статус «открыт для знакомств», переход между приложениями, «4 из 20 на событии открыты и подходят»).

Над бэками — 4 клиента (events/dating × mobile/web) и 1 общая админка-агрегатор. Дорогую инфраструктуру и регулируемое (identity/verification, notifications, media, analytics, moderation, payment-gateway) выносим в общие сервисы; доменную логику и данные держим в каждом продукте раздельно.

Документ покрывает: - §1 Инфраструктура и стек — дейтинг уже в проде на Python (Django+FastAPI, k8s в Yandex Cloud); наследуем стек и инфру, events строим в том же стеке; данные в РФ-облаке (152-ФЗ). - §2 Спецификация и роадмап — 2 бэка + общие сервисы + integration layer; фазы по зависимостям (P0→P8). - §3 Ситуативы — быстрое реагирование на инциденты (удаление/блокировка, сбои платежей/интеграций, модерация) через событийную шину и единый журнал; формирование решений. - §4 Админ-таксономия — единый журнал внутренних событий (от регистрации до ошибок). - §5–§6 Качество и безопасность — NFR-цели, пентест, нагрузка, масштабирование.

Дейтинг «По любви» — существующий прод (Python: Django+FastAPI, клиент Flutter, k8s в Yandex Cloud). Его бэкенд и есть dating-backend: мы его принимаем и достраиваем (общий identity, net-new фичи), а не переписываем; интеграция с events — через уже работающую Kafka.


1. ИНФРАСТРУКТУРА И ТЕХНОЛОГИЧЕСКИЙ СТЕК

Важная вводная: дейтинг «По любви» уже работает в проде на зрелом стеке (Python + k8s в Yandex Cloud). Поэтому стек мы не выбираем с нуля — наследуем существующее и достраиваем недостающее. Events — net-new; решение принято: строим его в том же стеке (Python — Django+FastAPI), чтобы переиспользовать инфраструктуру, CI и identity.

1.1 Реальная архитектура «По любви» (как есть, из репозиториев)

Слой Чем реализовано сейчас
Бэкенд (основной) Django 4.2 + DRF + SimpleJWT (django-main-app): auth, профили, matching, survey/«Открывашки», cities, media. Ранжирование подбора — scikit-learn/numpy. Matching вынесен в отдельный деплой. Контент/админка — Wagtail.
Бэкенд (сервисы) FastAPI: fastapi-chat-app (чат, WebSocket + aiokafka), fastapi-verification-app (фото-верификация)
Фоновые задачи Dramatiq (брокер — Redis) + dramatiq-crontab
Данные managed PostgreSQL (psycopg3), Redis + Redis Stack, Kafka (managed), S3 (Yandex Object Storage — медиа + бэкапы). Гео — geopy (расстояния/города, без PostGIS).
Контракты контракт-фёрст: swagger (nikea-swagger, 14 доменов) → кодоген клиентов surfgen (Android/iOS/Flutter)
Клиент Flutter (BLoC, dio/retrofit/fresh, drift-офлайн, in_app_purchase, geolocator, FCM-push, OTP-логин)
Платежи нативные IAP (App Store / Google Play) + подписки
Аналитика/атрибуция Firebase (analytics/crashlytics/messaging/remote-config) + AppMetrica + AppsFlyer (без ClickHouse)
DevOps k8s (Yandex Cloud) + ArgoCD (GitOps) + Helm + Vault (секреты) + Terraform; образы — Surf Nexus (nexus.surfstudio.ru/nikea/*); бэкапы PG/Redis → S3-кронжобы; локалка — minikube

Вывод: инфраструктура, шина (Kafka), хранилища, контракт-фёрст-пайплайн и DevOps-контур — уже есть и в РФ-облаке. Это меняет роадмап: первый шаг — не «строим инфру с нуля», а принимаем существующую (доступы, registry, CI, дампы БД).

1.2 Целевой стек — достраиваем поверх реальности

Для дейтинга стек наследуем. Для events-backend (net-new) решение принято — тот же стек (Python), чтобы переиспользовать инфру/CI/identity и не раскалывать команду. Отдельно — слои, которых сейчас нет и которые надо докупить/построить.

Слой Сейчас (dating) Для events / net-new Решение
Язык / бэкенд Django+DRF, FastAPI то же (Django — CRUD/админка, FastAPI — realtime) наследуем
Контракты / клиент swagger→surfgen, Flutter то же наследуем
Данные PG + Redis + Kafka + S3 те же managed-сервисы наследуем
Шина событий Kafka (есть) Kafka для events↔dating наследуем
Гео geopy + lat/long PostGIS для «события рядом» + GPS-радар (net-new для dating) BUILD на managed PG
Identity / SSO Django auth (phone OTP + JWT) вынести в общий identity с единым user_id BUILD (на базе существующего)
Платежи IAP + подписки ЮKassa для events: билеты, эскроу/сплит, выплаты самозанятым, ФНС-чеки BUY провайдер / BUILD домен
AI-модерация фото/чата только фото-верификация CV/text-модерация UGC (обязательна для сторов) BUY + BUILD правила
Голосовой онбординг Yandex SpeechKit (STT/TTS) + LLM на обезличенном тексте + текстовый фолбэк BUY
Комплаентный скоринг ЕСИА + ФССП-самопроверка + self-upload справок (без госбаз/скрейпинга) BUY провайдеры / BUILD оркестрация
Реестр образов Surf Nexus перенести в cr.yandex заказчика миграция
Админка Wagtail (контент) единая админка-агрегатор над двумя бэками BUILD

1.3 Принципы

  1. РФ-локализация по умолчанию (152-ФЗ). ПДн, фото/голос (биометрия, отдельные согласия) — физически в РФ-облаке. Уже соблюдается: всё в Yandex Cloud.
  2. Наследуем стек, не переписываем. Единый Python-периметр (Django+FastAPI) + контракт-фёрст (swagger→surfgen) + Flutter — как у существующего дейтинга; events в том же стеке. Переписывать рабочий прод на другой язык — риск без выгоды.
  3. Переиспользуем существующую инфру. Kafka, PostgreSQL, Redis, S3, k8s/ArgoCD/Vault — уже в проде. Шина Kafka есть сейчас — это не «фаза V2».
  4. BUY для AI/инфраструктуры — BUILD для доменной логики и ПДн. Покупаем CV/text-модерацию, SpeechKit, LLM, ЕСИА/ФССП, ЮKassa; пишем сами identity, скоринг-оркестрацию, репутацию, эскроу, events-домен, integration layer.
  5. Net-new строим точечно — только то, чего в проде ещё нет (см. §1.2): events-домен, общий identity, GPS-радар, голосовой онбординг, скоринг, ЮKassa-эскроу, единая админка, AI-модерация.

1.4 Что покупаем (BUY) vs пишем сами (BUILD)

Уже есть — наследуем: Python-бэкенд (Django/FastAPI/Dramatiq), managed PG/Redis/Kafka/S3, k8s/ArgoCD/Helm/Vault/Terraform, swagger→surfgen, Flutter-клиент, IAP-платежи, Firebase/AppMetrica/AppsFlyer.

Покупаем (BUY) — net-new: CV/text-модерация (UGC для сторов), Yandex SpeechKit, LLM-API (обезличенный текст), ЕСИА/ФССП/KYC-провайдеры, ЮKassa + ФНС/НПД. Регулируемые внешние системы — пишем только обёртки/комплаенс вокруг.

Пишем сами (BUILD) — наш IP: общий identity/SSO (единый user_id на базе Django-auth), скоринг-оркестрация и тиры доверия, репутация, эскроу/сплит (events), events-домен (RSVP/waitlist/check-in/афиши), GPS-радар и голосовой онбординг (dating net-new), integration layer events↔dating, единая админка.


2. СПЕЦИФИКАЦИЯ + ТАЙМЛАЙН

2.1 Что строим (спецификация скоупа)

Два бизнесово раздельных продукта на общей платформе: Events («По душе» — офлайн-события) и Dating («По любви» — знакомства). У каждого — свой бэкенд со своей БД и доменом (независимый деплой, при необходимости разводятся), сверху — тонкий слой общих платформенных сервисов и integration layer для cross-app-связки. Над всем — 4 клиента и 1 общая админка-агрегатор.

Топология:

Слой Состав Стек
Продуктовые бэки dating-backend (существующий) + events-backend (net-new) — свои БД и домен Django+DRF / FastAPI, PostgreSQL, Redis, Kafka
Общие сервисы identity/SSO, verification, notifications, media, moderation, payment-gateway Python (Django/FastAPI), Kafka, S3 (Yandex Object Storage)
Integration layer cross-API events↔dating + deep-link + кросс-статус на общем identity Kafka + swagger/REST
Клиенты (mobile) dating-mobile (есть), events-mobile (net-new) Flutter (BLoC, dio/retrofit, surfgen)
Веб лендинги/страницы событий для SEO (events) Next.js (или Flutter Web)
Админка 1 общая, агрегатор над двумя бэками (поверх Django/Wagtail-admin) Django/Wagtail + кастом
Контракты swagger (nikea-swagger) → surfgen-кодоген клиентов

Что шарим vs держим в продукте. Логика: общими делаем чистую инфраструктуру, регулируемое (152-ФЗ) и кросс-продуктовое; доменную логику и данные держим раздельно, чтобы продукты дёшево «развести».

Концерн Решение Почему
Identity/SSO + Verification (ЕСИА/ФССП/селфи/KYC) SHARED линчпин интеграции (единый user_id); 152-ФЗ; «верифицирован в одном = в обоих»
Notifications (push/SMS/email) SHARED чистая инфра, дорого дважды
Media (фото/видео, РФ, биометрия) SHARED чистая инфра + 152-ФЗ (биометрия в РФ-контуре)
Analytics / атрибуция (Firebase/AppMetrica/AppsFlyer) SHARED pipeline кросс-продуктовая воронка; server-side события — общий стрим
Moderation (AI-движки + очередь) SHARED, product-scoped обязательна для сторов; модели дорогие — купить раз; правила per-product
Payment-gateway SHARED только шлюз dating: нативные IAP+подписки (как сейчас); events: ЮKassa (билеты, эскроу/сплит, выплаты, ФНС) — в своих бэках
Доменная логика, reputation PER-PRODUCT это и есть продукт; раздельные БД → дёшево развести
Growth / cross-sell per-product; cross-sell через shared identity кросс-промо завязан на единый профиль

Интеграция events↔dating (сценарий)

Продукты раздельные, но внутри каждого — интеграция другого. Ключевой механизм: в Events пользователь ставит статус «открыт для знакомств», и это разворачивает расширенный функционал через cross-API к dating-backend:

  • Подсветка статуса в events-профиле; на событии — «4 из 20 участников открыты для знакомств и подходят под твои критерии» (events-backenddating-backend: кто из этих user_id открыт + matches).
  • Deep-link в «По любви» за полной анкетой / доп.фото / видеокружочками.
  • Фильтры «показывать события/людей с таким же статусом»; рекомендации людей и событий учитывают флаг.
  • Обратно: dating-backendevents-backend — «встречал вживую» / общие посещённые события как сигнал для дейтинга.

Флаг «открыт для знакомств» и базовый кросс-профиль живут на shared identity (читают оба продукта); полная анкета — в dating-backend.

Как это ложится на реальный API «По любви»

Связь events↔dating — через общий identity + Kafka + swagger/REST (тот же контракт-фёрст, что в дейтинге). Сценарии выше опираются на уже существующие домены API «По любви»:

Сценарий интеграции Реальный API дейтинга Направление
«Открыт для знакомств» (флаг) хранится на shared identity, читают оба бэка events ↔ dating
«4 из 20 открыты и подходят» matching (фильтры/пересчёт) + profile/users (мини-карточка) events → dating
Переход за полной анкетой (deep-link) profile (фото/видеокружочки) + survey («Открывашки») events → dating
Действие из контекста события likes (лайк / супер-лайк / записка) + matching events → dating
«Встречал вживую» / общие события сигнал в ранжирование matching dating → events
Сообщества ↔ категории событий community (списки, вступление) dating ↔ events
Чат пост-событийных пар chat (FastAPI WebSocket — переиспользуем, не дублируем) dating ↔ events

Net-new под интеграцию (поверх существующего API): флаг «открытости» на identity, фильтр matching «по событию/участникам», пометка «met-IRL». Всё остальное — matching / likes / chat / community / profile / surveyпереиспользуем как есть.

Продукт Events (events-backend). Платформа офлайн-событий: создание события, RSVP (мгновенно / по одобрению, waitlist), карта+список как главный экран, pre-event чат, geo-fenced check-in, post-event review, парсинг внешних афиш (Timepad/KudaGo) для cold-start.

  • Создание события L1/L2, recurring-серии; RSVP-движок (capacity, waitlist, одобрения).
  • Геопоиск (PostGIS), карта/список, geo-fenced check-in.
  • Pre-event чат, post-event review, репутация явки; парсинг афиш (cold-start).

Продукт Dating (dating-backend). «По любви» (plbvi.ru) — существующее приложение знакомств для серьёзных отношений и семьи («знакомства для души»). Его бэкенд (Django+FastAPI) мы принимаем как dating-backend и достраиваем: подключаем к общему user_id, добавляем net-new фичи. Это не переписывание — перенос данных (дампы из S3 на целевой контур) + аккуратный strangler там, где выносим identity.

Текущие фичи «По любви» (переносим как есть):

  • Селфи-верификация + строгая модерация — «только реальные люди», без фейков.
  • «Открывашки» — ответы на вопросы-открытки для самопрезентации.
  • «Видеокружочки» — короткие видео о себе.
  • Лимит 8 лайков/день; «Записочки» — прямое сообщение тому, кто понравился.
  • Reels от психологов об отношениях; тематические Сообщества.

Что добавляем поверх (новое):

  • GPS-пересечения профилей (фоновый BLE-радар на iOS нереализуем — исключён).
  • События в свайп-ленте + сигнал «пошёл бы / не интересно» (каталог из events-backend по API).
  • Голосовой онбординг — RU-каскад (Yandex SpeechKit + LLM на обезличенном тексте) + текстовый фолбэк.
  • Комплаентный скоринг — ЕСИА + ФССП-самопроверка + self-upload справок (без госбаз судимостей, без скрейпинга соцсетей).
  • AI-модерация фото и чата (обязательна для сторов).

2.2 Фазовый роадмап

Роадмап исходит из того, что дейтинг уже в проде: первые фазы — не «строим с нуля», а принимаем существующую систему и инфру, затем достраиваем net-new и строим events. Фазы — по зависимостям; клиент и интеграция идут внахлёст.

Фаза Длит. Что шипается (результат) Зависимости / риски
P0 — Доступы и приём проекта 2–4 нед Доступы: registry (Nexus→cr.yandex), CI (ветка ci-up), дампы БД (S3, выдаёт resource manager), legacy-данные. Параллельно — внешние процессы: KYC ЮKassa, аккаунты Apple/Google/RuStore, статус ИС в ЕСИА, юр.заключение по ПДн Доступы и внешние процессы не сжимаются — стартовать в неделю 1
P1 — Принять инфру, поднять dating-backend 2–4 нед Существующий dating-backend (Django/FastAPI) развёрнут в целевом контуре: образы в cr.yandex, ArgoCD/Helm/Vault, прогон на стейдж-дампе, зелёный CI Зависит от P0; риск нестыковок секретов/конфигов Vault
P2 — Общий identity 4–6 нед Вынос Django-auth (phone OTP + JWT) в общий identity с единым user_id; cross-app SSO; контракт для events Затрагивает рабочий прод — strangler + обратная совместимость токенов
P3 — Net-new фичи dating 6–8 нед GPS-радар (geolocator уже в клиенте), голосовой онбординг (SpeechKit+LLM+фолбэк), скоринг (ЕСИА/ФССП/справки), AI-модерация (CV/text) Новые внешние интеграции; голос/биометрия — отдельные согласия (152-ФЗ)
P4 — Events-backend (net-new) 6–8 нед events-backend в том же стеке: события L1/L2, RSVP/waitlist/capacity, гео (PostGIS), check-in, афиши (cold-start), эскроу/сплит на ЮKassa ЮKassa блокируется KYC из P0; парсинг афиш — отдельный риск
P5 — Events-клиент (Flutter) + веб 5–7 нед (∥ P4) events-mobile на Flutter (переиспользуем surfgen/компоненты), лендинги событий для SEO Параллелится через контракт-фёрст; карты (Yandex MapKit)
P6 — Integration layer 3–4 нед (∥ P5) events↔dating через Kafka: статус «открыт для знакомств», «4 из 20», deep-link, cross-sell Зависит от P2 (общий identity) + обоих доменов
P7 — Единая админка 3–4 нед Агрегатор над двумя бэками (поверх Django/Wagtail): модерация, пользователи, события, выплаты, жалобы, RBAC+аудит Зависит от moderation/payments; нужна до публичного запуска events
P8 — Compliance / прод / сторы 4–6 нед (∥) Оператор ПДн в РКН, биометрия-согласия, security-hardening (OWASP), релиз events в App Store / Google Play / RuStore Внешние блокеры ревью сторов/юр.процессов не сжимаются; 152-ФЗ

Параллелизм. P5/P6 идут внахлёст с P4, compliance (P8) тянется процессно с P0 — реальный календарь короче суммы длительностей. Ключевое отличие от greenfield: P1–P3 опираются на готовый прод дейтинга, а не на стройку ядра с нуля. Внешние блокеры (KYC ЮKassa, ревью сторов, статус ИС в ЕСИА, доступ к дампам/legacy) ресурсами не сжимаются.


3. Обработка ситуативов: быстрое реагирование и решения

Ситуатив — любое значимое событие или инцидент в системе: от удаления/блокировки аккаунта до сбоя платежа, застрявших в эскроу денег, жалобы или падения внешней интеграции. Цель — не расписать один сценарий до винтика, а иметь единый механизм: быстро поймать → быстро отработать → сформировать решение (авто или человеком).

3.1 Единый механизм

  • Каждый продукт/сервис публикует событие в шину (Kafka, уже в проде) с общим correlation_id.
  • Заинтересованные сервисы реагируют идемпотентно (отмена, возврат, уведомление, скрытие, отзыв доступа).
  • Всё стекается в единый журнал админки (§4) с темой / severity / тегами — оператор видит ситуатив и формирует решение в одном экране; критичное (critical) уходит в алерт.
  • Принцип UX: пользователю никогда не показываем 500/битый экран — ситуатив деградирует в понятное состояние.

3.2 Каталог типовых ситуативов

Ситуатив Как ловим Быстрая отработка (авто) Где решение
Удаление / блокировка аккаунта событие account.* от identity отзыв сессий, скрытие из ленты/поиска, стоп выплат, удаление медиа админка (см. §3.3)
Сбой платежа / фискализации ФНС payment.*.failed ретрай, статус «в обработке», сам платёж не трогаем алерт Finance + админка
Деньги застряли в эскроу (бан организатора) бан + активное платное событие заморозка выплаты, сага возврата/переназначения админка (ручное подтверждение)
Жалоба / AI-флаг модерации moderation.* авто-скрытие явного, очередь для borderline очередь модерации
Фейк / антифрод antifraud.* шадоу-бан, капча, блок устройства антифрод-раздел
Сбой внешней интеграции (афиши/ЕСИА/SpeechKit/ЮKassa) *.integration.failed ретрай/деградация, фолбэк (напр. текстовый онбординг) алерт On-call
Всплеск ошибок / деградация рост error-rate / latency автоскейл, circuit breaker алерт On-call, инцидент-режим

Любой ситуатив — это та же связка «событие → идемпотентная реакция → запись в журнал → решение». Новый добавляется как новая тема/правило, а не как отдельная подсистема.

3.3 Пример: удаление и блокировка аккаунта

Самый «сквозной» ситуатив — показывает механику целиком. Identity-сервис (источник истины аккаунта) публикует account.blocked / account.deleted; оба продуктовых бэка и общие сервисы реагируют идемпотентно:

  • identity — мгновенный отзыв сессий/токенов; media — удаление фото/видео/биометрии; events/dating — скрытие из ленты/поиска, отмена будущих RSVP, разрыв матчей; payments — заморозка выплат, сага по эскроу; analytics — анонимизация (агрегаты сохраняем); admin/audit — след сохраняем всегда.
  • Режимы: блокировка (временно, другим видно «аккаунт недоступен») vs удаление (soft-delete с окном отмены ~30 дней → purge) vs анонимизация.
  • Тяжёлый кейс: деньги в эскроу при бане организатора с предстоящим платным событием — сага: вернуть гостям / переназначить хост, не «потеряв» деньги.
  • Ретеншн: платёжные/ФНС/аудит-данные храним по закону даже после удаления (152-ФЗ: право на удаление vs обязательное хранение).

Все шаги каскада — обычные события в том же журнале (§4), развёрнутые по correlation_id: видно, что отработало штатно.


4. АДМИНКА: таксономия внутренних событий (теги/темы) — от новой регистрации до ошибок

4.0 Назначение и принцип

Команда оперирует двумя продуктами на общей платформе. Если каждый модуль (общие сервисы, events-backend, dating-backend) ведёт свой журнал, оператор поддержки, модератор, антифрод и дежурный инженер смотрят в разные места и не видят причинно-следственных связей. Поэтому в админке заводится единый фид внутренних системных событий — один поток, в котором появляется всё: регистрация, верификация, модерация, платежи, события/дейтинг, гео, рост, комплаенс и ошибки. Каждое событие классифицируется по теме (бизнес-домен) и severity (важность), помечается тегами (пересекающиеся срезы) и связывается с цепочкой через correlation_id.

Бизнес-смысл для CPO: - Один экран на всю систему → поддержка/модерация/антифрод не переключаются между инструментами, время реакции на инцидент падает. - Тема ≠ severity ≠ тег — три независимых оси фильтрации. Тема отвечает на «что за домен», severity — «насколько срочно», тег — «по какому срезу искать» (например biometric, pii, fraud, money). Это даёт точные дашборды и алерты без раздувания числа типов. - RBAC встроен в таксономию: payload с ПДн/биометрией виден не всем (152-ФЗ), а сам факт доступа к чувствительному событию логируется как событие (compliance.audit.access). - Переиспользование, а не новый код: фид строится поверх уже работающей шины (Kafka) и логов/аналитики — отдельная подсистема логирования не нужна.


4.1 Каталог тем (групп) событий

Severity — фиксированная шкала из 4 уровней: info (норма, для аудита/аналитики), warning (требует внимания, не блокирует), error (сбой операции/нарушение правила), critical (угроза деньгам/данным/доступности — порождает алерт).

RBAC-роли: Support-L1 (Support Specialist), Moderator (Support 1-я линия модерации/Community Manager), Antifraud, Finance (payment-focused BE/финоператор), Compliance/DPO (ответственный за ПДн, оператор РКН), Engineer/On-call (Backend/DevOps), Admin (PM/Founder — полный доступ). Принцип least-privilege: чувствительный payload (биометрия, ПДн, платёжные реквизиты) маскируется для ролей, которым он не нужен.

Темы ↦ реальные сервисы-источники. - Auth, Profile, Matching, Likes, Survey, Community, Referral, Citiesdjango-main-app (Django/DRF; ранжирование подбора — scikit-learn). - Chatfastapi-chat-app (FastAPI/WebSocket + Kafka). Verification (селфи)fastapi-verification-app. - Payments: dating — нативные IAP/подписки (payment/subscription); events — ЮKassa (net-new). - Events-домен, GPS-радар, голосовой онбординг, ЕСИА/ФССП-скоринг, AI-модерация — net-new сервисы. - Фоновое (нотификации, обработка видео, ретеншн) → Dramatiq-воркеры.

Auth / Registration

Тема Примеры событий (type) Severity Теги Кто видит Действия из админки
Auth/Registration auth.user.registered (новая рега) info auth, signup, funnel Support-L1, Antifraud, Admin Открыть профиль, привязать к correlation-цепочке
Auth/Registration auth.verification.selfie.passed/failed info / warning auth, verification, biometric, pii Moderator, Compliance, Admin Запросить переснять, эскалация на ручную проверку
Auth/Registration auth.verification.document.passed/failed info / warning auth, verification, pii Moderator, Compliance, Admin Ручная верификация, отклонить
Auth/Registration auth.verification.esia.linked/failed (net-new) info / error auth, verification, esia, pii Compliance, Admin Повторить привязку, пометить как «личность подтверждена»
Auth/Registration auth.login.success info auth, session Support-L1, Antifraud Открыть сессии пользователя
Auth/Registration auth.otp.requested / auth.otp.verified (вход по телефону + OTP) info auth, otp, session Support-L1, Antifraud Разлогинить все сессии, посмотреть попытки OTP
Auth/Registration auth.login.suspicious (новый девайс/гео/невозможная поездка) warning auth, security, antifraud, geo Antifraud, Security, Admin Принудительный 2FA, заморозить сессию, эскалация в Security

Profile / Media

Тема Примеры событий Severity Теги Кто видит Действия
Profile/Media media.photo.uploaded info media, profile Support-L1, Moderator Открыть медиа (с правом просмотра)
Profile/Media media.photo.autoflag (AI-модерация: 18+/насилие/чужое лицо) warning media, moderation, ai, nsfw Moderator, Admin Скрыть фото, отправить в очередь ручной модерации, бан
Profile/Media profile.field.flagged (запрещённый текст в био) warning profile, moderation, ai Moderator Очистить поле, предупреждение пользователю

Moderation

Тема Примеры событий Severity Теги Кто видит Действия
Moderation moderation.complaint.created (жалоба) warning moderation, report, ugc Moderator, Support-L1, Admin Взять в работу, объединить дубликаты
Moderation moderation.ai.flag (флаг чата/контента) warning moderation, ai, chat Moderator Открыть контекст, эскалировать
Moderation moderation.decision.made (решение модератора) info moderation, decision, audit Moderator, Compliance, Admin Просмотр обоснования, апелляция
Moderation moderation.user.banned (бан) error moderation, ban, account, audit Moderator, Admin Разбан, посмотреть каскад (см. §4.4)
Moderation account.blocked / account.deleted (каскад из раздела 3) error / critical moderation, compliance, account, cascade, audit Compliance, Admin Просмотр каскада блокировок/удалений, выгрузка аудита

Payments

Тема Примеры событий Severity Теги Кто видит Действия
Payments payment.iap.succeeded (подписка dating — App Store/Google Play) · payment.yookassa.succeeded (events — net-new) info payments, money, iap, yookassa Finance, Support-L1, Admin Открыть транзакцию/подписку
Payments payment.escrow.held (удержание эскроу) info payments, money, escrow Finance, Admin Просмотр статуса удержания
Payments payment.payout.sent (выплата организатору) info payments, money, payout Finance, Admin Повторить выплату, открыть получателя
Payments payment.refund.processed (возврат) info payments, money, refund Finance, Support-L1 Инициировать/подтвердить возврат
Payments payment.chargeback.received (чарджбек) error payments, money, chargeback, antifraud Finance, Antifraud, Admin Открыть спор, заморозить выплаты по юзеру
Payments payment.provider.error (ошибка ЮKassa) error payments, money, integration, yookassa Finance, Engineer, Admin Ретрай, ручная сверка
Payments payment.fns.receipt.failed (фискализация ФНС/54-ФЗ) critical payments, money, integration, fns, compliance Finance, Compliance, On-call Повторить фискализацию, эскалация (риск 54-ФЗ)

Events (events-backend)

Тема Примеры событий Severity Теги Кто видит Действия
Events events.event.created info events, ugc Support-L1, Moderator Открыть событие, предмодерация
Events events.rsvp.created info events, funnel Support-L1 Открыть участника
Events events.checkin.done (чек-ин на месте) info events, geo, attendance Support-L1 Просмотр гео-подтверждения
Events events.event.cancelled (отмена) warning events, refund-trigger Support-L1, Finance Запустить массовый возврат, уведомить участников
Events events.parser.import.ok/failed (парсер-импорт афиш) info / error events, integration, parser Engineer, Admin Перезапустить импорт, открыть лог источника

Dating (dating-backend)

Тема Примеры событий Severity Теги Кто видит Действия
Dating dating.like.sent / superlike.sent / note.sent (записка) info dating, like Support-L1 Открыть пользователя (ПДн маскируются)
Dating dating.match.created (матч) info dating, match Support-L1 Открыть пару (с маскированием ПДн)
Dating dating.chat.message.sent (чат — FastAPI/Kafka) info dating, chat Support-L1, Moderator Открыть тред по жалобе, эскалация в модерацию
Dating dating.community.joined/left (Сообщества) info dating, community Support-L1 Открыть сообщество и участников
Dating dating.survey.prompt.answeredОткрывашки») info dating, survey Support-L1
Dating dating.subscription.changed (подписка/IAP) info dating, payments, iap Finance, Support-L1 Открыть подписку, статус IAP
Dating dating.user.reported (репорт) warning dating, moderation, report Moderator, Antifraud Взять в модерацию, заблокировать переписку

Geo

Тема Примеры событий Severity Теги Кто видит Действия
Geo geo.crossing.detected (GPS-пересечение) info geo, dating, match Support-L1 Просмотр пересечения (агрегированно)
Geo geo.location.fake (подмена/спуфинг локации) warning geo, antifraud, security Antifraud, Admin Сбросить гео-доверие, пометить юзера

Growth / Referrals

Тема Примеры событий Severity Теги Кто видит Действия
Growth/Referrals growth.invite.sent (инвайт) info growth, referral Growth, Admin Открыть реферальную цепочку
Growth/Referrals growth.points.granted (начисление баллов) info growth, referral, rewards Growth, Finance Откатить начисление
Growth/Referrals growth.promo.fraud (фрод промокодов) warning growth, antifraud, fraud, money Antifraud, Finance, Admin Деактивировать промокод, отозвать баллы

Compliance

Тема Примеры событий Severity Теги Кто видит Действия
Compliance compliance.consent.granted/revoked (согласие на ПДн/биометрию) info compliance, pii, consent, audit Compliance, Admin Просмотр версии согласия, история
Compliance compliance.dsr.export.requested (запрос экспорта данных, 152-ФЗ) warning compliance, pii, dsr, audit Compliance, Admin Сформировать выгрузку, отметить срок
Compliance compliance.dsr.delete.requested (запрос удаления) warning compliance, pii, dsr, cascade, audit Compliance, Admin Запустить каскадное удаление (см. §4.4)
Compliance compliance.audit.access (доступ оператора к ПДн/биометрии) info compliance, pii, audit, rbac Compliance, Admin Просмотр кто/что/когда смотрел

System / Errors

Тема Примеры событий Severity Теги Кто видит Действия
System/Errors system.exception.unhandled (необработанное исключение) error system, error, backend Engineer, On-call, Admin Открыть стек, перейти в Grafana/Loki по correlation_id
System/Errors system.integration.failed (фейл: SpeechKit/FCM/AppMetrica/ЮKassa/ЕСИА/Maps) error system, integration, error Engineer, On-call Ретрай, открыть статус провайдера
System/Errors system.queue.backlog (переполнение очереди/ретраи шины) warning system, queue, kafka Engineer, On-call Открыть лаг консьюмера, масштабировать
System/Errors system.service.degraded (деградация: рост latency/error-rate) critical system, availability, slo On-call, Admin Алерт, открыть дашборд SLO, инцидент-режим

Security / Antifraud

Тема Примеры событий Severity Теги Кто видит Действия
Security/Antifraud security.bruteforce.detected (массовые попытки входа/OTP) warning security, antifraud, auth Antifraud, On-call Включить rate-limit/блок IP, форс-2FA
Security/Antifraud antifraud.bot.detected (поведение бота/масс-регистрация) warning security, antifraud, bot, signup Antifraud, Admin Шадоу-бан, капча, блок устройства
Security/Antifraud security.account.banned (бан антифродом) error security, antifraud, ban, account Antifraud, Admin Разбан, просмотр причин и связанных аккаунтов
Security/Antifraud security.data.breach.suspected (подозрение на утечку ПДн) critical security, pii, breach, compliance Compliance, On-call, Admin Инцидент-режим, уведомление РКН (72 ч по 152-ФЗ)

4.2 Модель данных и источник

Единая структура события (event / audit-log)

{
  "id":             "evt_01J9...",        // ULID, монотонный, сортируемый по времени
  "ts":             "2026-06-25T10:31:02.581Z",
  "theme":          "Payments",            // тема из каталога §4.1 (enum)
  "type":           "payment.fns.receipt.failed", // <module>.<entity>.<action>
  "severity":       "critical",            // info | warning | error | critical
  "actor": {                               // кто инициировал
    "kind": "user|operator|system|integration",
    "id":   "usr_4821", "role": null
  },
  "target": {                              // на кого/что направлено
    "kind": "user|event|payment|profile|...",
    "id":   "pay_99213"
  },
  "tags":           ["payments","money","integration","fns","compliance"],
  "payload":        { /* доменные поля; ПДн/биометрия — отдельный класс, маскируется по RBAC */ },
  "correlation_id": "corr_5f1c...",        // сквозной id цепочки бизнес-операции
  "source":         "dating.fastapi-chat",   // сервис: dating.django-main | dating.fastapi-chat | dating.fastapi-verification | events-backend | shared.identity | dramatiq
  "pii_class":      "biometric|pii|none"   // класс чувствительности → правило маскирования и хранения
}

Соглашения, чтобы таксономия оставалась управляемой: - type = <module>.<entity>.<action> — иерархичен, новые типы добавляются без миграций, фильтр по префиксу (payment.*) работает из коробки. - theme — закрытый enum, привязан к модулю-владельцу. Темы стабильны, типы растут. - tags[] — открытый, но из словаря (pii, biometric, money, fraud, audit, cascade, integration, …). Один тег пересекает темы: money ловит и Payments, и Growth-фрод; pii — и Auth, и Compliance. Это даёт срезы, недоступные через тему. - pii_class управляет двумя вещами: маскированием payload в UI (RBAC) и политикой хранения (см. ниже).

Источники и хранение

Слой Источник Хранилище Зачем
Доменные события Событийная шина Kafka (уже в проде) — модули публикуют доменные события Аналитическая витрина (Postgres-агрегаты + Loki для логов; ClickHouse — опционально при росте объёма) Запросы и агрегаты по теме/тегу/времени
Технические события Структурные логи приложений (JSON) → коллектор (Vector/Loki-pipeline) → нормализация в ту же схему Та же витрина (Postgres/Loki) Единый формат с доменными событиями, общий фид
Критичный аудит Те же события с severity=critical и/или тегом audit/compliance/money/pii Durable-хранилище: PostgreSQL (append-only, WORM-семантика) + бэкап Юридически значимый аудит (152-ФЗ, 54-ФЗ): неизменяемость, длительное хранение, доказуемость

Принцип: витрина — для объёма и аналитики, durable-стор — для доказуемости. Критичные события пишутся в оба (dual-write через шину). Хранение по классам: none/pii info-события — короткий TTL в аналитической витрине; audit/compliance/money — длительное durable-хранение по требованиям регуляторов; биометрические payload не дублируются в фид — событие хранит только факт и ссылку, сами биоданные лежат в защищённом хранилище с отдельным согласием.

correlation_id присваивается в точке входа (регистрация, открытие платежа, создание события) и протягивается через шину по всей цепочке. Именно он связывает «рега → верификация → платёж → ошибка» в один трейс и соединяет фид с логами/метриками в Grafana/Loki (уже в инфре; distributed tracing OTel/Tempo — по мере внедрения).


4.3 UX админки

Лента (основной экран). Реверс-хронологический поток событий. Каждая строка: время · цветной бейдж severity · тема · type · actor → target · теги-чипы · кнопка drill-down. Цветовой код severity: info — нейтральный, warning — янтарный, error — красный, critical — красный с пульсацией + значок алерта.

Фильтры (комбинируются, сохраняются в URL).

Фильтр Значения Сценарий
Тема мультиселект из каталога §4.1 «покажи только Payments + Moderation»
Severity info / warning / error / critical дежурный смотрит только error+critical
Пользователь actor.id / target.id / телефон / email поддержка разбирает жалобу на конкретного юзера
Время пресеты + произвольный диапазон «последний час», «во время инцидента 03:00–03:40»
Тег мультиселект из словаря антифрод: всё с fraud; DPO: всё с pii
correlation_id точный ввод/из drill-down развернуть цепочку одной операции
Источник/модуль общие сервисы, events-backend, dating-backend изоляция продукта

Drill-down в событие. Полная карточка: вся структура §4.2, развёрнутый payload (с маскированием по RBAC), кнопки действий из §4.1 (контекстно по теме), ссылки на профиль/транзакцию/событие и переход в Grafana/Loki по correlation_id.

Drill-down в цепочку (по correlation_id). Таймлайн-вид: все события одной бизнес-операции в хронологии, с переходами между темами и подсветкой, где цепочка «сломалась» (первый error/critical). Это ключевой инструмент разбора инцидентов — видно весь путь от регистрации до сбоя.

Сохранённые фильтры (saved views). Преднастроенные ленты под роли, чтобы не собирать фильтр заново: - Дежурный инженер: severity ≥ error, темы System/Errors + Payments-integration. - Антифрод: тег fraud/antifraud/bot + Security/Antifraud + Geo-fake. - DPO/Compliance: тег pii/consent/dsr/audit + темы Compliance/Moderation-каскад. - Финансы: тема Payments + тег money. - Модерация: Moderation + Profile-autoflag + Dating-report.

Алерты на critical. Любое severity=critical (фискализация ФНС, деградация сервиса, подозрение на утечку, чарджбек-шторм) → мгновенный алерт в Telegram (дежурный чат) и на почту ответственной роли, с дедупликацией и группировкой, чтобы один инцидент не породил сотню сообщений. Алерты конфигурируются по комбинации тема+severity+тег.

Дашборды по темам. Поверх аналитической витрины: динамика событий по темам, доля error/critical, воронка Auth/Registration (рега → селфи → документ → ЕСИА), здоровье платежей (success-rate ЮKassa, фейлы ФНС), очередь модерации, лаги консьюмеров шины. Дашборды и лента используют одни и те же оси (тема/severity/тег) — то, что видно агрегатом, разворачивается в конкретные события одним кликом.


4.4 Связь с разделом 3 (каскад блокировки/удаления)

События жизненного цикла аккаунта из раздела 3 — не отдельный механизм, а часть этого же фида. Когда срабатывает account.blocked или account.deleted и запускается каскад (отмена будущих RSVP/событий, разрыв матчей, остановка выплат, удаление медиа, отзыв согласий), каждый шаг каскада публикуется в шину как обычное событие с общим correlation_id блокировки/удаления:

Событие каскада Тема Severity Ключевые теги
account.blocked Moderation error account, cascade, audit
account.deleted Compliance critical account, pii, cascade, dsr, audit
events.rsvp.cancelled (каскад) Events info cascade, refund-trigger
dating.match.broken (каскад) Dating info cascade
payment.payout.frozen (каскад) Payments warning cascade, money
media.purged (каскад) Profile/Media info cascade, pii
compliance.consent.revoked (каскад) Compliance info cascade, pii, consent, audit

В админке оператор открывает событие account.deleted, разворачивает по correlation_id — и видит весь каскад: что именно было удалено/отменено, в каком порядке, без ошибок ли. Для DPO это готовое доказательство исполнения требования по удалению ПДн (152-ФЗ): единый журнал = единый источник правды, не нужно собирать подтверждения из разных модулей.


4.5 Сквозной пример: жизненный цикл в ленте

Один пользователь, одна цепочка correlation_id=corr_5f1c. Как это выглядит в фиде (новый → старый порядок показан сверху вниз по времени):

# ts Тема type Severity Теги actor → target Что произошло
1 10:00:01 Auth/Registration auth.user.registered info auth, signup, funnel usr_4821 → usr_4821 Новая регистрация
2 10:01:14 Compliance compliance.consent.granted info compliance, pii, biometric, consent, audit usr_4821 Согласие на ПДн + биометрию (селфи)
3 10:01:40 Auth/Registration auth.verification.selfie.passed info auth, verification, biometric, pii system → usr_4821 Селфи-верификация пройдена
4 10:02:55 Auth/Registration auth.verification.esia.linked info auth, verification, esia, pii usr_4821 Личность подтверждена через ЕСИА
5 10:20:33 Payments payment.succeeded info payments, money, yookassa usr_4821 → pay_99213 Первый платёж (билет на событие) через ЮKassa
6 11:42:09 Moderation moderation.complaint.created warning moderation, report, ugc usr_7777 → usr_4821 На пользователя поступила жалоба
7 12:05:50 Moderation moderation.decision.made info moderation, decision, audit op_mod_3 → usr_4821 Модератор: предупреждение (бана нет)
8 12:06:02 System/Errors payment.fns.receipt.failed critical payments, money, integration, fns, compliance integration → pay_99213 (опц.) Ошибка фискализации чека ФНС по платежу из шага 5 → алерт в Telegram + Finance/Compliance

Как это читается командой: - Поддержка фильтрует по target.id=usr_4821 и видит всю историю человека в одной ленте — от реги до жалобы. - DPO по тегу pii/consent и шагам 2–4 доказывает, что биометрия собрана с согласием (152-ФЗ). - Модератор по теме Moderation (шаги 6–7) разбирает жалобу с полным контекстом. - Финансы/дежурный получают алерт по шагу 8 (critical), открывают цепочку по corr_5f1c и сразу видят, что упала именно фискализация уже успешного платежа — ретраят чек, не трогая сам платёж. - Всё это — одна цепочка corr_5f1c, развёрнутая в drill-down как таймлайн: видно, что система отработала штатно, а сбой — только на последней внешней интеграции.


Источник истины по реальному стеку дейтинга — репозитории nikea-backend, nikea-swagger, nikea-backend-infra (Django/FastAPI, swagger→surfgen, k8s/ArgoCD/Vault).


5. Нефункциональные требования и качество (NFR)

5.1 Целевые показатели качества

Метрика Цель MVP Цель stable Как меряем / обеспечиваем
Crash-free sessions (мобайл) > 98% ≥ 99% Firebase Crashlytics + AppMetrica (уже в приложении); релиз-гейт — не катим при регрессе
API latency p95 / p99 < 800 мс / < 1.5 с < 500 мс / < 1 с Prometheus + Grafana (уже в инфре), алерт на деградацию (§4); tracing (OTel/Tempo) — добавить
Холодный старт приложения < 2.5 с < 2 с RUM, perf-профайлинг релиза
Веб (LCP / TTI) LCP < 2.5 с < 2 с Lighthouse CI + RUM; SSR Next.js
Uptime 99.5% 99.9% health/ready-пробы, managed-БД; мульти-AZ — апгрейд под 99.9% (сейчас PG/Redis/Kafka single-AZ)
RPO / RTO 1 ч / 4 ч ниже бэкапы уже есть (PG/Redis → S3 cronjobs), managed-БД (PITR), отработка восстановления

Crash-free и latency — релиз-гейты: сборка не уходит в прод/стор, если показатели хуже порога.

5.2 Покрытие устройств и версий (цель ≥ 80%)

  • iOS: три последних мажорных версии (ориентир iOS 16–18), минимум iOS 15 (deployment target в проекте 12–15) → ~95%+ активных устройств.
  • Android: minSdk 28 (Android 9.0) — как в приложении сейчас (compileSdk 36 / targetSdk 35) → ≥ 80% активных устройств РФ. Пуш сейчас — FCM + AppMetrica; RuStore (дистрибуция) и Huawei/HMS — отдельно учесть/добавить (в коде их пока нет), иначе теряем долю РФ-рынка.
  • Матрица версий фиксируется и пересматривается ежеквартально по статистике установок.

5.3 Клиент: Flutter (как сейчас) → нативные модули точечно

  • База: Flutter — как у существующего «По любви»; один стек на обе апки (events/dating) и переиспользование наработок дейтинга; перф-чувствительные куски (карты/гео, камера/верификация) — точечно нативными модулями (platform channels).
  • Триггер перехода на натив: после релиза stable MVP и подтверждения PMF, если упираемся в производительность/нативные возможности (плавность свайп-ленты, карта/гео, анимации, фоновые сценарии).
  • Подход — постепенный (brownfield), не big-bang: сначала самые перф-чувствительные экраны (лента, карта, чат), при необходимости — полная нативная переписка одной из апок. Снижает риск против «переписать всё сразу».
  • Только по метрикам: полная нативная переписка — заметные доп.затраты и время → делаем лишь при доказанной необходимости по §5.1, а не по умолчанию.

6. Безопасность и DevOps-гейты

6.1 Тестирование безопасности

  • Пентест: внешний — обязательный gate перед публичным релизом, далее раз в 6–12 мес и после крупных изменений. Охват: мобайл (OWASP MASVS), API, инфра, флоу ПДн/платежей.
  • В CI постоянно: SAST (код), SCA (зависимости/CVE), DAST (по стейджу), секрет-сканер — добавляем в существующий пайплайн (сейчас CI — Jenkins PR/TAG-джобы + ruff-линт).
  • Bug-bounty — опционально после релиза.

6.2 Нагрузочное и стресс-тестирование

  • Нагрузочные тесты (k6 / Locust / Gatling) — net-new, добавляем (сейчас в проде их нет): перед релизом и пиками, целевой RPS с запасом, проверка автоскейла, soak-тесты на утечки/деградацию.
  • Часть CI/CD-гейтов перед прод-деплоем; результаты питают capacity planning.

6.3 Динамическое (полуавто) масштабирование

  • K8s HPA (CPU/RPS/кастомные метрики) + Cluster Autoscaler (ноды). Managed-кластер в Yandex есть, но cluster-autoscaler сейчас выключен, а HPA — настроить. «Полуавто» = включаем автоскейл по метрикам + ручной контроль порогов и capacity planning по §6.2.

6.4 ТГ-боты (верификация и аналитика/алерты)

  • Бот верификации: быстрый low-friction канал подтверждения личности/ускоренной верификации (Telegram/MAX-bot link в онбординге), интеграция с identity/verification.
  • Бот аналитики/алертов: дежурные алерты critical (§4), быстрые метрики/отчёты для команды.
  • 152-ФЗ: в ботов не уходят ПДн — только id-ссылки, метрики, severity, correlation_id (согласовано с §4.3).

6.5 Предиктивные белые списки + «рубильник» сертификатов

Единый контур безопасности, оба аспекта:

  • Антифрод-allowlist'ы (юзеры/устройства): предиктивные списки доверенных (поведение, репутация, верификация) — снижают трение для «хороших» и фокусируют антифрод/модерацию на рисковых; риск-скоринг устройств/аккаунтов отдаёт сигнал в moderation/growth.
  • Инфра/доступы: IP-allowlist на админку и служебные эндпоинты; отзыв клиентских сертификатов / ключей / токенов API.
  • Cert kill-switch (мобайл): certificate pinning (net-new в Flutter-клиенте) с удалённым отзывом/ротацией пина через remote-config (Firebase Remote Config — уже в приложении, §1) — при компрометации/плановой смене сертификата апки не «кирпичатся» и не ждут релиза в сторе. Закладываем remote pin-set + аварийный bypass.
  • Все срабатывания — события темы Security в админ-фиде (§4); механика kill-switch — поверх Firebase Remote Config (§1).