Контекст и задача
Учётная система ломается не от нагрузки, а от связей
Это мультиарендная ERP: одна кодовая база обслуживает независимых арендаторов, у каждого свои справочники, документы, цены и права доступа.
Пока доменов три, их можно держать в голове. На десяти любое изменение в нормативно-справочной информации задевает продажи, склад и финансы одновременно, и вопрос «кто ещё зависит от этого поля» перестаёт иметь короткий ответ. Именно здесь учётные системы обычно и превращаются в набор доработок поверх доработок.
Вторая сложность в том, что учёт — не CRUD. Документ живёт по правилам: у него есть статус, разрешённый порядок переходов, основание и последствия. Приходная накладная меняет остатки, документ расчётов — состояние взаимоотношений с контрагентом, перемещение — сразу два склада. Если каждый модуль реализует эти правила по-своему, расхождения в отчётах появляются раньше, чем ошибки в коде: формально всё работает, а суммы не сходятся.
Третья — чтение. Операционная запись и поиск по документам конкурируют за одну и ту же базу. Пока пользователь ищет документ за год по десятку фильтров, транзакции ждут; а отказаться от поиска нельзя, потому что именно им и пользуются каждый день.
Отсюда требования, которые мы поставили до первой строки кода:
- держать десять и более доменов в одной кодовой базе, не превращая её в клубок взаимных вызовов;
- дать внешним клиентам один вход, а внутренним сервисам — один контракт, который нельзя нарушить молча;
- развести запись и чтение так, чтобы поиск не влиял на учётные операции;
- изолировать арендаторов на уровне маршрутизации данных, а не на уровне внимательности разработчика;
- сохранять обратимость: любая миграция должна откатываться, иначе выкладка становится необратимым событием.