Пошаговый план по созданию веб‑приложения для прайс‑листов и контрактов поставщиков: импорт, валидация, утверждения, продления, аудит и безопасный доступ пользователей.

Большинство проблем с прайсами и контрактами поставщиков выглядят похоже: прайс‑листы живут в прикреплённых к письмам таблицах, «final_FINAL» PDF лежат на шаред‑дисках, и никто до конца не уверен, какие условия актуальны. Результат предсказуем — используются устаревшие цены при заказах, возникают спорные ситуации с поставщиками, и продления проходят незамеченными.
Хорошее веб‑приложение должно централизовать источник правды для прайс‑листов поставщиков и контрактов, и делать изменения полностью трассируемыми. Цели — сократить:
Проектируйте систему вокруг людей, которые работают с ценами и условиями каждую неделю:
Выберите несколько измеримых целей с самого начала:
Для первого релиза стремитесь к централизованным записям о поставщиках, импорту прайс‑листов с валидацией, хранению контрактов с ключевыми датами, базовому утверждению, поиску и аудиту.
Позже можно добавить глубокие интеграции с ERP, библиотеки клаузул, автоматическое сведение счётов, поддержку мульти‑юридических лиц и продвинутые отчёты.
Прежде чем рисовать экраны или таблицы, спланируйте, что реально происходит с момента, когда поставщик присылает прайс‑лист, до момента, когда по нему делают заказ. Это поможет не построить пирожное типа «репозитория документов», когда нужен контролируемый ценовой механизм.
Начните с реального примера вместе с закупками, финансами и юристами. Зафиксируйте передачи и артефакты на каждом шаге:
Простой swimlane‑диаграммы (Supplier → Buyer/Procurement → Legal → Finance → Operations) обычно достаточно.
Перечислите решения, которые меняют бизнес‑результаты, и назначьте владельцев:
Также отметьте, где согласования зависят от порогов (например, рост >5% требует согласования финансов) — эти правила можно закодировать позже.
Запишите точные вопросы, на которые приложение должно отвечать в день запуска:
Эти выходы должны определять поля данных, поиск и отчёты — не наоборот.
Данные закупок грязные. Явно задокументируйте частые исключения:
Отнесите этот список к критериям приёмки для импорта и утверждения, чтобы система поддерживала реальность, а не заставляла обходные пути.
Хорошая архитектура для прайс‑листов и контрактов — это не про модные шаблоны, а про снижение накладных расходов на координацию и готовность к росту.
Для большинства команд лучшая стартовая точка — модульный монолит: одно деплоимое приложение с чётко отделёнными модулями и границами. Это даёт более быструю разработку, проще отлаживать и меньше операционных сложностей.
Переходите к сервисам, только если есть веская причина — например, большие нагрузки на импорт, которые нужно масштабировать отдельно, несколько команд, работающих параллельно, или жёсткая изоляция. Типичный путь: модульный монолит → вынос фоновых задач (import/processing и document) в воркеры → по необходимости выделение высоконагруженных доменов в сервисы.
Если нужно ускорить прототип (экраны, рабочие процессы и RBAC) без долгой разработки, платформы типа Koder.ai помогут сгенерировать каркас React + Go + PostgreSQL по спецификации и быстрее проверить гипотезы с пользователями.
Организуйте приложение вокруг стабильных доменов:
Сохраняйте правила и доступы внутри каждого модуля. Даже в монолите держите границы в коде (пакеты, нейминг и чёткие API между модулями).
Интеграции меняют поток данных, поэтому оставьте явные точки расширения:
Задайте измеримые ожидания заранее:
Чистая модель данных — основа доверия к системе закупок. Когда пользователи спрашивают: «Какая цена была действительна 3 марта?» или «Какой контракт регулировал эту покупку?», база должна дать однозначный ответ.
Начните с небольшого набора хорошо определённых записей:
Смоделируйте связи в соответствии с рабочими сценариями:
Если поддерживаете несколько мест доставки или бизнес‑юнитов, добавьте концепт Scope (компания, площадка, регион), который можно навешивать на контракты и прайс‑листы.
Избегайте редактирования «живых» записей на месте. Вместо этого:
Так проще отвечать на аудиторские вопросы: можно восстановить, что и когда утверждалось.
Держите справочные данные в отдельных таблицах, чтобы избежать свободного текста:
Применяйте уникальные идентификаторы:
Прайс‑листы обычно приходят в таблицах, которые изначально не предназначались для машинной обработки. Удобный импорт — разница между «мы будем пользоваться приложением» и «мы продолжим слать Excel по почте». Цель: загрузки прощают ошибки, но сохранённые данные строги.
Поддерживайте CSV и XLSX с первого дня. CSV удобен для выгрузок ERP и BI; XLSX — то, что чаще отправляют поставщики.
Дайте скачиваемый шаблон, который соответствует вашей модели данных, и включите:
Версионируйте шаблон (Template v1, v2), чтобы развивать его, не ломая процессы.
Явно определите правила сопоставления и покажите их в UI при загрузке.
Обычный подход:
Если разрешаете кастомные колонки, храните их как метаданные, чтобы не загромождать основную схему цен.
Выполняйте проверки до сохранения:
Делайте и валидацию на уровне строки, и валидацию на уровне файла (конфликты с существующими записями).
Хороший опыт импорта выглядит так: Загрузить → Предпросмотр → Исправить → Подтвердить.
На экране предпросмотра:
Избегайте «провалить весь файл из‑за одной строки». Позвольте пользователю выбрать: импортировать только корректные строки или блокировать до исправления всех ошибок, в зависимости от политики.
Для аудита и удобства повторной обработки храните:
Это даёт защищённый след для споров («что мы импортировали и когда?») и позволяет перерабатывать файлы при изменении правил валидации.
Запись контракта должна быть не просто «шкафом файлов». Её задачa — иметь достаточно структурированных данных, чтобы управлять продлениями, утверждениями и отчётностью, при этом сохранять лёгкий доступ к подписанным документам.
Начните с полей, которые отвечают на вопросы, которые часто задают отделы закупок:
Оставляйте свободный текст для крайних случаев, но нормализуйте всё, по чему будете фильтровать, группировать или оповещать.
Обращайтесь с документами как с первоклассными объектами, привязанными к контракту:
Храните метаданные для каждого файла: тип документа, дата вступления в силу, версия, загрузивший и уровень конфиденциальности. Если есть требования по хранению, добавьте поля «хранить до» и «legal hold», чтобы приложение могло блокировать удаление и поддерживать аудит.
Поправки не должны затирать историю. Моделируйте их как датированные изменения, которые либо продлевают сроки (новая дата окончания), либо корректируют коммерческие условия, либо меняют объём.
По возможности фиксируйте ключевые клаузулы в структурированном виде для оповещений и отчётов — например: разрешено расторжение без причины (Y/N), формула индексирования, штрафы за невыполнение, лимит ответственности и эксклюзивность.
Если закупки централизованы, но операции распределены, поддержите привязку одного контракта к нескольким площадкам/бизнес‑юнитам с опциональными переопределениями на уровне площадки (например, адрес выставления счёта, условия доставки). Аналогично, разрешите одному контракту покрывать родительского поставщика и дочерние компании, сохраняя при этом чёткое поле «contracted party» для комплаенса.
Утверждения — это место, где прайс‑листы и контракты становятся обоснованными решениями. Чёткий процесс снижает споры «кто это утвердил?» и даёт повторяемый путь от подачи поставщиком до использования данных в закупках.
Используйте простой, видимый жизненный цикл для прайс‑листов и контрактов:
Draft → Review → Approved → Active → Expired/Terminated
Определите обязанности в приложении (не в головах сотрудников):
Добавьте проверяемые политики, которые автоматически инициируют дополнительные согласования:
Каждое утверждение или отклонение должно фиксировать:
Задайте SLA, чтобы согласования не застревали:
Управление работает лучше, когда оно встроено в поток, а не навязывается задним числом.
Приложение для закупок выигрывает или проигрывает по тому, насколько быстро люди получают ответы на простые вопросы: «Какая текущая цена?», «Какой контракт покрывает эту позицию?» и «Что изменилось за квартал?» Делайте UI вокруг тех рабочих процессов, а не таблиц БД.
Предоставьте два основных входа в верхней навигации:
На страницах результатов используйте фильтры, которые соответствуют реальной работе: дата действия, статус контракта (draft/active/expired), бизнес‑юнит, валюта и «есть ожидающее согласование». Держите фильтры видимыми и съёмными в виде чипов, чтобы не запутывать нетехнических пользователей.
Профиль поставщика — хаб: активные контракты, последний прайс‑лист, открытые споры/заметки и панель «последних действий».
Просмотр контракта отвечает на вопрос «Что нам разрешено покупать, на каких условиях и до какого срока?» Включите ключевые условия (incoterms, условия оплаты), вложения и временную шкалу поправок.
Сравнение прайс‑листов — где пользователи проводят много времени. Показывайте текущий vs предыдущий бок‑о‑бок с:
Отчёты должны быть прагматичны: «истекают через 60 дней», «наибольшие повышения цен», «позиции с несколькими активными ценами». Предлагайте один‑кликовый экспорт в CSV для финансов и PDF для совместного использования/согласований, с теми же фильтрами, что и в интерфейсе.
Используйте понятные метки («Effective date», а не «Validity start»), подсказки для сложных полей (единицы, валюта) и состояния «пусто», которые объясняют следующие шаги («Загрузите прайс‑лист, чтобы начать отслеживание изменений»). Небольшой checklist на /help сократит время обучения.
Безопасность проще, когда она заложена в процесс, а не прикручена позже. Цель для приложений закупок: люди видят и меняют только то, за что они отвечают, и каждая важная правка прослеживается.
Начните с небольшой модели ролей и сопоставьте её с действиями, а не только экранами:
Права должны проверяться на сервере для каждого endpoint. Если организация сложная, добавьте правила по scope (по поставщику, бизнес‑юниту или региону).
Решите заранее, что требует повышенной защиты:
Фиксируйте неизменяемый журнал для ключевых сущностей (контракты, условия, ценовые позиции, утверждения): кто, что изменилось (до/после), когда и источник (UI/import/API). Записывайте имя файла импорта и номер строки, чтобы можно было отследить и исправить ошибки.
Выберите один основной метод входа:
Добавьте разумные политики сессий: короткоживущие токены доступа, защищённые cookies, таймауты неактивности и повторную аутентификацию для чувствительных действий (например, экспорт цен).
Сфокусируйтесь на практичных контролях: принцип наименьших привилегий, централизованное логирование, регулярные бэкапы и проверенные процедуры восстановления. Обращайтесь с журналами аудита как с деловыми записями — ограничьте удаление и определите политику хранения.
Цена редко — просто «одно число». Приложение должно дать однозначный ответ: какая цена сегодня для этой позиции?
Храните цены как временные записи с датой начала и опциональной датой окончания. Позволяйте будущие строки (например, повышение на следующий квартал) и определите, что значит «без даты окончания» (обычно: действительно до замены).
Пересечения обрабатывайте сознательно:
Практическое правило: одна активная базовая цена на поставщик‑позицию‑валюту‑единицу в любой момент; всё остальное — явно отмеченные переопределения.
Если есть несколько кандидатов, задайте порядок приоритета, например:
Если у вас есть предпочтительные поставщики, добавьте поле приоритета поставщика, используемое при мульти‑поставщике для одной позиции.
Решите, хранить ли:
Часто делают и то, и другое: храните цену в исходной валюте и запасную «сконвертированную» величину для отчётов.
Определите нормализацию единиц (шт vs кейс vs кг) и храните коэффициенты конверсии с версионированием. Применяйте правила округления последовательно (десятичные знаки валюты, минимальный шаг цены) и явно указывайте, когда происходит округление: после конверсии единиц, после конверсии валюты и/или при подсчёте итоговой суммы строки.
Продления — место, где теряется стоимость: пропущенные сроки уведомления, молчаливые авто‑продления и срочные переговоры часто приводят к невыгодным условиям. Приложение должно управлять продлениями как процессом с чёткими датами, ответственными и видимыми рабочими очередями.
Моделируйте продление как набор вех, привязанных к контракту (и, опционально, к конкретной поправке):
Стройте напоминания вокруг этих вех. Практический дефолт — cadence 90/60/30 дней до ключевого дедлайна (срок уведомления обычно самый критичный), плюс оповещение в день дедлайна.
Начните с двух каналов:
Опционально поддержите экспорт ICS (по контракту или на пользователя), чтобы владельцы могли подписаться в Outlook/Google Calendar.
Делайте уведомления «действующими»: включайте имя контракта, поставщика, точную дату и глубокую ссылку на запись.
Оповещения должны доставляться:
Добавьте правила эскалации: если первичный не подтвердил за X дней, уведомить резервного или менеджера. Фиксируйте метки «подтверждён/acknowledged», чтобы убрать шум.
Дашборды должны быть простыми, фильтруемыми и ролевыми:
Каждый виджет ведёт к отфильтрованному списку с поиском и экспортом — дашборд должен быть точкой старта для действий, а не только отчётом.
MVP для прайс‑листов и контрактов должен доказать одну вещь: команды могут безопасно загрузить цены, быстро найти нужный контракт и доверять утверждениям и истории аудита.
Стартуйте с полного end‑to‑end потока, а не множества отдельных функций:
Если нужно двигаться быстро с небольшой командой, рассмотрите использование Koder.ai для генерации основы (React frontend, Go backend, PostgreSQL) и итераций в «planning mode» с командами закупок/юристами.
Фокусируйтесь на том, где ошибки дорогие:
Используйте staging с данными, похожими на прод (санитизированными). Требуйте чек‑лист: включены бэкапы, отрепетированы миграции, есть план отката (версионированные миграции БД + откат deploy).
Добавьте мониторинг для сбоев импорта, медленных запросов поиска и узких мест в утверждениях.
Проводите 2–4 недельный цикл обратной связи с закупками и финансами: топ ошибок в импортёх, недостающие поля в контрактах, медленные экраны. Следующие кандидаты: интеграции ERP, портал для поставщиков, аналитика по сбережениям и соответствию.
Suggested internal reads: /pricing and /blog.
Начните с централизации двух вещей: версий прайс‑листов и версий контрактов.
В MVP включите:
Для большинства команд (1–6 инженеров) разумнее начать с модульного монолита: одно деплоимое приложение с четко выделенными модулями (Suppliers, Price Lists, Contracts, Approvals, Reporting).
Для тяжёлых задач вынесите фоновые воркеры (импорт, обработка документов, уведомления) прежде, чем переходить к микросервисам.
Моделируйте минимальный набор:
Ключевые связи:
Не затирайте историю. Используйте версионирование:
Текущая версия определяется запросом: последняя утверждённая версия, действительная на выбранную дату.
Стремитесь к «прощают загрузку, строгим сохранённым данным»:
Храните исходный файл + сопоставление + результаты валидации для аудита и повторной обработки.
Распространные правила валидации:
Если пересечения разрешены (промо/исключения), требуйте причину и согласование.
Держите жизненный цикл явным и согласованным:
Применяйте ту же модель к прайс‑листам и версиям контрактов, чтобы пользователи усвоили один шаблон поведения.
Начните с простой модели ролей и применяйте проверку на стороне сервера:
Добавляйте scope‑политику (по бизнес‑единице/региону/поставщику) при усложнении. Считайте PDF контрактов и банковские реквизиты как данные повышенной чувствительности с более жёстким доступом.
Моделируйте ключевые вехи и делайте уведомления полезными:
Дашборды, которые побуждают к действию:
Каждый виджет должен вести на отфильтрованный список с экспортом.