Перейти до вмісту

Потоки даних

Критичні наскрізні сценарії, відомі провайдери підставлені (Monobank, Google OAuth, Cloudflare Origin Pulls, Typesense).

Автентифікація — Google OAuth + JWT

Section titled “Автентифікація — Google OAuth + JWT”
sequenceDiagram
    actor U as Абітурієнт
    participant W as Abitly Web
    participant A as Abitly API (NestJS)
    participant G as Google OAuth
    participant DB as Postgres (shared)
    U->>W: Login → Google
    W->>G: redirect OAuth (client_id, redirect_uri)
    G-->>U: вибір акаунту, consent
    U->>G: підтверджує
    G-->>W: callback з code
    W->>A: POST /auth/google {code}
    A->>G: exchange code → tokens
    G-->>A: id_token / refresh_token
    A->>DB: upsert user
    A-->>W: JWT access + refresh cookies
    W-->>U: авторизовано

Альтернатива: Telegram-прив’язка через бот — deep-link link_<token> редімить одноразовий Redis-токен (мінтить бекенд) і лінкує акаунт (telegram_users.web_user_id). Наскрізно ще не працює — див. картку бота.

sequenceDiagram
    actor U as Абітурієнт
    participant W as Web / Mini App
    participant A as Abitly API
    participant M as Monobank API
    U->>W: Обирає Premium / Token purchase
    W->>A: POST /payments/create {plan}
    A->>M: create invoice (MONOBANK_TOKEN)
    M-->>A: invoiceId + paymentUrl
    A-->>W: paymentUrl
    W-->>U: redirect на Monobank checkout
    U->>M: оплачує
    M-->>A: webhook (SUBSCRIPTION_WEBHOOK_URL / PREMIUM_WEBHOOK_URL / TOKEN_PURCHASE_WEBHOOK_URL)
    A->>A: verify signature, активувати підписку
    A-->>W: redirect (SUBSCRIPTION_REDIRECT_URL / ...)

Контент Strapi — через Cloudflare Authenticated Origin Pulls

Section titled “Контент Strapi — через Cloudflare Authenticated Origin Pulls”
sequenceDiagram
    actor U as Абітурієнт
    participant W as Abitly Web
    participant CF as Cloudflare proxy
    participant S as Strapi (EC2)
    participant DB as Postgres
    U->>W: Відкриває сторінку ЗВО
    W->>CF: GET /api/universities/...
    CF->>S: запит з origin-cert<br/>(валідація ORIGIN_PULL_CA)
    S->>S: перевірка cert OK
    S->>DB: SELECT (схема strapi)
    DB-->>S: рядки
    S-->>CF: JSON
    CF-->>W: cached / fresh
    W-->>U: відрендерена сторінка

403 від Strapi → найімовірніше прострочений CF origin-cert. Деталі → domains-dns.

sequenceDiagram
    actor U as Користувач
    participant T as Telegram API
    participant B as Bot (aiogram · AWS ECS)
    participant DB as Postgres (abitly)
    participant A as Abitly API
    participant M as Mini App (Next.js · Railway)
    U->>T: /start
    T->>B: update (long polling)
    B->>DB: upsert TelegramUser
    DB-->>B: профіль / бали
    B->>T: sendMessage (+ web_app button)
    T-->>U: повідомлення + кнопка
    U->>T: tap «Open App»
    T->>M: launch Mini App with initData
    M->>A: POST /telegram/auth {initData}
    A->>A: verify HMAC(initData, bot_token)
    A-->>M: JWT
    M-->>U: інтерактивний UX

Повний набір сценаріїв бота (use-case, sequence по кожній команді/deep-link, state, доменна UML) → Telegram-бот: user-сценарії.

Підтримка — CRM/Support bot (омніканальні звернення)

Section titled “Підтримка — CRM/Support bot (омніканальні звернення)”

Один Lambda-вебхук на три канали. Telegram-гілка — інтейк-візард; Meta-гілка (Instagram Direct / Messenger) — топік з першого DM. Деталі й обмеження → картка сервісу.

sequenceDiagram
    actor IGU as IG-користувач
    actor OP as Оператор
    participant MG as Meta Graph API
    participant GW as API GW /meta
    participant L as Lambda abitly-crm-bot
    participant D as DynamoDB
    participant SR as Форум-група «Abitly CRM»

    IGU->>MG: DM до @abitly_org
    MG->>GW: POST (X-Hub-Signature-256)
    GW->>L: подія messages
    L->>L: verify HMAC + дедуп mid
    L->>D: get/create CONVO (CHAN#ig#IGSID)
    L->>SR: createForumTopic «🔵📸 Ім'я @username» + текст
    L->>D: LOG# + MAP mid↔message_id
    OP->>SR: відповідь у топіку
    SR->>L: Telegram webhook (topicId)
    L->>MG: POST /me/messages (RESPONSE ≤24h / HUMAN_AGENT ≤7d)
    MG-->>IGU: відповідь у Direct
    L->>SR: топік → ⚪️
sequenceDiagram
    participant W as Abitly Web
    participant GW as API Gateway HTTP<br/>(abitly-collector-dev)
    participant L as Lambda collector
    participant F as Kinesis Firehose
    participant S as S3 Iceberg/Parquet
    participant DB as Athena + Glue Catalog
    W->>GW: POST /collect {events:[...]}
    GW->>L: invoke
    L->>L: Ajv validate vs events.schema.json
    L->>L: dedup + enrich
    L->>F: PutRecordBatch
    F->>S: Parquet partitions
    DB-.->S: каталог
    Note over DB: dbt models<br/>→ Metabase dashboards

Поточний стан — dev only, prod ще не задеплоєно. Деталі → analytics.

Cross-product search (Abitly → Studsearch)

Section titled “Cross-product search (Abitly → Studsearch)”
sequenceDiagram
    actor U as Абітурієнт
    participant W as Abitly Web
    participant A as Abitly API
    participant S as Studsearch backend
    participant DB as Postgres<br/>(shared, різні схеми)
    U->>W: пошук ЗВО з insider-відгуками
    W->>S: GET /search?q=...
    Note over W,S: NEXT_PUBLIC_STUDSEARCH_API_URL
    S->>DB: SELECT FROM studsearch.*
    DB-->>S: відгуки
    S-->>W: JSON
    W->>A: GET /universities/...
    A->>DB: SELECT FROM abitly.*
    DB-->>A: дані ЗВО
    A-->>W: JSON
    W-->>U: об'єднаний UX

Один і той самий Postgres, дві різні схеми, два різні API.

Маркетинг — grounded AI-кампанія + атрибуція

Section titled “Маркетинг — grounded AI-кампанія + атрибуція”
sequenceDiagram
    participant SCH as Marketing<br/>(BullMQ)
    participant DB as marketing schema<br/>(read-model)
    participant AI as Claude (L2/L3)
    participant V as Validator
    participant ST as Strapi (facts)
    participant ESP as ESP / @abitlybot
    actor C as Контакт
    participant LH as Lake-house
    participant M as Monobank
    SCH->>DB: SELECT сегмент (lifecycle × intent)
    SCH->>AI: згенерувати копію (structured input)
    AI-->>SCH: обгортка зі слотами
    SCH->>V: перевірити (нема вигаданих фактів)
    V-->>SCH: ok / regenerate
    Note over SCH: approval queue (людина схвалює L2)
    loop на кожен контакт
        SCH->>ST: факти (дедлайн, бал, ціна)
        SCH->>DB: suppression + freq cap + consent?
        SCH->>ESP: send (campaign_id, contact_id)
        ESP-->>C: лист / повідомлення<br/>(unsubscribe + preference-center)
        ESP->>LH: delivered / opened / clicked
    end
    C->>M: оплата (Premium / Sub / Tokens)
    M->>LH: webhook → last-touch campaign_id
    Note over LH: mart: sends→clicks→purchases<br/>= attributed revenue (D1)

Факти ніколи не генеруються моделлю — лише підставляються у слоти (ADR-3). Поточний стан — план (abitly-marketing).