Usługi

Backend Trans-Atlas: Sprint 0

Plan przekształcenia demonstracyjnego SPA w aplikację z serwerowym źródłem prawdy: konta firm, trwałe zgłoszenia, słowniki w bazie danych, dziennik zdarzeń.

To specyfikacja i zapis już przeprowadzonych kontroli artefaktów, a nie podłączony backend: index.html nadal jest jednostronicowym plikiem bez etapu budowania, bez PostgreSQL, bez serwera NestJS i bez prawdziwego API. Sekcja „Planowane zmiany we frontendzie” opisuje kolejny krok, a nie to, co już zastosowano - LISTINGS, logowanie przez localStorage i test-data/ nadal działają tak samo, jak przed tą stroną.

Zakres Sprintu 0

  • PostgreSQL 18 + PostGIS: схема, міграції, довідники з реєстрів SPA
  • Автентифікація: реєстрація компанії, вхід, ротація refresh-токенів, підтвердження email, ролі
  • CRUD заявок і стрічка з фільтрами, що повторюють filteredListings()
  • Імпорт наявних 10 773 демо- і тестових заявок у БД без втрати даних
  • Append-only журнал подій
  • Розгортання, міграції, бекапи, моніторинг

Świadomie poza zakresem

Co Dlaczego Przeniesiono do
Модуль SEARCH (маршрути, магістраль→фідери, POST_DRONE)Власний REST-контракт і власний CIОкремий етап
Верифікація контрагента (KYB, реєстри, дельта-моніторинг)Напрям A плануТижні 3–7
Ingest-агентНапрям B плануТижні 4–8
SSE-стрічка, push, PWAНапрям C плануТижні 6–10
Ставки, торг, ескроу, розрахункиМежа модулів A.1.3 рамкового ТЗПісля перших угод

Stos i środowisko

Komponent Decyzja Dlaczego
МоваTypeScript, Node.js 24 LTSОдна мова від схеми до інтерфейсу
КаркасNestJSМодульність, DI, готова інтеграція валідації та OpenAPI
БДPostgreSQL 18 + PostGIS 3.6PostGIS потрібен уже зараз для країн і відстаней
Кеш і чергаRedis 7Ідемпотентність, ліміти запитів, надалі шина подій стрічки
Міграціїnode-pg-migrate або Flyway, тільки впередЗастосовність до продової бази без ручних кроків
ПоштаSMTP із SPF/DKIM/DMARCПідтвердження email і скидання пароля
СпостережуваністьJSON-логи, /api/v1/health, PrometheusМінімум, без якого продакшн не запускається

Kluczowe niezmienniki na poziomie bazy danych

Niezmiennik Mechanizm
mode='multi' ⇒ components містить ≥ 2 плеча, лише базові видиCHECK listings_components_rule
mode<>'multi' ⇒ components IS NULLтой самий CHECK
mode='drone' ⇔ існує рядок у listing_drone_detailsвідкладений CONSTRAINT TRIGGER
Місто відправлення ≠ місто призначенняCHECK listings_origin_ne_destination
is_cross_border не редагується вручнуGENERATED ALWAYS AS ... STORED
Рівень верифікації вище L0 неможливий без дати перевіркиCHECK companies_verified_needs_date
У компанії рівно один власникчастковий UNIQUE INDEX по role='owner'
Email унікальний без урахування регіструтип citext
Журнал подій не редагується застосункомREVOKE UPDATE, DELETE для ролі застосунку

Zgodność filtrów API i SPA

GET /api/v1/listings musi zwracać ten sam wynik co dzisiejsze filteredListings().

state.filters w SPA Parametr API
state.filters.modemode
state.filters.multiModescomponents
state.filters.fromorigin_city_id
state.filters.todestination_city_id
state.filters.fromCountryorigin_country
state.filters.toCountrydestination_country
state.filters.borderScopeborder_scope
state.filters.currencycurrency

Uwierzytelnianie i bezpieczeństwo

Wymaganie Wartość
Хешування пароляargon2id, m=64 MiB, t=3, p=1
Мінімальна довжина пароля10 символів; перевірка за списком скомпрометованих
Access-токенJWT, 15 хв, EdDSA, kid для ротації ключів
Refresh-токен30 днів, лише SHA-256; ротація з родиною, повторне використання вбиває всі сесії
Блокування10 невдалих спроб → блок на 15 хвилин
Підтвердження emailОдноразовий токен, 24 години; до підтвердження - перегляд без публікації
Роліowner, manager, viewer; редагувати заявку може лише її компанія

Wymagania niefunkcjonalne

Wskaźnik Cel
Стрічка з фільтрами, p95≤ 200 мс на 100 тис. заявок
Публікація заявки, p95≤ 300 мс
Доступність99.5% на місяць
БекапЩодоби повний, WAL безперервно, відновлення - щомісяця
МіграціїТільки вперед, без ручних кроків

Rzeczywiste przebiegi testów

Przebieg Co sprawdzał Wynik
tools/extract_registries.pyВитягування реєстрів із index.html175 міст, 9 вантажів, 32 валюти, порожніх полів немає
ci/check_backend_contract.py8 груп перевірок артефактів15 із 15 пройдено
ci/acceptance_db.pyЖива PostgreSQL 18.6 + PostGIS 3.625 із 25 пройдено

Planowane zmiany we frontendzie

Kolejny krok po pojawieniu się prawdziwego backendu - niezastosowany w tym demo:

  • LISTINGS перестає бути літералом і стає результатом GET /api/v1/listings; loadExternalListings() і LISTINGS_FEED замінюються курсорною пагінацією
  • getUsers(), setUsers(), saveUser() видаляються. localStorage лишається лише для мови, вибраного виду транспорту та інших втрачуваних станів UI
  • Форма модального вікна отримує третій режим — публікацію заявки
  • Помилки показуються з problem+json, поле в помилці підсвічується за JSON Pointer
  • Перемикач API_BASE: за відсутності бекенду сайт чесно повідомляє про це, як уже роблять вкладки погоди й кордонів

Bramki CI: wymagane kontrole

Dwanaście wymaganych kontroli z trzech potoków; każdy potok ma własny job-bramkę, który kończy się niepowodzeniem, jeśli zawiedzie dowolny zależny od niego job.

Potok Job Kontrola w regule
.github/workflows/contract.yml schema Схема і сценарії T16-T27
i18n Валютні та мовні сценарії C1-C13, L1-L12
proto Контракт proto модуля SEARCH
ui UI-сценарії U1-U8 вибору виду транспорту
contract-gate contract-gate
.github/workflows/backend.yml backend-contract Контракт бекенду Спринту 0
backend-db Приймальні тести БД Спринту 0
verification-contract Контракт модуля верифікації
verification-db Інваріанти верифікації
backend-gate backend-gate
.github/workflows/web3.yml web3-tests web3-sprint0-tests
blockchain-gate blockchain-gate

To zastosowana konfiguracja, a nie projekt: reguła gałęzi main wymaga wszystkich dwunastu kontroli wymienionych w tabeli powyżej, a `.github/workflows/` zawiera trzy wymagane potoki - `contract.yml`, `backend.yml` i `web3.yml` - oraz nieblokujący `source-probe.yml`. Skrypty `sprint-0-backend/ci/*`, które wywołuje potok backendu, są w repozytorium i uruchamiają się na prawdziwej PostgreSQL z PostGIS: w przebiegu na main przeszły migracja, zasianie słowników, import 10773 ogłoszeń i negatywne testy niezmienników - łącznie 42 kontrole na żywej bazie. `ci/check_live_ruleset.py` porównuje plik reguły z żywym GitHubem i na obecnym main zgłasza zgodność: 12 kontroli w pliku, 12 w GitHubie. Walidator spójności `ci/check_ruleset.py` też się uruchamia: 14 reguł, 35 z 35 mutacji wykrytych. Czego nadal nie zastosowano: sama ta strona pozostaje jednym plikiem bez backendu - potoki sprawdzają kontrakty i bazę, a nie obsługują index.html.

Pliki modelu