Mriya Playground

Архітектура · модульний моноліт

Як усе влаштовано під капотом

Один API, одна база, спільні контракти — і жодного сервісу, який не потрібен. Ось як рухаються запити, де живуть дані й які компроміси ми обрали свідомо.

модулів API
5
ендпоінтів HTTP і WebSocket
13
зовнішні сервіси
3
бекенд, що деплоїться цілим
1

Схема системи

Від браузера до даних: три шари й два спільні пакети.

Клієнт

  • Браузер

    працює

    HTTP і WebSocket до API; форма контактів іде напряму в EmailJS.

  • apps/web

    працює

    Next.js 16 App Router, React 19, next-intl, TanStack Query.

  • Developer Console

    працює

    Записує запити й події, які застосунок і так робить; без секретів і персональних даних.

Сервер

  • apps/api

    працює

    NestJS, модульний моноліт на /api/v1, по модулю на демо.

    • health
    • analytics
    • realtime
    • workflows
    • ai-search
  • Наскрізні механізми

    працює

    Zod-валідація, rate limit, request id, єдиний формат помилок, OpenAPI на /api/v1/docs.

Дані й зовнішні сервіси

  • PostgreSQL

    працює

    Прогони workflow, їхні кроки й події; міграції при старті.

  • Датасет у памʼяті

    працює

    Синтетичні замовлення для аналітики й AI-пошуку, генеруються один раз при старті.

  • Binance · Bybit

    працює

    Публічні WebSocket-потоки цін BTC/USDT, по одному зʼєднанню на біржу.

  • EmailJS

    працює

    Доставка форми контактів напряму з браузера.

  • Redis

    заплановано

    Є в Docker-стеку, але код його не використовує: черга зʼявиться лише за потреби.

packages/contractsZod-схеми й типи для web і api
packages/uiСамодостатня бібліотека UI-компонентів
Зелена позначка — компонент працює. Пунктир — компонент є в стеку, але код його ще не використовує.

Як рухаються запити

Чотири шляхи даних — по одному на кожен тип демо.

HTTP-запит

  1. Браузер звертається до API через TanStack Query, а Developer Console записує запит.
  2. Rate limit і request id застосовуються до кожного запиту.
  3. ZodValidationPipe перевіряє параметри за схемою з packages/contracts; помилка повертається в єдиному форматі.
  4. Сервіс модуля рахує відповідь із датасету або PostgreSQL.
  5. Браузер розбирає відповідь тією самою схемою, перш ніж її показати.

Потік реального часу

  1. API тримає одне зʼєднання з кожною біржею й зберігає двогодинну історію цін.
  2. Генератор створює замовлення з частотою, яку обрав відвідувач (3–1 500 за секунду), пакетами.
  3. Шлюз на /api/v1/realtime перевіряє origin, обмежує кількість зʼєднань і відключає клієнтів, що не встигають.
  4. Браузер перевіряє кожен кадр Zod-схемою й тримає обмежену історію.
  5. Графіки uPlot перемальовуються в requestAnimationFrame без перерендеру React.

Прогін workflow

  1. POST /workflows одним SQL-запитом створює прогін і очікуваний крок для кожного вузла.
  2. Виконавець паралельно запускає кожен вузол, вхідні дані якого готові.
  3. Кожна зміна — один SQL-запит із перевіркою версії, тож вузол не виконається двічі.
  4. Вузол, що впав, повторюється сам до maxAttempts; ручний повтор продовжує з вузлів, що впали.
  5. Браузер опитує прогін двічі на секунду й малює його в React Flow.
  1. Браузер запитує записаний сценарій.
  2. API наживо виконує перевірку вводу, нормалізацію й збирання промпту; кроки моделі відтворюються із запису.
  3. Zod перевіряє відповідь моделі, а guardrails конвертують валюти й обмежують дати.
  4. Фільтри стають параметризованим SQL і виконуються над датасетом у памʼяті.

Модулі API

Маршрути саме такі, як їх оголошують контролери; усі під /api/v1.

Модулі API, їхні ендпоінти та де зберігається стан
МодульЕндпоінтиСтан
health

Готовність API й бази даних.

  • GET/health
Без стану
analytics

KPI, часові ряди, розбивки й таблиця замовлень.

  • GET/analytics/summary
  • GET/analytics/timeseries
  • GET/analytics/breakdown
  • GET/analytics/records
У памʼяті процесу
realtime

Потік подій і цін, двогодинна історія цін.

  • WS/realtime
  • GET/realtime/prices
У памʼяті процесу
workflows

Запуск, стан, події та повтор прогонів.

  • POST/workflows
  • GET/workflows/:id
  • GET/workflows/:id/events
  • POST/workflows/:id/retry
PostgreSQL
ai-search

Записані сценарії й живі кроки конвеєра.

  • GET/ai-search/scenarios
  • GET/ai-search/scenarios/:id
У памʼяті процесу

Ключові рішення

Шість рішень із журналу docs/decisions.md — з причиною й ціною, яку ми за них платимо.

D3

Один контракт, написаний на Zod

Схеми з packages/contracts перевіряють запити на сервері й відповіді в браузері, а типи виводяться з них.

Компроміс: зміна контракту потребує перезбірки пакета для обох застосунків.

D5

Модульний моноліт на NestJS

Один деплой, по модулю на демо: межі є, мережевих переходів між ними немає.

Компроміс: модулі масштабуються разом; виділення сервісу згодом вимагатиме явного інтерфейсу.

D13

Нативний WebSocket, не Socket.IO

Браузерний WebSocket не потребує клієнтської бібліотеки, а політика перепідключення живе в одному хуку.

Компроміс: немає вбудованих кімнат і fallback-транспортів; потік лише в один бік.

D14

Workflow у процесі, стан у PostgreSQL

Перезавантаження чи рестарт не губить прогін, а оновлення з версією не дають виконати вузол двічі.

Компроміс: виконання в одному процесі; для розподілених воркерів знадобиться черга.

D17

Графіки на canvas через uPlot

SVG через React перерендерювався б на кожну точку; canvas тримає частоту кадрів при 1 500 подіях за секунду.

Компроміс: canvas невидимий для скрінрідерів, тож графіки мають приховані таблиці або описи.

D18

AI-пошук відтворює записані трасування

Мультимовна поведінка показана чесно без виклику моделі, а кроки-код виконуються наживо.

Компроміс: відвідувач не може ввести власний запит.

Що гарантує платформа

Те, що перевіряють тести, а не лише обіцяє документація.

  • Контракти на обох кінцях

    Кожен ендпоінт перевіряє вхід спільною Zod-схемою, а браузер — відповідь.

  • Ліміти запитів

    Глобальний ліміт, жорсткіший — для запису workflow; кількість WebSocket-зʼєднань обмежена.

  • Єдиний формат помилок

    Код помилки й request id замість внутрішнього тексту винятків.

  • CORS і перевірка origin

    Дозволені origin задаються конфігурацією — і для HTTP, і для WebSocket.

  • Консоль без секретів

    Developer Console лише спостерігає, приховує облікові й персональні дані та обмежує історію.

  • Тести на кожному рівні

    Vitest для логіки, e2e API зі справжньою базою, Playwright на desktop і мобільному.

Обговоримо архітектуру вашого продукту?

Покажемо, як ці рішення ляжуть на ваші вимоги: навантаження, дані, інтеграції та команду.