Перейти к основному содержимому

Архитектура системы

Как устроен zolotoy.dev сегодня, куда он движется и какие контракты ещё не решены. Current и target намеренно разделены.

Текущее состояние системы

Сегодня zolotoy.dev — это одно Vue 3 SPA (интерактивное демо), раздаваемое как статика, плюс статически сгенерированный слой портфолио, описывающий работу. Демо в mock-режиме полностью работает на MSW-моках; VITE_API_MODE=real переключает цели транспорта на настроенные хосты, не загружая граф моков.

В бэкенд-репозитории один реализованный Go-модуль: HTTP-сервис заказов на вехе Service Layer. Он валидирует запросы, вызывает слой сервиса и возвращает демонстрационные результаты. Доменные машины состояний существуют отдельными пакетами и ещё не подключены к HTTP-потоку. PostgreSQL, Redis, Kafka, auth и живая интеграция с фронтендом не подключены.

Текущая архитектура

Браузер → типизированный транспорт фронтенда (native fetch через API-фасады модулей) → перехват MSW для mock-демо. Серверное состояние принадлежит TanStack Query; Pinia-сторы намеренно узкие (сессия, рантайм, тема).

Параллельно локально работает Go-сервис заказов: POST /orders и GET /orders/{id} валидируют вход и делегируют слою сервиса. Живой связи между публичным демо и Go-сервисом нет — демо намеренно замокано, пока не готовы auth и контракты.

  • Current

    Demo flows run on deterministic MSW scenarios; unhandled requests to configured service origins fail closed with 501 MOCK_UNHANDLED_REQUEST.

  • Current

    The Go order service is a separate local implementation: HTTP validation → service call, no persistence, no tests yet.

  • Current

    Order domain models and transition methods exist but are not integrated with the HTTP flow.

Current
  • BrowserPortfolio + demo SPA
  • Vue SPA (demo)Typed transport → MSW mock APIs
  • Go order service (local)POST/GET /orders, validation → service layer
  • static assets: browser → spa
  • no live connection: spa → order-go (planned)
Current topology: mocked demo SPA and a local Go order service, not connected.

Целевая архитектура

Цель — четыре независимо владеемых сервиса за /api/v1 с явным владением данными и событийным контрактом между Order и Notification. Вся инфраструктура на целевой диаграмме — PostgreSQL, Redis, Kafka — планируемая, а не развёрнутая.

  • Target

    Auth owns users, credentials and sessions. Other services never read credential tables.

  • Target

    Order owns orders, payment-related state, history and outbox records.

  • Target

    Notification owns inbox records, delivery jobs and delivery attempts.

  • Target

    Shortener owns links and bounded analytics.

  • Target

    Services do not query each other’s private tables; shared deployment infrastructure does not imply shared business-data ownership.

  • Target

    Order events feed Notification through a defined event contract via a transactional outbox.

Target
  • BrowserPortfolio + demo
  • /api/v1 gatewaysOne namespace per service
  • AuthUsers, credentials, sessions
  • OrderOrders, payment state, outbox
  • NotificationInbox, delivery jobs, attempts
  • ShortenerLinks, bounded analytics
  • PostgreSQLPer-service schemas
  • RedisSessions/cache (planned)
  • KafkaEvent transport (planned)
  • HTTPS JSON: browser → apiv1
  • auth API: apiv1 → auth (planned)
  • order API: apiv1 → order (planned)
  • notification API: apiv1 → notification (planned)
  • shortener API: apiv1 → shortener (planned)
  • order events (outbox): order → kafka (planned)
  • event consumption: kafka → notification (planned)
  • own schema: order → pg (planned)
  • own schema: auth → pg (planned)
  • session/rate-limit state: auth → redis (planned)
Target topology: four services, owned data, event contract. All infrastructure planned.

Границы сервисов

Каждый сервис открывает свой namespace /api/v1 и владеет своим хранилищем. Фронтенд считает их независимыми модулями за одним общим транспортом и моделью ошибок. Межсервисные допущения (например, соответствие ролей Order и Auth) — явные интеграционные контракты, а не неявные JOIN между базами.

Владение данными

Order: заказы, история жизненного цикла, переходы платёжного состояния, записи outbox. Auth: пользователи, учётные данные, сессии и семейства refresh. Notification: inbox, задачи доставки, попытки. Shortener: ссылки и ограниченная аналитика. Ничто другое не читает эти таблицы напрямую; интеграции — через API или событийный контракт.

Mock против live-рантайма

Режим по умолчанию — mock: MSW перехватывает тот же сетевой путь, что и реальный транспорт, с детерминированными сценариями и сбросом. Real-режим никогда не загружает граф моков. Поле demoMode в каждом кейсе (mock/mixed/live) — свидетельство о видимом демо-потоке, а не утверждение о развёрнутом бэкенде.

Архитектурные принципы

Границы вместо быстрых решений: транспортный разбор не попадает в бизнес-логику; сервисы не лезут в хранилища друг друга. Честность вместо маркетинга: current ≠ target ≠ measured, планируемая инфраструктура всегда помечена. Сценарии отказа проектируются, а не обнаруживаются: идемпотентность, конкурентность и семантика at-least-once — полноценный контент.

Связь с роадмапом

Приведённая архитектура — пункт назначения последовательности вех: Order → персистентность → жизненный цикл/конкурентность → Auth → живой фронтенд → события → Notification → Shortener → наблюдаемость. Секция Next Milestone каждого кейса называет ближайший шаг и его критерии приёмки.

Integration Contracts (unresolved areas)

These areas require explicit API-contract decisions before the corresponding frontend flows switch from mock to live. None of them has a canonical OpenAPI document yet.

Поведение Cookie/CORS/CSRF

Атрибуты refresh-cookie, CORS-origins и защита CSRF ещё не согласованы с бэкендом.

  • Политика SameSite/Domain для refresh-cookie
  • Способ передачи CSRF-токена
  • Разрешённые origins по окружениям

Конверты ошибок и health-контракты

Общий конверт ошибок и health-эндпоинты стандартизированы на уровне сервисов, но контрактно не зафиксированы.

  • Namespace кодов ошибок
  • Семантика health/live и health/ready
  • Форма ответа rate limiting

Роли Auth против ролей Order

Соответствие RBAC-ролей Auth ролям действий с заказами (buyer/manager/admin) не определено.

  • Формат role-claim в access-токенах
  • Смена ролей в демо против реальных ролей

Контракты Order: DTO/список/история/отгрузка/отмена/возврат

Пагинация списка, представление истории и эндпоинты жизненного цикла помимо create/get — TBD.

  • Поля DTO для списка и детали
  • Формы запросов/ответов cancel/refund
  • Имя заголовка идемпотентности

Поведение Auth: cookie/тела/DTO сессий

Точные тела запросов/ответов login/register/refresh и форма списка сессий — TBD.

  • Тело refresh-запроса против cookie-only
  • Поля DTO сессии
  • Семантика logout-all

Контракты Notification: задачи/попытки/фильтры/ручной ретрай

Фильтры списка задач, представление попыток и семантика ручного ретрая — TBD.

  • Имена параметров фильтров
  • Авторизация ручного ретрая
  • Политика повторной постановки dead-задач

Shortener: владение/статусы/аналитика/404 против 410

Правила владения ссылками, коды статусов для истёкших и отключённых, форма аналитики — TBD.

  • Модель владения
  • Соответствие 404 и 410
  • Гранулярность аналитики