Технологический стек
Инфраструктура
Section titled “Инфраструктура”| Слой | Решение | Примечание |
|---|---|---|
| БД | PostgreSQL 18 | Единственное хранилище: данные, очередь задач, блокировки |
| Секреты | Локальный master key (файл) или Vault Transit | Pluggable, см. Шифрование |
| Метрики | Prometheus + OpenTelemetry | См. Наблюдаемость |
| Контейнеризация | Docker + Docker Compose | |
| Reverse proxy | Traefik v3 | TLS для панели |
Redis отсутствует намеренно: фоновые задачи и блокировки живут в PostgreSQL (River + advisory locks). Меньше stateful-компонентов — проще self-hosted-эксплуатация; при целевом масштабе выигрыша от отдельного брокера нет.
Backend
Section titled “Backend”| Слой | Решение |
|---|---|
| Язык | Go 1.25+ |
| HTTP | Fiber v3 |
| Доступ к БД | pgx + sqlc |
| Миграции | Goose + go:embed |
| Фоновые задачи | River (очередь в PostgreSQL) |
| Auth | JWT + Argon2id |
| Валидация | go-playground/validator |
| OpenAPI | Генерация из кода (Swaggo) |
| Телеметрия | OpenTelemetry |
| Конфигурация | Koanf |
sqlc вместо GORM: схема и запросы описываются SQL-ом, из них генерируется типизированный Go-код. Нет рантайм-магии ORM, каждый запрос виден и объясним (EXPLAIN), поведение при миграциях предсказуемо.
| Слой | Решение |
|---|---|
| Язык | Go 1.25+ |
| Связь | gRPC-стрим к backend (mTLS), см. gRPC API |
| Xray | Дочерний процесс в том же контейнере |
| Конфигурация | Koanf |
Frontend
Section titled “Frontend”| Слой | Решение |
|---|---|
| Рантайм / пакеты | Bun |
| Фреймворк | React 19 + Vite |
| Роутинг | TanStack Router |
| Серверный стейт | TanStack Query |
| Глобальный стейт | Zustand |
| Формы | React Hook Form + Zod |
| Стили | CSS Modules + токены; Tailwind — точечно |
| API-клиент | openapi-react-query + openapi-typescript |
| Графики | Recharts |
| Иконки | Lucide React |
| i18n | Paraglide JS |
Стили строятся на трёх уровнях:
- Токены — семантические CSS custom properties в духе shadcn/ui (
--background,--primary,--muted-foreground,--sidebar-*,--chart-*) вshared/styles.css; тёмная тема — класс.dark, переопределяющий переменные. - CSS Modules — основной механизм:
*.module.cssрядом с компонентом, классы сразу в camelCase (.cardHeader). Цвета, отступы, радиусы, шрифты — только черезvar(--token), сырые значения запрещены. Темизация модулей автоматическая: они ссылаются на переменные и о темах не знают. - Tailwind v4 — подключён (
@theme inlineпробрасывает те же токены в утилиты), но используется как исключение: одиночная утилита там, где класс в модуле ради одного свойства избыточен. Если утилит у элемента больше двух или комбинация повторяется — это класс в module.css или компонент ui-kit. Произвольные значения ([…]) запрещены везде.
Один источник дизайн-решений — токены: и модули, и утилиты ссылаются на одни переменные, палитра меняется только в styles.css.