Продукт — ProAnima Arkvory, бренд — ProAnimaStudio. Автор и правообладатель — Ian Panaev лично. Репозиторий: https://github.com/ProAnima/Arkvory. Соблюдай LICENSE.md (ADR 0061): продукт бесплатный, код открыт для чтения, но это не open source — использование и изменения внутри организации разрешены, распространение копий и форков, продажа и сервис для третьих лиц запрещены, указание источника обязательно. Не называй продукт «open source», не добавляй открытую лицензию и не меняй условия без явного указания правообладателя.
Это самостоятельный сервис хранения UPack и обычных файлов. Потребители: агенты развёртывания, CI/CD и внешние системы. Исходные данные: 4 ТБ, объекты десятков гигабайт и больше без фиксированного предела размера. Требования и план находятся в docs/PROJECT_PLAN.md.
Перед изменениями прочитай docs/ARCHITECTURE.md, CONTRIBUTING.md и документацию затрагиваемого модуля. Для хранения/очередей также прочитай docs/RELIABILITY.md; для HTTP — docs/API_CONTRACTS.md. Текущее состояние каркаса описано в README; не считай запланированные возможности реализованными.
- TypeScript strict для всего кода продукта. Не ослабляй общий tsconfig ради удобства.
domainне зависит от Node.js, браузера, HTTP, ORM, БД, SDK, конфигурации окружения и часов системы.applicationзависит отdomainи определяет узкие порты внешних зависимостей. Не импортирует конкретные адаптеры.infrastructureреализует порты. HTTP-запросы преобразуют в сценарии приложения серверныеapps/*, а не адаптеры инфраструктуры.- Зависимости собираются в серверных
apps/*. Кодpackages/*не импортируетapps/*; приложения не импортируют друг друга. webи удалённыйcliиспользуютsdkиcontracts.cliвладеет локальными файлами/профилями, не импортирует сервер илиdeploy.sdkиспользует публичные контракты, не БД, внутренние доменные модели или серверный код.- Межпакетные импорты идут через публичный
src/index.tsи имя workspace. Не обходи границы относительными путями и deep imports. - Правила зависимости проверяются
.dependency-cruiser.cjs. При добавлении пакета сначала опиши его роль и явный allowlist; новый пакет по умолчанию не разрешает новые связи.
- SRP: один модуль/сценарий отвечает за конкретное действие; HTTP-обработчик не содержит SQL, разбор ZIP и бизнес-правила одновременно.
- OCP: новые backend и протоколы подключаются через порты и адаптеры. Не добавляй условие по типу хранилища в каждый use case.
- LSP: все реализации одного порта проходят общие контрактные тесты, включая ошибки, отмену и гарантии завершения.
- ISP: отдельные небольшие интерфейсы чтения, публикации, управления сессиями и аудита вместо одного универсального service/repository.
- DIP: интерфейсы принадлежат потребителю; внедряй зависимости явно при создании сценария.
- Предпочитай композицию, чистые функции, небольшие модули и явные состояния. Классы допустимы, но не обязательны.
- Не создавай абстракцию без текущего сценария и причины изменения. Запрещены «базовый репозиторий для всего», скрытый service locator, глобальные изменяемые singleton и папка
utilsкак склад несвязанных правил. - Не дроби проект на новые микросервисы, брокеры и базы без измеренной необходимости и ADR.
- Внешние данные —
unknownдо runtime-валидации. Нельзя считать JSON безопасным из-заas SomeType. - Не используй
any, non-null assertions, отключение lint и TS suppression для обхода ошибок. Необычное поведение стороннего API изолируй типизированным адаптером с причиной рядом с кодом и проверкой поведения. - Ошибки, результаты и состояния должны быть различимыми типами с машинными кодами; переходы состояний явные и исчерпывающие.
- Проверяй целые размеры/смещения; не используй 32-битные побитовые операции для размеров файлов. Полные 64-битные значения сериализуй по контракту, без потери точности.
- Схема wire API отделена от таблиц БД и внутренних объектов домена. Схемы, OpenAPI и SDK должны оставаться согласованными.
- Даты/ID/случайность в правилах передаются зависимостями; тесты не должны зависеть от текущего времени машины.
- Байты файлов проходят потоково с backpressure и AbortSignal. Не загружай большой файл в RAM целиком и не блокируй event loop CPU-затратной обработкой.
- Держи bounded queue и ограничения памяти, staging, числа частей и параллелизма. Любой retry ограничен, безопасен и имеет backoff.
- Опубликованный blob неизменяем. Публикация успешна только после нужного уровня долговечности blob и фиксации метаданных.
- Нет общей транзакции БД/blob-store: нужны идемпотентное завершение, reconciliation и очистка осиротевших объектов.
- Очереди допускают повторную доставку. Используй leases/fencing и идемпотентные операции; не обещай exactly-once транспорт.
- ACL проверяются сервером для каталогов, метаданных и байтов. Хранилище не зависит от доступности клиентских приложений для авторизации.
- Секреты, query keys и transfer tokens не попадают в логи, fixtures и VCS. TLS-проверку не отключать.
- Публичный контракт
/api/v1, OpenAPI и SDK меняются аддитивно либо через ADR. Поддержку проверяй собственными SDK/CLI проекта и фикстурами с известным происхождением. - Миграции БД совместимы с rolling update по expand/contract; деструктивная очистка отделена от выпуска нового кода.
- Определи сценарий, затрагиваемый слой, инварианты и критерии готовности.
- Реализуй минимальный завершённый сценарий; обнови контракт и документацию при изменении поведения.
- Добавь проверки значимых правил, ошибок и отказов. Не добавляй тесты пустых экспортов, которые создают видимость покрытия.
- Запусти
npm run gate -- quickи относящиеся к изменению функциональные гейты. Перед merge обязателен полныйverify, перед релизом —release. Отсутствие БД или браузера — невыполненная проверка, не успешный skip. - Изменения вносятся только через pull request: работай в отдельной ветке, не коммить и не пушь напрямую в
main. Открой PR с описанием сценария и выполненных проверок и дождись зелёного CI. Не вливай PR (merge, squash, rebase, включение auto-merge) без явного подтверждения владельца в чате; одобрение относится к конкретному PR и не переносится на следующие. - Сообщи результат, выполненные проверки и оставшиеся ограничения. Не выдавай каркас, заглушки, local volume или пару API-процессов за работающее HA.
Архитектурные решения, изменяющие границы, долговечность, безопасность или публичный контракт, фиксируй в ADR. Рутинные реализации в согласованных границах не требуют нового разрешения. Описание продукта поддерживаем в двух согласованных версиях: README.md на английском и README.ru.md на русском. Позиционируем Arkvory как самостоятельный продукт; конкретные внутренние приложения не включаем в описание. Инженерные документы и пояснения ведём по-русски, идентификаторы кода — по-английски. Пользовательская документация — сайт wiki/: английский — источник, переводы на все языки консоли меняются в том же коммите; изменили поведение — обновите страницу (WIKI, LOCALIZATION).
- Максимум 500 строк кода на файл, 300 на класс, 100 на функцию/метод; для продукта и scripts. Комментарии и пустые строки исключаются AST-проверкой. Соблюдай Prettier, не уплотняй код ради лимита.
- Существующий долг зафиксирован в config/architecture-exceptions.json. Не увеличивай потолки и не продлевай срок ради прохождения CI. Новое исключение требует конкретной причины, owner, ADR, регрессионных тестов и срока не более 90 дней.
- Рядом с декларацией обязателен комментарий
arkvory-exception ARCH-NNN -- причина; для файла — в начале. При уменьшении размера снижай потолок, при устранении нарушения удаляй исключение. Исключение размера не разрешает нарушение границ или безопасности. - Комментируй неочевидные инварианты: транзакции, ownership/cleanup, порядок блокировок, отмену и идемпотентность. Не дублируй очевидное поведение и имена методов. Для спорной гарантии публичного порта объясни обязанности вызывающей стороны.
- Не используй suppression lint/TS, only/skip/todo и успешный выход вместо отсутствующей инфраструктуры. Все тестовые входы и запуск дочерних helpers должны быть учтены в config/gates.json. Все приёмочные тесты запускай через
npm run gate. - Пакеты, allowlist и порядок сборки определяет config/architecture.json. Новые наборы проверок подключай к verify/release и CI. Политики тоже покрываются регрессионными тестами; не меняй их только ради зелёного статуса.