Files
mono/components/controller
coopops b67581ce80
Typecheck / desktop (pull_request) Failing after 22m0s
Typecheck / controller (pull_request) Successful in 13m37s
fix(extension): atomic jsonb config patch to stop onboarding flag lost-updates
extensions.config is a single jsonb blob shared by every flag/hash the L1
onboarding wizards (capital, chairman) write to. Every write site did the
classic read-modify-write: findByName() the whole row, spread+mutate one key
in app memory, then update() the whole config back. Two DecisionTrackedEvent
handlers firing concurrently (two council decisions tracked near-simultaneously)
each read the same stale snapshot and each write their own flag back — whichever
write lands last wins and silently reverts the other one's flag to its old value.
Symptom hit live: onboarding_generator_program_template_done reverted to false
(with its hash still present, proving the decision really was tracked) after
onboarding_generation_contract_template_done raced it to true.

Added ExtensionDomainRepository.patchConfig(name, patch), implemented as a single
`UPDATE extensions SET config = config || patch::jsonb ... RETURNING *` — no
app-side read before the write, Postgres serializes concurrent UPDATEs on the
row so two different-key patches can no longer clobber each other. Replaced
every config read-modify-write in capital's and chairman's onboarding services
(the events handler's flag write, loadPlugin's init/expire timestamps, the
hash writes in completeStep/completeGeneralMeet, saveProgramDocDataHash) with
this atomic patch. update() is untouched for other callers.

Live data recovered manually: onboarding_generator_program_template_done was
patched back to true for voskhod/capital (hash was already present, confirming
the decision had in fact been tracked before the race reverted the flag).
2026-07-19 07:56:00 +00:00
..
2026-03-23 00:40:49 +05:00
2026-07-14 22:31:19 +03:00
2026-01-20 21:23:02 +05:00
2026-03-23 15:52:27 +05:00
2026-03-19 18:50:42 +05:00
2026-06-24 22:04:51 +05:00
2026-06-24 22:04:51 +05:00
2026-01-23 13:00:24 +05:00

🎛️ @coopenomics/controller

Основной бэкенд-сервис платформы «Цифровой Кооператив». GraphQL API на NestJS с чистой архитектурой — обрабатывает все запросы от рабочего стола, управляет кооперативными процессами, генерирует документы и взаимодействует с блокчейном EOSIO.

Основные возможности

  • GraphQL API для всех операций платформы
  • Чистая архитектура: domain → infrastructure → modules
  • Управление пайщиками, кошельками и финансовыми операциями
  • Электронный документооборот с ЭП через блокчейн
  • Система расширений (extensions) для модульного подключения функциональности
  • Платёжный шлюз с поддержкой нескольких провайдеров
  • JWT-аутентификация и авторизация
  • Миграции данных через TypeORM
  • Интеграция с Novu для уведомлений и LiveKit для видеоконференций

Установка

Компонент является частью монорепозитория. Установка зависимостей из корня проекта:

pnpm install

Или только для этого компонента:

pnpm install --filter @coopenomics/controller

Скрипты

Скрипт Команда Описание
dev pnpm run dev Запуск в режиме разработки (nodemon + ts-node)
start pnpm run start Запуск в production-режиме
lint pnpm run lint Проверка кода (ESLint)
lint:fix pnpm run lint:fix Автоисправление lint-ошибок
typecheck pnpm run typecheck Проверка типов TypeScript
migration:generate pnpm run migration:generate Генерация новой миграции
migration:run pnpm run migration:run Применение всех миграций
migration:status pnpm run migration:status Текущий статус миграций
migration:rollback pnpm run migration:rollback Откат миграций
migration:list pnpm run migration:list Список всех миграций
docs pnpm run docs Генерация документации API (SpectaQL)

Конфигурация

Скопируйте .env-example в .env и настройте переменные окружения:

  • Строки подключения к MongoDB, реляционной БД, Redis
  • Endpoint блокчейн-ноды и CHAIN_ID
  • VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY — ключи для push-уведомлений
  • Настройки JWT-аутентификации
  • Конфигурация платёжных провайдеров
  • Настройки Sentry для мониторинга ошибок

Подробное описание переменных — в файле .env-example.

Тестирование

Интеграционные тесты выполняются через компонент @coopenomics/boot, который разворачивает полную инфраструктуру:

pnpm --filter @coopenomics/boot run test

Архитектура

Проект следует принципам чистой архитектуры с направлением зависимостей внутрь (к домену):

src/
├── domain/                # Доменный слой (бизнес-логика)
│   ├── account/           # Аккаунты пользователей
│   ├── agreement/         # Соглашения
│   ├── auth/              # Аутентификация
│   ├── blockchain/        # Интерфейсы блокчейна
│   ├── branch/            # Кооперативные участки
│   ├── capital/           # Паевые взносы
│   ├── cooplace/          # Маркетплейс
│   ├── document/          # Документооборот
│   ├── extension/         # Расширения
│   ├── gateway/           # Платёжный шлюз
│   ├── ledger/            # Бухгалтерский учёт
│   ├── meet/              # Собрания
│   ├── participant/       # Участники кооператива
│   ├── registration/      # Регистрация
│   ├── wallet/            # Кошельки
│   └── common/            # Общие порты и репозитории
├── infrastructure/        # Инфраструктурный слой (адаптеры)
│   ├── blockchain/        # Адаптер блокчейна EOSIO
│   ├── database/          # Адаптеры БД (Mongoose, TypeORM)
│   └── external/          # Внешние сервисы
├── modules/               # Прикладной слой (NestJS-модули)
│   ├── auth/              # Модуль аутентификации
│   ├── cooperative/       # Модуль кооператива
│   └── ...                # Остальные модули
└── extensions/            # Система подключаемых расширений
    ├── extensions.registry.ts
    └── base.extension.module.ts
migrations/                # Миграции данных (TypeORM)

Поток данных

  1. Резолвер принимает входные данные и передаёт в сервис
  2. Сервис вызывает интерактор домена, передавая DTO (реализующие доменный интерфейс)
  3. Интерактор выполняет бизнес-логику и взаимодействует с портами
  4. Адаптеры (инфраструктура) преобразуют доменные объекты в формат внешних систем
  5. Результаты возвращаются обратно по цепочке

Ключевые зависимости

  • @nestjs/* — фреймворк бэкенда
  • graphql / @nestjs/graphql — GraphQL API
  • mongoose — MongoDB ODM
  • typeorm — реляционный ORM с миграциями
  • eosjs — взаимодействие с блокчейном EOSIO
  • ioredis — Redis-клиент
  • @novu/api — сервис уведомлений
  • livekit-server-sdk — видеоконференции
  • winston — логирование

Лицензия

BY-NC-SA 4.0