Заказчик пришёл не с идеей архива, а с работающей системой, сделанной несколько лет назад: около 100 тысяч PDF, сканы и атрибуты к ним,. Отказаться от неё нельзя - в ней лежат архивы клиентов.
Развивать её при этом было невозможно. Внешнего API нет, подключить к архиву что-то ещё нельзя. Любая доработка требовала вмешательства в старый PHP-код, поддержка стоила дорого. Поиск формально работал, но документы попадали в индекс с задержкой и не полностью: файл уже загружен, а найти его ещё нельзя или находится только часть текста.
Мы переписали систему на React, Nest, Redis и PostgreSQL, сохранив данные и рабочий функционал. После этого добавили то, чего в прежней версии не было: OCR с извлечением атрибутов, проверку данных человеком, блокировку одновременного редактирования, журналы аудита, фильтры, статусы документов, роли и доступ к папкам.
Сейчас в системе 113 268 документов и 861 ГБ. Поиск работает по имени файла, по тексту документа и по любым атрибутам проекта: номер, дата, ответственные, название, сумма - набор полей задаётся в проекте, и по ним же строятся фильтры.
Главное, что изменилось для бизнеса: атрибуты больше не набирают руками с нуля. Оператор проверяет и правит то, что извлекла нейросеть. Для компании, которая продаёт оцифровку, ручной ввод - основная статья себестоимости.
- Оператор загружает документы — по одному файлу или пакетом.
- OCR в фоне извлекает текстовый слой и заполняет атрибуты, заданные в проекте.
- Оператор открывает документ в предпросмотре, сверяет извлечённые поля с оригиналом и исправляет ошибки распознавания.
- Документ сохраняется со статусом «Проверено» и дальше участвует в поиске и фильтрах.
- OCR избавляет от ручного ввода. Решение о том, что документ готов, остаётся за человеком.
861 ГБ невозможно загрузить через обычную форму: пользователь уходит со страницы, и загрузка обрывается. Мы вынесли её в фоновый процесс и начали грузить файлы небольшими порциями. Оператор переключается между разделами и продолжает работать, файлы при этом продолжают загружаться. Даже если пропал интернет или произошел сбой на сервере загрузка приостановится на последнем файле и ее можно продолжить.
Статусы и атрибуты в таблице обновляются в реальном времени. Каждый пользователь видит, что происходит с документом прямо сейчас: загружается, обрабатывается OCR, находится на проверке, проверен, ошибка распознавания. Обновлять страницу и уточнять у коллег, кто чем занят, не нужно.
Документ, открытый на редактирование, блокируется для остальных. Когда оператор закрывает документ или переходит к следующему, блокировка снимается. Двое не могут править одну карточку одновременно и перезаписывать чужие правки.
Права распределяются на двух уровнях.
- Системные роли определяют, кто управляет пользователями, проектами и модулем OCR.
- Проектные роли выдаются отдельно для каждого проекта: редактор управляет файлами, пользователями и ролями проекта, оператор работает с файлами и атрибутами документов, читатель видит документы, но не изменяет их.
Отдельно настраивается доступ к папкам: можно указать, кому папка отображается, а кому нет. Документ хранится в архиве, но пользователь без доступа его не увидит.
Это не «настройка безопасности на будущее». В одной системе лежат архивы разных заказчиков, и над ними работают разные группы операторов. Без разделения по проектам и папкам такую систему нельзя отдать в работу.
Если у вас есть архив или система обработки документов, от которой нельзя отказаться и которую сложно развивать, пришлите пример документов. Оценим объём работ и сроки за 2–3 дня.
Прежняя версия работала на PHP, сканы и атрибуты хранились в файловом хранилище. Поиск был, но индексация отставала и покрывала документы не полностью. Задача первого этапа: сохранить сто тысяч файлов и получить систему, которую можно дальше менять.
Переписали интерфейс, серверную часть, очереди задач и деплой: React, Nest, Redis, PostgreSQL с векторным поиском.
Только после переноса подключили AI-ядро и ручную проверку атрибутов - в том порядке, в котором это и планировал заказчик.
Загрузить документы -> дождаться обработки -> открыть карточку -> проверить поля -> сохранить со статусом «Проверено». Дальше документ находится по имени файла, по тексту или через фильтры по атрибутам проекта.
Предпросмотр и поля документа находятся на одном экране: оператор сверяет скан с извлечёнными данными, не переключаясь между разделами. Если OCR ещё не отработал, поля пустые - это видно сразу.
Набор полей свой для каждого проекта: одному нужны номер и дата договора, другому - стороны и сумма. Новое поле создаётся в настройках проекта, там же указывается, участвует ли оно в фильтрах.
К извлечённому значению можно применить правила постобработки: привести даты к одному формату, убрать лишние пробелы, сократить формы собственности. Без этого поиск по «ООО» не найдёт «Общество с ограниченной ответственностью», и часть архива фактически теряется.
Документы загружаются пакетами в фоне, загрузка не прерывается при переходе между страницами. Без этого перенести 861 ГБ в систему было бы невозможно.
Статусы обработки приходят в интерфейс в реальном времени, поэтому несколько операторов работают в одном проекте, не согласовывая действия вручную.
Документ, открытый на редактирование, недоступен для изменения остальным до момента, пока первый оператор его не закроет.
Системные роли действуют на уровне всей системы: пользователи, проекты, модуль OCR. Проектные - только внутри конкретного проекта. Доступ к папкам ограничивает видимость ещё точнее. Читатель не изменяет атрибуты, оператор не раздаёт права, редактору не нужны права администратора системы.
Материал приходит такой, какой есть: часть документов сканируется на месте, часть присылают готовыми файлами - плохого качества, перевёрнутыми, с рукописными пометками и полями. Выбирать входящее качество компания не может, это условие работы.
Поэтому OCR здесь не заменяет человека, а сокращает ему работу. На плохом скане или рукописи атрибут останется пустым или будет распознан с ошибкой, и оператор его поправит. Ради этого в процессе и стоит отдельный шаг проверки со статусом «Проверено»: система рассчитана на то, чтобы проверка занимала минимум времени.