Технологии и командная разработка
Развивать по частям. Видеть систему целиком. В geek.moscow у каждой предметной области есть собственный сервис, у крупных разделов интерфейса — свой модуль, а у команды — общие контракты, дизайн-система и инструменты наблюдения. Такое устройство даёт понятную основу для перехода от небольшой команды к параллельной продуктовой разработке.
Например, команда инженерного профиля может развивать анкеты и интеграцию с ФСП, команда работодателей — кабинеты компаний и вакансии, а команда коммуникаций — переписку. Границы этих задач уже отражены в коде. Общие правила авторизации, форматы обмена и визуальные компоненты помогают соединять результаты в один продукт.
Стек и его назначение
| Уровень | Технологии | Что получает проект |
|---|---|---|
| Backend | TypeScript, NestJS, Fastify | Единый язык, модульная структура сервисов, общий подход к HTTP и обработке ошибок |
| Контракты | gRPC, Protocol Buffers, JSON Schema | Явные интерфейсы между сервисами и схемы событий; возможность проверять совместимость изменений |
| Данные | PostgreSQL, pg |
Транзакции и собственная логическая база с правами доступа у каждого бизнес-сервиса |
| Фоновая работа | RabbitMQ, Transactional Outbox, workers | Доставка событий, повтор обработки и отдельные очереди для неуспешных сообщений |
| Оперативное состояние | Redis | Лимиты запросов, межпроцессные сигналы и восстанавливаемое состояние |
| Frontend | React, TypeScript, Vite, Module Federation | Общая оболочка и подключаемые функциональные модули |
| Интерфейсные контракты | React Router, TanStack Query, @geek.moscow/design-sys, Storybook |
Согласованная навигация, работа с серверными данными и единый язык компонентов |
| Наблюдаемость | Pino, prom-client, Prometheus, Grafana |
Структурированные логи, показатели операций и ресурсов, дашборды и правила оповещений |
| Поставка | Docker, Kubernetes/k3s, Kustomize, GitLab | Воспроизводимые образы, описанные окружения, история кода и основа автоматизации выпуска |
| Проверки | Jest, Vitest, Playwright, проверки контрактов | Проверки предметной логики, интерфейсных модулей, совместимости и сквозных сценариев |
| Почтовая доставка | Nodemailer, SMTP, очередь Identity | Фоновые письма безопасности, повторы, шаблоны и контроль результата; Mailpit для демонстрации |
Версии библиотек закреплены в манифестах и lock-файлах. Карта каталогов и репозиториев приведена в структуре кода.
Микросервисы: понятные границы ответственности
Backend разделён на восемь бизнес-сервисов: Identity, Candidates, Employers, Opportunities, Recruitment, Chat, Notifications и Backoffice. Gateway связывает браузер с этими сервисами; один код Gateway работает в двух профилях — продуктовом и административном.
Каждый сервис владеет своей областью: Candidates — анкетами и достижениями, Employers — компаниями и членствами, Recruitment — подбором, оферами и разрешениями на раскрытие. Изменять данные другой области нужно через её контракт. Это позволяет закрепить сервис за командой, локализовать изменение и понимать, кто отвечает за его проверку и эксплуатацию.
Для немедленного ответа используются gRPC-вызовы. Для событий и длительной работы — RabbitMQ: например, публикация анкеты запускает обновление поисковой проекции, а отправка офера — создание диалога и уведомления. Transactional Outbox сохраняет изменение и событие одной транзакцией; обработчики учитывают повторную доставку. API и фоновые процессы одной области можно запускать и масштабировать отдельно.
Контракты остаются общей точкой согласования. Изменение формата офера затрагивает его потребителей, поэтому независимая работа команд опирается на совместимость RPC и событий. Схема взаимодействий и владельцы данных подробно разобраны в архитектуре.
Module Federation: один интерфейс, несколько команд
Пользователь видит единое приложение. Внутри него web-shell загружает четыре отдельно собираемых модуля через Module Federation:
| Модуль | Область работы |
|---|---|
candidates |
Инженерный профиль, анкеты и достижения |
employers |
Компания, её участники и вакансии |
recruitment |
Подбор, интересы, оферы и раскрытие данных |
messaging |
Переписка и уведомления |
У каждого модуля есть окружение для самостоятельной разработки. Общая оболочка отвечает за маршруты и подключение разделов, пакет платформы — за общие механизмы, дизайн-система — за компоненты и оформление. React, роутер и другие разделяемые зависимости согласованы общей конфигурацией, чтобы модули работали в одном окружении.
Состав выпуска описан в release.json. При загрузке проверяются API модуля, идентификатор, ревизия сборки и требуемые версии платформы. Ошибка загрузки или несовместимость получает предусмотренное состояние интерфейса с возможностью восстановления. Это делает интеграцию модулей управляемой и помогает находить расхождения между сборками.
Команды могут параллельно разрабатывать и собирать свои разделы. Действующая поставка согласует их через описание выпуска; полностью независимые production-релизы потребуют отдельных конвейеров и правил совместимости. Административный интерфейс уже выделен в самостоятельное приложение.
JSON-логи: от обращения пользователя к причине сбоя
Штатный прикладной логгер backend — Pino. По умолчанию он пишет JSON-записи в стандартный вывод процесса. Gateway фиксирует начало и завершение пользовательских HTTP-запросов, статус ответа и длительность; отдельно записываются ошибки внутренних gRPC-вызовов, сбои очередей и события жизненного цикла процессов. Для локальной разработки предусмотрен читаемый режим pretty.
У запроса есть идентификатор: его можно вернуть пользователю и найти соответствующие записи. HTTP-контекст использует поле requestId, диагностика gRPC — request_id; сообщения очередей содержат correlation_id. Если передан контекст трассировки, Gateway также сохраняет traceId. Эти поля помогают сопоставлять события; при подключении общего хранилища их имена следует нормализовать.
Сокращённый пример завершения HTTP-запроса, иллюстрирующий формат:
{"level":30,"requestId":"demo-request-001","method":"GET","url":"/api/v1/me","statusCode":200,"elapsed":18,"msg":"request end"}
По таким полям легко отфильтровать ошибки, медленные ответы или конкретное обращение. Полезный диагностический след охватывает запросы, межсервисные ошибки и фоновую обработку; служебные health-проверки исключены из обычного HTTP-журнала. Аудит административных решений хранится отдельно и позволяет восстановить действие, основание и результат исполнения.
В Gateway и Identity настроено скрытие чувствительных полей, включая пароли и токены. HTTP-хуки Gateway не записывают тела запросов. Подробность журналирования регулируется через LOG_LEVEL; включать в диагностические записи личную переписку и секреты для расследования не требуется.
Как подключить Elasticsearch и Kibana
Структурированный JSON упрощает следующий шаг — централизованный поиск по логам. Предусматриваемая цепочка: логи контейнеров → сборщик, например Filebeat → Elasticsearch → Kibana. Сборщик читает контейнерный поток, разбирает JSON и добавляет контекст окружения, namespace, pod и сервиса; Elasticsearch индексирует записи, Kibana предоставляет поиск и представления.
При настройке нужно сопоставить время и уровни Pino с полями хранилища, унифицировать идентификаторы запросов, определить срок хранения и доступы. После этого можно переходить от роста ошибок в Grafana к записям нужного сервиса за тот же интервал. Формат прикладных логов уже подходит для такого подключения; развёрнутый Elasticsearch/Kibana и доставка логов в него в текущем комплекте инфраструктуры не зафиксированы.
Метрики: видны и операции, и ресурсы
Prometheus собирает показатели приложений и инфраструктуры, а Grafana показывает их вместе. Можно выяснить и то, растёт ли нагрузка на сервер, и то, удаётся ли людям войти, подтвердить почту или завершить административную операцию.
| Группа | Что измеряется | Какой вопрос помогает решить |
|---|---|---|
| Бизнес-операции и безопасность | Регистрации по результату и типу аккаунта, входы, подтверждения email, обновления сессий, отправка служебных писем | На каком шаге пользователь сталкивается с отказом? |
| Административные процессы | Результаты решений, возраст ожидающих действий, ошибки сверки исполнения, операции жизненного цикла аккаунта | Решение оператора дошло до исполнения или зависло? |
| Качество API и коммуникаций | Частота запросов, 4xx/5xx, p95/p99 задержек, ошибки gRPC, WebSocket-соединения и причины закрытия | Где замедлился сценарий или оборвалась связь? |
| Фоновая обработка и данные | Очереди ready/unacked, DLQ, consumers, подключения PostgreSQL, Redis и состояние брокера | Успевают ли обработчики и доступны ли зависимости? |
| Ресурсы | CPU, RSS/heap, event loop, GC, память контейнеров, рестарты, диски, сеть, состояние Kubernetes | Какой ресурс ограничивает работу системы? |
Предметные счётчики уже представлены, например, метриками identity_auth_registrations_total, identity_security_mail_total и backoffice_direct_action_outcomes_total. Это основа наблюдения за бизнес-процессами. Для полной аналитики найма — конверсии из просмотра анкеты в офер, принятие и трудоустройство — потребуется отдельное расширение событий и отчётов.
Практический маршрут при сбое: открыть Overview, уточнить затронутый контур, затем сопоставить его метрики с логами за тот же период. Все десять дашбордов, их назначение и прямые ссылки собраны в разделе Grafana.
Как передать развитие нескольким командам
Основу сопровождаемости дают конкретные договорённости: у сервиса есть владелец данных, у frontend-модуля — контракт подключения, у общей библиотеки — версия, у выпуска — известная ревизия, у сбоя — диагностический след.
Распределение работы может выглядеть так: одна команда ведёт Candidates и инженерный интерфейс, другая — Employers, Opportunities и кабинет компании, третья — Chat, Notifications и модуль коммуникаций. Общую платформу, Identity, контракты и дизайн-систему сопровождают назначенные владельцы. Это пример организации дальнейшей разработки на существующих границах модулей.
Рабочий цикл для команды:
- Согласовать изменение контракта и затронутых потребителей.
- Реализовать задачу в своей ветке; при параллельной работе использовать отдельные worktrees.
- Проверить предметную логику, контракт модуля и связанные пользовательские сценарии.
- Провести ревью, собрать версионированный артефакт и включить его в согласованный выпуск.
- Проверить сценарий на стенде и оценить ошибки, задержки и результаты операций в мониторинге.
В репозиториях уже есть структура для такого цикла: общие пакеты, схемы контрактов, проверки совместимости, тестовые инструменты и манифесты окружений. Следующий организационный шаг — закрепить владельцев, обязательное ревью и автоматические проверки в GitLab CI/CD. Это снижает стоимость передачи задач: новому разработчику можно дать конкретную область, её интерфейсы и критерии готовности.
Роли как часть архитектуры
Разделение ответственности действует и внутри продукта. Тип аккаунта определяет сторону платформы, членство и назначение на вакансию — полномочия в компании, служебные разрешения — доступ оператора, а согласие инженера — объём раскрываемых данных. Эти проверки принадлежат сервисам и действуют независимо от экранных кнопок. Примеры и матрица доступа приведены в ролевой модели.
Администрирование, почта и корпоративная интеграция
Отдельная админка даёт сотрудникам рабочие инструменты: жалобы и поддержку, управление аккаунтами и компаниями, контроль исполнения решений, аудит и выдачу прав. Admin UI и Admin Gateway можно разместить во внутренней сети с доступом через VPN. Сетевое ограничение действует вместе со служебными сессиями и полномочиями.
Почтовый модуль уже включён в сценарии аккаунта: Identity создаёт задание, очередь передаёт его worker, Nodemailer отправляет письмо через SMTP. Шаблоны, ограниченные повторы и метрики помогают сопровождать доставку. На демонстрации письма принимает Mailpit; для рабочей поставки задаётся корпоративный SMTP. Продуктовые email-уведомления и массовые рассылки описаны как дальнейшее расширение.
Для корпоративной среды можно добавить Keycloak или другой совместимый OIDC-провайдер. Предлагаемая интеграция выполняет внешний вход через адаптер, связывает его с аккаунтом Identity и сохраняет внутреннюю модель ролей и сессий. В текущей версии работает собственная email/password-аутентификация; OIDC требует отдельной реализации и проверки.
Основания: исходный код, конфигурация federation и загрузчик packages/platform/src/federation.ts во frontend; logger.ts, HTTP-хуки Gateway, метрики Identity/Backoffice и реестр операторских прав в backend; манифесты мониторинга в infra/k3s/geek-monitoring-np1/.
Архитектура · Ролевая модель · Grafana и мониторинг · Все разделы