Услуге
Technology stack
The language and technology choices for a production rewrite of Trans-Atlas as an exchange covering six transport modes: a server-side database as the single source of truth, PostgreSQL + PostGIS, contracts via JSON Schema.
This is a decision record, not a deployed stack: none of the listed services (Next.js, NestJS, Go, Kafka, ClickHouse, Kubernetes) actually run in this project. index.html stays the same single-page file it always was. "Backend: Sprint 0" is the first executed and tested slice of this broader plan.
Decisions by layer
| Layer | Choice | Language | Why |
|---|---|---|---|
| Frontend | Next.js (App Router) + React + TypeScript | TypeScript | SSR/ISR для SEO-розділів біржі, клієнтські таблиці заявок, один тип-контракт із бекендом |
| UI-шар | Tailwind CSS + Radix UI + TanStack Table/Query | TypeScript | Щільні табличні інтерфейси біржі, доступність, серверний кеш замість localStorage |
| Основний backend | NestJS на Node.js 24 LTS | TypeScript | Одна мова з фронтендом, модульність під розділи транспорту, зрілі валідація/DI/OpenAPI |
| ORM / доступ до даних | Prisma для CRUD + чистий SQL (pg) для геозапитів | TypeScript / SQL | PostGIS-функції та ранжування пишуться SQL-ом, не ORM-абстракцією |
| Пошук маршрутів (SEARCH) | окремий сервіс на Go | Go | Обхід графа магістраль→фідери, POST_DRONE; передбачувана латентність і паралелізм |
| Геодані та відстані | PostgreSQL 18 + PostGIS; OSRM або Valhalla | SQL / C++ | Радіусний пошук для дрон-плеча, реальні дорожні відстані замість «по прямій» |
| СУБД | PostgreSQL 18 (Patroni або керований кластер) | SQL | Транзакційна цілісність угод, ставок, ескроу; JSONB для шаблонів заявок |
| Кеш і черги коротких задач | Redis 7 | — | Вимога A.4/A.11; кеш конекторів погоди та кордонів |
| Шина подій | Kafka (або Redpanda) | — | Ставки, статуси угод, аудит, вебхуки партнерам; ordered log під фінансові події |
| Повнотекстовий пошук | PostgreSQL FTS на MVP → OpenSearch за потреби | SQL | Не вводити ще один кластер, поки Postgres тримає навантаження |
| Реальний час (ставки, чат) | WebSocket (Socket.IO або ws) + Redis pub/sub | TypeScript | Онлайн-стрічка заявок і ставок |
| Платежі, валюти, ескроу | окремий сервіс settlement, decimal-арифметика | TypeScript + SQL | Валюта ціни ≠ валюта оплати: ставка, договір, платіж, курс, комісія — окремі поля |
| Web3-шар (опційний) | Solidity + Foundry, EVM L2, стейблкоїн-виплати | Solidity | Смартконтрактне ескроу як додатковий шар, а не заміна фіатної бухгалтерії |
| Аналітика та BI | ClickHouse (події) + Metabase/Power BI | SQL | Оперативна аналітика без навантаження на OLTP |
| ML / прогноз ставок | Python (FastAPI, pandas, scikit-learn/LightGBM) | Python | Окремий сервіс, викликається API; не змішується з доменним бекендом |
| Інфраструктура | Docker + Kubernetes (керований) або Nomad; Terraform | HCL / YAML | Один спосіб опису середовищ, узгоджений із наявним CI-підходом |
| CI/CD і контракти | GitHub Actions + JSON Schema + мутаційні тести + bash -euo pipefail | YAML / Python | Продовження вже перевіреного контрактного CI проєкту TA |
| Спостережуваність | OpenTelemetry → Grafana (Loki, Tempo, Prometheus), Sentry | — | Трасування пошуку маршрутів і платіжних операцій end-to-end |
Why these choices
TypeScript as the primary language: one type contract from database to UI, the largest hiring market for a web product of this class, and the existing demo prototype and local TA server carry over to production without a language change.
Go for the SEARCH module only: graph traversal for routing and bulk distance calculations give unstable latency under load in Node; goroutines and a single static binary make the parallel fan-out direct and predictable.
Deliberately not chosen
| Rejected | Reason |
|---|---|
| PHP/Laravel монолiт | Слабший шлях до реального часу й до окремого високонавантаженого сервісу пошуку |
| Java/Spring | Придатний і надійний, але дорожчий у наймі та повільніший в ітераціях для команди такого розміру |
| Python як основний backend | Залишено лише для ML і аналітики; для OLTP-домену з ескроу типізований TypeScript зручніший у контрактному CI |
| MongoDB як основна база | Угоди, ставки, ескроу потребують транзакцій і обмежень цілісності |
| Vector DB на старті Q&A | У TA вже працює локальне retrieval по курованих wiki.json/outputs.json — цього достатньо для MVP |
| Повністю on-chain біржа | Юридично значущі документи й фіатні платежі лишаються off-chain; блокчейн — опційний розрахунковий шар |
| localStorage як сховище предметних даних | Пряма заборона рамкового ТЗ; допустимий лише втрачуваний UI-стан |
MVP service map
web (Next.js, TS)
└─ api-gateway (NestJS, TS) ── OpenAPI + JSON Schema
├─ identity (KYB, тризрівневий онбординг, права на розділи транспорту)
├─ exchange (заявки, лоти, ставки, рейтинги) ── Kafka
├─ settlement (валюта ціни / валюта оплати, курс + джерело курсу, комісія, ескроу)
├─ search (Go) ── PostGIS, OSRM/Valhalla, Redis
├─ connectors (погода, кордони, довідники) ── Redis-кеш, деградація по джерелу
└─ qa-portal (raw → wiki → outputs, цитати й статус перевірки)
PostgreSQL 18 + PostGIS · Redis · Kafka · ClickHouse · S3-сумісне сховище документівLaunch sequence
| Stage | What's included | Technology added |
|---|---|---|
| Етап 1 (0–3 міс.) | Заявки, ставки, профілі, права на розділи, UK/EN/PL/DE, платна реєстрація | Next.js, NestJS, PostgreSQL+PostGIS, Redis, GitHub Actions |
| Етап 2 (3–6 міс.) | Модуль SEARCH, POST_DRONE, реальні дорожні відстані | Go-сервіс, OSRM/Valhalla, gRPC-контракт |
| Етап 3 (6–9 міс.) | Мультивалютні угоди, ескроу, e-invoicing, локальні виплати | settlement, decimal-арифметика, PSP-інтеграції |
| Етап 4 (9–12 міс.) | Аналітика, рейтинги на даних, прогноз ставок, вебхуки партнерам | ClickHouse, Python-ML, Kafka Connect |
| Етап 5 | Смартконтрактне ескроу й оракули підтвердження доставки | Solidity + Foundry, L2 |
Acceptance criteria for the stack choice
- Жоден предметний запис не зберігається у сховищі браузера; очищення браузера не втрачає даних учасника
- Кожен публічний API-ендпойнт має JSON Schema, і мутація схеми валить CI
- Контракт між api-gateway і search перевіряється окремим негативним pull request
- Пошук повертає зібраний і ранжований набір варіантів, а не перший знайдений маршрут
- Дрон-варіант додається як альтернатива останнього авто-плеча і не видаляє авто-варіант
- У угоді ставка, договір, платіж, курс, джерело курсу, комісія та стан ескроу — окремі поля
- Деградація одного зовнішнього конектора дає частковий результат, а не помилку всієї сторінки
- Усі bash-кроки конвеєра виконуються з bash -euo pipefail