AAYMA
RU
Войти

OptiStock

Fullstack-агент закупок для Электрокомплекта: импортирует 12 XLSX по IEK и Systeme Electric, прогнозирует спрос с сезонностью и трендом…

Доведённый продукт
Команда «AIM» 17💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: AIM
Кейс HackAlem.ai: Логистика — Электрокомплект · ekt.kz
Стадия: Доведённый продукт

Задача кейса: Автоматический расчёт заказов поставщикам для пополнения склада, с утверждением менеджером

Суть

Fullstack-агент закупок для Электрокомплекта: импортирует 12 XLSX по IEK и Systeme Electric, прогнозирует спрос с сезонностью и трендом, рассчитывает рекомендуемые заказы по поставщикам. Менеджер правит количества с указанием причины, утверждает заказ и выгружает CSV.

Как устроено

Адаптеры Excel загружают продажи, остатки, товары в пути, MOQ и сезонность в версионированный набор в PostgreSQL; происхождение данных отслеживается до строки и колонки. Детерминированная модель robust-seasonal-v1 учитывает сезонность, тренд, сценарный рост, выбросы, потерянный спрос, MOQ/кратность и поступления, а затем готовит черновики заказов с объяснениями. Утверждённые заказы попадают в следующий расчёт как ожидаемые поступления. Фоновые задачи идут через таблицу jobs (FOR UPDATE SKIP LOCKED, lease), есть бэктест. Опциональный OpenAI-ассистент в цикле tool calling только объясняет уже посчитанные числа.

Ключевые решения

  • сезонный прогноз robust-seasonal-v1
  • обработка выбросов
  • оценка потерянного спроса (stockout)
  • округление по MOQ/кратности
  • бэктест
  • tool calling
  • очередь FOR UPDATE SKIP LOCKED
  • идемпотентность

Особенности

Полный цикл согласования: ревизии, аудит, идемпотентность и проверка актуальности плана. Утверждённые заказы возвращаются в расчёт как обязательства перед поставщиками. LLM отделён от расчёта и только вызывает серверные инструменты. Интерфейс на трёх языках: EN, RU, KZ.

Стек

Python · FastAPI · PostgreSQL 17 · SQLAlchemy · Alembic · openpyxl · React 19 · TypeScript · Vite · Recharts · Docker Compose · Nginx · pytest · Playwright · GitHub Actions

Модели

OpenAI API


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-32f862cb-aim.

README

README.md

OptiStock

Планирование закупок с объяснимыми рекомендациями

От Excel-выгрузок до согласованного заказа поставщику.

Python FastAPI PostgreSQL Docker React Status

Кейс «Электрокомплект» · HackAlem AI · IEK / Systeme Electric

О проекте · Архитектура · Установка · API · Демо


Текущая версия — fullstack MVP. Основной экран — Procurement agent (/agent): импорт, проверка данных, расчёт и подготовка черновиков. React-интерфейс доступен на English / Русский / Қазақша. Утверждение выполняет менеджер; поставщикам заказы не отправляются. Расчёт детерминированный и работает без внешних AI-ключей. Поверх него — необязательный AI-ассистент на OpenAI: он объясняет уже посчитанные числа и вызывает серверные инструменты, но не рассчитывает и не утверждает заказы.

Навигация по README

О проекте

OptiStock помогает закупщику определить, какие товары и в каком количестве заказать. Система объединяет продажи, остатки, товары в пути, сезонность и ограничения закупки, рассчитывает потребность по датам и сохраняет объяснение каждого решения.

Менеджер проверяет исходные данные, изменяет количество с указанием причины, передаёт заказ на утверждение и выгружает согласованную ревизию в CSV. Утверждённые заказы учитываются в следующих расчётах как ожидаемые поступления.

ВозможностьРеализация
Агент закупокЕдиный запуск проверки, очистки, расчёта, анализа рисков и подготовки черновиков
ИнтерфейсReact 19, три языка, графики, история запусков и согласование заказов
ИмпортКомплект из 12 XLSX и загрузка через API; адаптеры IEK и Systeme Electric
КаталогПоиск по коду и названию, фильтры поставщика и категории, история и исходные операции
ПланированиеСезонность, тренд, сценарный рост, обработка выбросов и оценка потерянного спроса
ОбъясненияДневная проекция, запас, поступления, поправки, округление и происхождение данных
ЗаказыЧерновики по поставщикам, правки с причиной, ревизии, утверждение и отмена
ЭкспортCSV с количествами в складских и закупочных единицах
ДоступПерсональные API-ключи, четыре серверные роли, отзыв ключей
НадёжностьОчередь в PostgreSQL, повторные попытки, идемпотентность, проверка актуальности плана
АудитИстория импорта, расчётов и действий с заказами, включая экспорт

Технологический стек

СлойТехнологии
ЯзыкPython ≥ 3.12; Docker использует Python 3.13
FrontendReact 19, TypeScript strict, Vite, React Router, Recharts, Lucide
HTTP APIFastAPI, Uvicorn, Pydantic / pydantic-settings
ХранениеPostgreSQL 17, SQLAlchemy 2, psycopg 3, JSONB
МиграцииAlembic
Excelopenpyxl, defusedxml
Фоновые задачиСобственный worker и таблица jobs в PostgreSQL
Проверкиpytest, httpx, Ruff, GitHub Actions
РазвёртываниеDocker Compose и постоянные volumes

Версии зависимостей закреплены в requirements.lock. Redis, Celery и отдельный брокер сообщений для текущего MVP не требуются.

Исходные данные

Работаем с файлами задания, а не подтверждёнными текущими данными компании. Отдельный синтетический Demo workspace обозначен в интерфейсе.

В репозитории находятся IEK/ и Systeme electric/ — по шесть тестовых XLSX. Дата среза по умолчанию — 22 сентября 2026 года. Дополнительные выгрузки для демонстрации не нужны.

ИсточникИспользование
Месячные продажиОсновной временной ряд спроса
Динамика продаж / документыДетализация операций и проверка аномальных крупных покупок
Месячные остаткиИстория запасов и сценарная оценка stockout
MOQМинимальный заказ и доступные ограничения кратности
Товары в путиПоступления с датами; для Systeme также свободный остаток и категория
СезонностьНормированный месячный профиль поставщика по завершённым годам

Импорт привязан к формату этих выгрузок. Произвольный XLSX с другими колонками не является поддерживаемым источником. Адаптер выбирает лист TDSheet, если он есть, иначе первый лист; тип определяет по заголовкам и, для месячных таблиц, имени файла. Формулы Excel не исполняются: читаются сохранённые значения.

flowchart LR
    A[12 XLSX] --> B[Импорт и проверка]
    B --> C[Версия набора данных]
    C --> D[Расчёт сценария]
    D --> E[Рекомендации и объяснения]
    E --> F[Черновики по поставщикам]
    F --> G[Правка с причиной]
    G --> H[Утверждение]
    H --> I[CSV]
    H --> J[Обязательства по поставкам]
    J --> D

Повторный импорт одинакового комплекта с той же датой среза переиспользует набор. Каждый новый расчёт сохраняет отдельный план с параметрами и версией алгоритма. Исходные файлы хранятся по SHA-256. Происхождение данных включает файл, лист, строку и, где предусмотрено, колонку.

Архитектура

flowchart TB
    Browser[Браузер] -->|HTTP :5173| Frontend[React / Nginx или Vite]
    Frontend -->|Proxy /api| API[FastAPI]
    Client[Swagger / HTTP-клиент / demo.py] -->|HTTP :8000| API
    Samples[IEK / Systeme electric] -->|read-only mount| API
    API -->|Данные, задания, аудит| DB[(PostgreSQL 17)]
    API -->|Сохранение XLSX| Files[(Volume documents)]
    Worker[Worker] -->|Захват задач и продление lease| DB
    Worker --> Child[Отдельный процесс задачи]
    Files -->|Чтение исходников| Child
    Child --> Import[Адаптеры Excel]
    Child --> Calc[Модель robust-seasonal-v1]
    Import -->|Атомарная запись результата| DB
    Calc -->|Атомарная запись результата| DB
    Migrate[Alembic migrate] -->|Обновление схемы| DB

Сервисы Docker Compose

СервисНазначениеДоступ с хоста
frontendReact SPA через Nginx; проксирует /api/ к API127.0.0.1:5173
dbPostgreSQL; при первой инициализации создаёт optistock, optistock_test и роль приложения127.0.0.1:5435
migrateОднократно выполняет alembic upgrade head после готовности БДНет
apiАвторизация, HTTP API, постановка заданий, операции с заказами127.0.0.1:8000
workerВыполняет импорт и расчёт после успешных миграцийНет

API и worker используют один образ, одну БД и общее файловое хранилище. Excel не включён в образ: API получает исходный комплект через read-only mounts и копирует его в documents. PostgreSQL сохраняет данные в volume database.

Выполнение задач

Импорт и расчёт асинхронны: API возвращает 202 Accepted и job_id, клиент опрашивает GET /api/v1/jobs/{id}.

  • Статусы задачи: queued → running → succeeded либо failed. Для набора и плана успешный статус называется ready.
  • Worker захватывает задачу через FOR UPDATE SKIP LOCKED и получает ограниченное по времени право её обработки — lease.
  • По умолчанию lease действует 60 секунд и продлевается; лимит задачи — 900 секунд, число попыток — 3.
  • Каждая задача запускается в отдельном процессе. Перед публикацией проверяются token и срок lease: старый процесс не может перезаписать результат после перехвата задачи.
  • Результат и статус успеха записываются одной транзакцией. Частично импортированный набор не становится готовым.
  • Временные ошибки повторяются в пределах лимита; ошибки данных завершают задачу. Для failed доступен ручной retry через API.

Модель хранения

ТаблицаСодержимое и связи
credentialsИмя, роль, SHA-256 ключа, активность
datasetsДата среза, сигнатура комплекта, статус и сводка
source_filesФайлы набора: поставщик, имя, SHA-256, тип
itemsСнимок SKU; уникальная комбинация dataset_id + supplier + code; история и источники в JSONB
plansНабор, сценарий, версия алгоритма, сводка и версии обязательств поставщикам
recommendationsКоличество, риск, дата поставки и объяснение по товару
agent_runsЗапуск агента, связь с планом и сохранённый отчёт
jobsОчередь, прогресс, попытки, lease, token и ошибка
purchase_ordersЗаказ по паре план/поставщик, статус, ревизия, авторы, дата поставки
order_linesРекомендованное и выбранное количество, причина правки
supplier_statesРевизия обязательств поставщику для проверки актуальности плана
idempotencyРезультаты изменяющих запросов и хеши их тела
audit_eventsАвтор, действие, объект, время, детали

MOQ, количества и остатки в БД используют Numeric(20, 4). История, сценарии и объяснения хранятся в JSONB. Права, ревизии и транзакционные блокировки проверяются сервером.

Структура репозитория

.
├── backend/optistock/
│   ├── api.py                 # HTTP endpoints, авторизация, ошибки, CSV
│   ├── schemas.py             # Входные схемы и параметры сценария
│   ├── services.py            # Импорт, планы, заказы, идемпотентность, аудит
│   ├── ingestion.py           # Проверка XLSX и адаптеры поставщиков
│   ├── agent.py               # Проверки, этапы и отчёт агента
│   ├── assistant.py           # Цикл function calling OpenAI и сохранение ответов
│   ├── tools.py               # Серверный реестр инструментов AI с валидацией аргументов
│   ├── backtest.py            # Историческая оценка прогноза
│   ├── planning.py            # Детерминированная модель расчёта
│   ├── worker.py              # Очередь, lease, повторы, процессы задач
│   ├── models.py              # SQLAlchemy-модели PostgreSQL
│   ├── db.py                  # Подключение и сессии БД
│   ├── config.py              # Настройки из окружения и .env
│   ├── middleware.py          # Ограничение размера HTTP-запроса
│   ├── errors.py              # Доменные ошибки
│   ├── cli.py                 # Создание и отзыв API-ключей
│   └── __init__.py            # Версия пакета
├── frontend/                  # React, TypeScript, Vite, Nginx и Playwright
├── migrations/                # Alembic и миграция схемы
├── scripts/
│   ├── configure.py           # Генерация .env со случайными паролями
│   ├── demo.py                # Сквозной сценарий через HTTP API
│   ├── local_dev.py           # Полный локальный стек Windows без Docker
│   ├── jury_demo.py           # Демонстрация для жюри
│   ├── backtest.py            # Запуск исторической проверки
│   └── test.py                # Миграции, pytest и проверка схемы
├── tests/                     # Расчёт, импорт, API, ограничения, конкуренция
├── docker/
│   ├── Dockerfile.db          # Образ PostgreSQL
│   └── init-db.sh             # Создание роли и двух БД
├── IEK/                       # 6 исходных XLSX
├── Systeme electric/          # 6 исходных XLSX
├── .github/workflows/frontend.yml # Проверки frontend в CI
├── .env.example               # Пример конфигурации без реальных секретов
├── Dockerfile                 # Образ API и worker
├── compose.yaml               # Сервисы, volumes, healthchecks, лимиты
├── alembic.ini                # Настройки миграций
├── pyproject.toml             # Пакет, CLI, pytest и Ruff
├── requirements.lock          # Зафиксированные зависимости
├── README.md                  # Основная документация
└── *.md                       # Кейс, архитектурные материалы и проверки

Локально появляются .env, .venv/ и var/ — ключи, файлы, выгрузки и отчёты. Эти рабочие файлы исключены из Git.

Интерфейс и быстрый запуск для жюри

Для жюри: проверка за несколько минут

  1. Запустить проект по одной из инструкций ниже. Открыть Procurement agent.
  2. При первом запуске нажать Загрузить материалы кейса; для своих файлов использовать Импорт Excel с форматом IEK/Systeme. Дождаться завершения импорта.
  3. Выбрать набор данных, поставщика/категорию, срок поставки, цикл, страховой запас и рост. Нажать Запустить агента.
  4. Проверить этапы, показатели, вкладки Требуют внимания и Разовые всплески. Нажатие на SKU открывает числовое объяснение и источники.
  5. Нажать Проверить заказ, изменить количество с причиной, сохранить и нажать Approve order, затем Export CSV. Закрыть и снова открыть страницу: расчёты и заказы сохранены в PostgreSQL.

Проверенный исходный сценарий: 491 позиция к пополнению (IEK 335, Systeme 156), 162 риска дефицита, 241 поправка по товарам в 231 уникальном документе у 190 SKU. Импорт и работа агента — 25,5 с в одном локальном замере. Полный браузерный тест с правкой, утверждением и экспортом также выполнен. Доказательства и ограничения: VERIFICATION.md, CASE_EVIDENCE.md. Трёхминутная демонстрация и текст для сдачи.

Быстрый запуск на Windows без Docker

Требуются Python 3.12+, Node.js 24 и установленные бинарники PostgreSQL в C:\Program Files\PostgreSQL\…\bin. Проверено с Python 3.13 и PostgreSQL 18.6.

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.lock
.\.venv\Scripts\python.exe -m pip install --no-deps -e .
Push-Location frontend
npm.cmd ci
Pop-Location
.\.venv\Scripts\python.exe scripts/local_dev.py

Открыть http://127.0.0.1:5173/agent. Скрипт создаёт отдельный кластер в var/local/postgres, базы optistock и optistock_test, применяет миграции и запускает API, worker, frontend. Системная PostgreSQL-служба и существующие базы не изменяются. Порты: 5435 / 8000 / 5173. Логи и PID — var/local/; повторный запуск сохраняет данные.

Локальный ключ хранится на сервере в var/local/api-key; браузер обращается через dev proxy без получения ключа. Этот режим включается только локальным .env.local, проверяет origin/host и не включается в production-сборку. Если ранее выбран Demo workspace, на странице агента нажать Подключить локальный сервер. Для Docker и внешних API используются персональные ключи через Settings.

Технологии и архитектура

React 19, TypeScript strict, Vite, Recharts; Python/FastAPI, Pydantic, openpyxl; PostgreSQL, SQLAlchemy и Alembic. Очередь задач находится в PostgreSQL, отдельный worker выполняет импорт и расчёт. API выдаёт результаты React-интерфейсу. Исходные файлы хранятся по SHA-256; каждый план фиксирует параметры, объяснения и версии обязательств.

Агент — исполняемый workflow из проверяемых инструментов: проверка → очистка → расчёт → риски → черновики. LLM не генерирует закупочные количества. Результат, журнал агента и черновики публикуются одной транзакцией; повторы защищены идемпотентностью и lease/token. Утверждение — отдельная операция менеджера с проверкой роли и ревизии.

Проект разработан с AI-агентом Codex, включая реализацию и автоматические проверки. Для планирования, импорта и заказов внешние платные API, ключи и GPU не нужны — весь расчёт выполняется локально. Серверный ключ OpenAI требуется только разделу «AI-ассистент»; без него остальные функции работают в полном объёме. Публичная deployed-версия пока отсутствует; адрес выше — локальный. Репозиторий команды: BAITC-Hacks/hack-32f862cb-aim.

React-интерфейс

Переключение English / Русский / Қазақша доступно в верхней панели и настройках. Выбор сохраняется в браузере; переведены все страницы, формы, статусы, графики и объяснения агента. Данные товаров и исходные документы сохраняют оригинальные названия. Подробнее: frontend/README.md.

cd frontend
npm.cmd ci
npm.cmd run dev

Открыть http://localhost:5173. Нужен Node.js 24; в Linux/macOS используйте npm вместо npm.cmd. По умолчанию доступен интерактивный деморежим. Для работы с бэкендом: Settings → API address /api/v1 → API access key → Connect workspace.

Реализованы Dashboard, Inventory, Suppliers, Orders, Forecast, Analytics, Reports и Settings. Полная инструкция, особенности данных и проверки: frontend/README.md.

Не запускайте Vite, локальный стек и Docker frontend одновременно на порту 5173. Для Docker API подключение задаётся в Settings; локальный скрипт на Windows настраивает dev proxy. Синтетический Demo workspace позволяет изучить интерфейс без сервера, но запуск агента требует работающего API и worker.

Setup & Installation

Все команды выполняются из корня репозитория. Для запуска в Docker нужны Git, Docker с Compose v2 и Python 3 для генератора .env. Для локальной разработки и demo нужен Python 3.12+; версия 3.13 совпадает с Docker.

1. Получить проект

git clone https://github.com/BAITC-Hacks/hack-32f862cb-aim.git
cd hack-32f862cb-aim

Если репозиторий уже открыт локально, используйте его текущую папку.

2. Запустить сервисы

python scripts/configure.py
docker compose up -d --build
docker compose ps -a

Frontend будет доступен на http://localhost:5173/agent. Node.js на хосте для Docker-запуска не требуется.

На Linux/macOS при необходимости используйте python3 вместо python. Генератор создаёт случайные пароли и сохраняет существующий .env без изменений. .env.example содержит заглушки; для первого запуска предпочтителен генератор.

db должен стать healthy, migrate — завершиться с кодом 0, api — стать healthy, worker — остаться запущенным. Завершившийся migrate — нормальное состояние.

АдресНазначение
http://localhost:5173/agentProcurement agent: основной рабочий экран
http://localhost:8000/docsSwagger UI: схемы и интерактивные запросы
http://localhost:8000/redocReDoc: справочник API
http://localhost:8000/openapi.jsonOpenAPI-схема
http://localhost:8000/health/liveПроцесс API отвечает
http://localhost:8000/health/readyДоступна БД и читается таблица Alembic

Readiness не проверяет worker и не сравнивает ревизию БД с последней миграцией. Корневой маршрут / не определён; для начала откройте /docs.

3. Создать API-ключ

Ключ показывается только при создании; в БД хранится его SHA-256. Для полного локального демо нужна роль admin.

Windows · PowerShell
New-Item -ItemType Directory -Force var | Out-Null
docker compose exec -T api optistock create-key --name demo-admin --role admin | Set-Content -Encoding ascii var/admin.key

ASCII сохраняет ключ без BOM и подходит для чтения scripts/demo.py.

Linux / macOS · Bash
mkdir -p var
(umask 077; docker compose exec -T api optistock create-key --name demo-admin --role admin > var/admin.key)

В Swagger нажмите Authorize и вставьте содержимое var/admin.key без префикса Bearer. Проверить роль можно через GET /api/v1/me.

Для других пользователей создавайте отдельные ключи:

docker compose exec api optistock create-key --name buyer --role planner
docker compose exec api optistock create-key --name manager --role approver
docker compose exec api optistock create-key --name observer --role viewer

Отзыв: docker compose exec api optistock revoke-key --name buyer. Имя уже созданного ключа нельзя использовать повторно, включая отозванные ключи. При повторной установке сохраняйте существующий var/admin.key; для нового ключа выбирайте новое имя и файл.

4. Установить окружение для demo и разработки

Windows · PowerShell
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.lock
.\.venv\Scripts\python.exe -m pip install --no-deps -e .
Linux / macOS · Bash
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.lock
.venv/bin/python -m pip install --no-deps -e .

Активация venv не обязательна: команды ниже используют исполняемые файлы окружения напрямую.

Локальная разработка: API и worker вне Docker

Можно оставить в Docker только PostgreSQL. Остановите контейнерные API и worker, если ранее запускали полный стек:

docker compose stop api worker frontend
docker compose up -d db

После готовности БД выполните миграции, затем запустите API и worker в разных терминалах:

ДействиеWindows PowerShellLinux / macOS
Миграции.\.venv\Scripts\alembic.exe upgrade head.venv/bin/alembic upgrade head
API, терминал 1.\.venv\Scripts\uvicorn.exe optistock.api:app --reload.venv/bin/uvicorn optistock.api:app --reload
Worker, терминал 2.\.venv\Scripts\python.exe -m optistock.worker.venv/bin/python -m optistock.worker
Ключ при необходимости.\.venv\Scripts\optistock.exe create-key --name local-admin --role admin.venv/bin/optistock create-key --name local-admin --role admin

Запускайте процессы из корня проекта: они должны читать один .env и одно хранилище var/files. Ключи остаются действительными при использовании той же БД.

Локальный и контейнерный worker не должны одновременно обрабатывать очередь с разными файловыми хранилищами. Если набор ранее импортировали в Docker, его файлы находятся в volume documents. Для локальной обработки нужен доступ к тем же исходникам; sample-комплект можно повторно импортировать через локальный API, чтобы скопировать файлы в локальное хранилище.

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

Настройки читаются из переменных окружения и .env с префиксом OPTISTOCK_. Переменные окружения имеют приоритет. Пароли и API-ключи не добавляйте в Git.

ПеременнаяЗначение по умолчанию / назначение
POSTGRES_PASSWORDПароль администратора PostgreSQL для Compose; генерируется скриптом
OPTISTOCK_DB_PASSWORDПароль роли optistock для инициализации и подключения контейнеров
OPTISTOCK_DATABASE_URLURL postgresql+psycopg://…; генератор задаёт localhost:5435/optistock, Compose — db:5432/optistock
OPTISTOCK_TEST_DATABASE_URLURL отдельной БД с суффиксом _test для тестового скрипта
OPTISTOCK_STORAGE_ROOTvar/files локально; /app/var/files в контейнере
OPTISTOCK_SAMPLE_ROOT. локально; /samples в контейнере
OPTISTOCK_CORS_ORIGINSJSON-массив, по умолчанию ["http://localhost:5173"]
OPTISTOCK_UPLOAD_MAX_BYTES26214400: 25 МиБ на файл
OPTISTOCK_XLSX_MAX_UNCOMPRESSED_BYTES262144000: 250 МиБ распакованного XLSX
OPTISTOCK_XLSX_MAX_ROWS400000: лимит строк
OPTISTOCK_LEASE_SECONDS60, минимум 10
OPTISTOCK_JOB_TIMEOUT_SECONDS900, минимум 30
OPTISTOCK_MAX_ATTEMPTS3, диапазон 1–10
OPTISTOCK_OPENAI_API_KEYСерверный ключ OpenAI. Пусто — раздел AI отключён, остальное работает
OPTISTOCK_OPENAI_MODELgpt-5.4-mini-2026-03-17
OPTISTOCK_AI_TIMEOUT_SECONDS45, диапазон 5–120: таймаут одного обращения к провайдеру
OPTISTOCK_AI_REQUESTS_PER_HOUR30, диапазон 1–300: лимит вопросов на пользователя
OPTISTOCK_AI_MAX_STEPS6, диапазон 1–12: ходов модели в одном цикле инструментов
OPTISTOCK_AI_MAX_TOOL_CALLS12, диапазон 1–40: вызовов инструментов за запрос
OPTISTOCK_AI_TOTAL_SECONDS180, диапазон 10–600: общее время одного AI-запроса
OPTISTOCK_AI_TOKEN_BUDGET120000: суммарный лимит токенов запроса

Compose явно передаёт URL БД, пути, CORS и настройки worker. Чтобы изменить лимиты XLSX в контейнерах, добавьте соответствующие переменные в общий блок x-app.environment в compose.yaml: одна запись в .env не передаёт их автоматически.

Дополнительные ограничения: HTTP-запрос до 50 МиБ, от 1 до 12 файлов на upload, уникальные имена XLSX до 250 символов, до 2000 записей ZIP-архива, до 256 колонок и 20 млн ячеек таблицы. XLSX с VBA-макросами отклоняется.

Алгоритм и сценарии

Версия модели — robust-seasonal-v1. Для каждой рекомендации сохраняются допущения и числовое разложение результата.

  1. Используются завершённые месяцы продаж до даты среза; неполный текущий месяц исключается. Базовый дневной спрос рассчитывается по последним доступным месяцам, максимум по 12.
  2. Крупные документы корректируются только при согласовании транзакций с месячным итогом. При восьми и более документах порог берётся по log-MAD распределения документов; на более коротких историях применяется консервативный резервный порог по медиане месячных продаж, а истории короче четырёх результативных месяцев помечаются insufficient_history_for_outlier_detection вместо догадки. Повторяющийся крупный спрос консервативно сохраняется. Транзакции не прибавляются к месячным продажам.
  3. При включённой оценке stockout спрос корректируется по нулевым месячным снимкам запасов. Это приближение с сохранённым предупреждением.
  4. Применяется сезонный профиль; тренд используется при согласии сравнений за 3 и 6 месяцев с прошлым годом. Сценарный рост задаётся отдельно.
  5. Строится дневная проекция спроса, запаса и поступлений, включая утверждённые заказы. Поздняя поставка не закрывает предшествующий дефицит.
  6. Рассчитывается потребность с даты новой поставки до конца горизонта и страховой остаток. Заказ округляется по MOQ, кратности и закупочным единицам.
Горизонт = lead_time_days + review_days
Дата новой поставки = as_of + lead_time_days
Страховой запас = прогноз спроса на safety_days после горизонта

Потребность = max(0,
                 максимальный дефицит с даты новой поставки,
                 страховой запас − остаток на конец горизонта)

При положительной потребности:
Закупочные единицы = ceil(max(потребность / conversion, MOQ) / multiple) × multiple
Складские единицы = закупочные единицы × conversion

Потерянные продажи до прихода новой поставки учитываются отдельно и не превращаются в отложенный заказ. Без месячной истории количество заказа равно нулю, статус — insufficient_data.

Поля scenario

ПолеПо умолчаниюДопустимые значения / смысл
suppliernullВсе поставщики либо iek / systeme
categorynullИсходный код категории, до 80 символов
lead_time_days30Срок поставки, 1–180 дней
review_days30Период пересмотра, 1–90 дней
safety_days14Страховое покрытие, 0–90 дней
category_safety_days{}До 50 кодов категорий со значениями 0–90; пример: {"1":21,"7":7}
growth_percent0Сценарный прирост от −50 до 200 %
remove_outlierstrueКоррекция аномальных крупных документов
estimate_stockoutstrueОценка потерянного спроса по остаткам
use_seasonalitytrueПрименение сезонного профиля
use_trendtrueПрименение согласованного тренда
blank_monthly_sales_as_zerotrueПустые месячные значения считать нулём; при false исключать
missing_inventorylatest_snapshotПоследний доступный снимок; альтернатива — zero
default_minimum"1"MOQ при отсутствии данных, 0 < x ≤ 1000000
default_multiple"1"Кратность при отсутствии данных, 0 < x ≤ 1000000
cable_reel_meters"305"Длина бухты для отмеченных кабелей, 0 < x ≤ 10000

Для трёх десятичных параметров разрешено до четырёх знаков после запятой. Неизвестные поля JSON-запросов отклоняются. Коды категорий используются как в источнике: система не объявляет их ABC-классами без расшифровки.

Статусы рекомендаций

riskЗначение
criticalОжидается потеря продаж до даты новой поставки
reorderТребуется закупка, дефицита до поставки модель не обнаружила
coveredПо сценарию дополнительная закупка не требуется
insufficient_dataНет месячной истории для расчёта

В подробном explanation доступны сценарий, источник запаса, базовый спрос, сезонность, тренд, прогноз, страховой запас, исходная потребность и округлённый заказ. Поля raw_monthly_sales, outlier_exclusions, stockout_adjustments, cleaned_monthly_sales, daily_projection, commitments, warnings и sources позволяют проверить поправки, дневной баланс, учтённые заказы и происхождение данных. rounding содержит minimum, multiple, conversion; text — краткое объяснение.

API endpoints

Базовый URL: http://localhost:8000. Интерактивный контракт: /docs, машиночитаемый — /openapi.json.

Авторизация и роли

Все /api/v1/* требуют Authorization: Bearer <API_KEY>. Health и страницы документации доступны без ключа.

Операцииviewerplannerapproveradmin
Чтение, аудит, экспорт утверждённого заказа✓✓✓✓
Импорт, retry задачи, создание плана—✓—✓
Создание и правка черновиков—✓—✓
Утверждение и отмена——✓✓

approver не наследует права planner. Управление ключами выполняется через CLI при доступе к среде приложения, отдельного HTTP endpoint для этого нет.

Общие правила

  • Каждый POST и PATCH требует Idempotency-Key длиной 1–128 символов. Ключ связан с пользователем и операцией: повтор того же запроса возвращает сохранённый результат, другое тело с тем же ключом даёт 409. Для нового действия нужен новый ключ.
  • Идентификаторы — UUID, даты — YYYY-MM-DD. Количества рекомендуется передавать десятичными строками, например "120.0000".
  • Основная пагинация: limit=50 (1–200), offset=0 (≥0). Для транзакций: limit=100 (1–500).
  • Списки наборов, планов, заказов и аудита возвращают {"items":[...]}. Каталог, транзакции и рекомендации дополнительно содержат total.
  • Обычный успешный ответ — 200; асинхронная операция — 202, создание черновиков — 201.

В таблицах Чтение — любая действующая роль; Планирование — planner или admin; Согласование — approver или admin. {id} — UUID ресурса; в OpenAPI параметр называется identifier.

Health и доступ

МетодEndpointДоступРезультат
GET/health/liveПубличныйstatus, service, version
GET/health/readyПубличныйПроверка БД и наличия таблицы Alembic
GET/api/v1/meЧтениеid, name, role текущего ключа

Импорт и задачи

МетодEndpointДоступПараметры / результат
POST/api/v1/datasets/sampleПланированиеJSON {"as_of":"2026-09-22"} или {}; 202, dataset_id, job_id, reused
POST/api/v1/datasets/uploadПланированиеMultipart: supplier, as_of, повторяемое поле files; 202, идентификаторы набора и задачи
GET/api/v1/datasetsЧтениеНаборы, limit, offset
GET/api/v1/datasets/{id}ЧтениеСтатус, сводка и состав файлов
GET/api/v1/jobs/{id}ЧтениеСтатус, progress, attempts, error, даты; внутренний token исключён
POST/api/v1/jobs/{id}/retryПланированиеТолько для failed, тело не требуется; 202, сброс попыток и постановка в очередь

Upload принимает файлы одного поставщика (iek или systeme) за запрос и создаёт самостоятельный набор. Для совместного расчёта обоих поставщиков на комплекте репозитория используйте sample-импорт.

Каталог

МетодEndpointДоступПараметры / результат
GET/api/v1/itemsЧтениеОбязательный dataset_id; supplier, category, q (до 100 символов), limit, offset
GET/api/v1/items/{id}ЧтениеКарточка, история, источники, число операций transaction_rows
GET/api/v1/items/{id}/transactionsЧтениеИсходные операции, limit, offset

Планы и рекомендации

МетодEndpointДоступПараметры / результат
POST/api/v1/plansПланированиеdataset_id, необязательный scenario; 202, plan_id, job_id
GET/api/v1/plansЧтениеСписок планов, limit, offset
GET/api/v1/plans/{id}ЧтениеСтатус, параметры, версия алгоритма, сводка
GET/api/v1/plans/{id}/recommendationsЧтениеsupplier, risk, limit, offset; количества, предупреждения, краткие причины
GET/api/v1/recommendations/{id}ЧтениеРекомендация с полным explanation

Агент закупок

МетодEndpointДоступПараметры / результат
POST/api/v1/agent/runsПланированиеdataset_id, scenario; 202, run_id, plan_id, job_id
GET/api/v1/agent/runsЧтениеНеобязательный dataset_id, limit=20 (1–100), без offset; items
GET/api/v1/agent/runs/{id}ЧтениеСохранённый отчёт, статус, сценарий, задача и ссылки на заказы

Агент выполняет workflow «проверка → очистка → расчёт → риски → черновики». План, отчёт и черновики публикуются одной транзакцией; утверждение остаётся отдельным действием менеджера. LLM не генерирует закупочные количества.

AI-ассистент

Необязательный раздел. Включается только серверным ключом OpenAI; при пустом ключе POST возвращает 503 ai_not_configured, а планирование продолжает работать.

МетодEndpointДоступПараметры / результат
GET/api/v1/assistant/statusЧтениеНастроен ли ключ, модель, лимиты и список доступных инструментов
POST/api/v1/assistant/runsПланирование / согласованиеplan_id, task (risks/explain/what_if), question, item_id, scenario; 202, run_id, job_id
GET/api/v1/assistant/runsЧтениеplan_id, limit=20; только собственные запросы автора
GET/api/v1/assistant/runs/{id}ЧтениеОтвет модели, вызванные инструменты, проверяемые числа и usage

Запрос выполняется фоновым worker'ом как задача kind=assistant с тем же lease/token, что импорт и расчёт. Результат сохраняется в assistant_runs и переживает перезагрузку страницы. Повтор через POST /api/v1/jobs/{id}/retry запрещён: новый вопрос — новый запрос к модели и новая оплата.

Function calling. Модель ведёт ограниченный цикл Responses над фиксированным серверным реестром инструментов:

ИнструментЧто возвращает
get_plan_summaryСценарий плана, счётчики риска, суммы заказа по поставщику и единице, черновики
find_itemsПоиск SKU внутри этого плана по коду/наименованию, фильтры риска и поставщика
explain_itemЧисловое разложение рекомендации: прогноз, страховой запас, запас, поступления, округление
sales_historyИсходный и очищенный месячные ряды, сезонный профиль и тренд
compare_scenarioПересчёт тех же SKU расчётным ядром с другими параметрами и сравнение before/after

Границы, которые обеспечивает сервер, а не инструкция модели:

  • Модель не получает SQL, Python, URL или команды. Она выбирает только имя инструмента и аргументы, которые повторно валидируются против плана этого запроса.
  • Количества считает детерминированное ядро. compare_scenario вызывает ту же функцию calculate, что и обычный план; гипотетический расчёт не меняет сохранённый план, заказы и обязательства.
  • Поставщик и категория сравнения неизменны: сравнение не может расширить охват SKU.
  • Товар вне плана отклоняется. Номера документов и клиентские данные в провайдера не уходят.
  • Бюджеты: ходы модели, вызовы инструментов, общее время и токены. Исчерпание бюджета даёт ответ по уже собранным данным, а не ошибку.
  • У ассистента нет инструмента правки, утверждения или отправки заказа. Ответы видит только их автор.

Интерфейс показывает ответ модели, список вызванных инструментов и проверяемые числа сервера рядом с текстом. В деморежиме ответы не генерируются — панель просит подключить сервер.

Заказы и аудит

МетодEndpointДоступПараметры / результат
POST/api/v1/ordersПланирование{"plan_id":"<UUID>"}; 201, массив order_ids
GET/api/v1/ordersЧтениеСписок заказов, limit, offset
GET/api/v1/orders/{id}ЧтениеЗаказ, текущая revision и lines
PATCH/api/v1/orders/{id}Планированиеrevision, lines из line_id, quantity, reason; новая ревизия
POST/api/v1/orders/{id}/approveСогласование{"revision":1}; утверждение текущей ревизии
POST/api/v1/orders/{id}/cancelСогласование{"revision":1}; отмена черновика или утверждённого заказа
GET/api/v1/orders/{id}/exportЧтениеCSV только для approved; действие записывается в аудит
GET/api/v1/auditЧтениеНеобязательный entity_id, limit, offset

В коде approve и cancel обслуживаются одним маршрутом POST /api/v1/orders/{identifier}/{action}, где action ограничен этими двумя значениями.

Ревизии и согласование

Заказ создаётся с revision=1. Правка, утверждение и отмена увеличивают ревизию. Перед изменением получите актуальный заказ: старая ревизия приводит к 409 revision_conflict.

Править можно только draft. В правке допустимо 1–5000 строк, количество от 0 до 1000000000 с четырьмя десятичными знаками, причина — 3–1000 символов. Нулевое количество исключает позицию из экспорта; положительное должно соответствовать MOQ, кратности и закупочной единице.

Черновики создаются только по положительным рекомендациям. Если закупка не нужна, order_ids может быть пустым. Утвердить заказ без положительных количеств нельзя.

Утверждение создаёт обязательство по поставке. Если после расчёта изменились обязательства тому же поставщику, API вернёт 409 stale_plan: нужен новый план. Отмена утверждённого заказа освобождает обязательство. Повторное создание заказов из прежнего плана возвращает существующие заказы, включая отменённые; для нового цикла закупки создайте новый план.

CSV

Кодировка — UTF-8 с BOM, разделитель — ;. Имя: optistock-<order_id>-r<revision>.csv.

order_id;revision;supplier;code;name;stock_unit;stock_quantity;purchase_quantity;arrival_date

Экспортируются только положительные количества утверждённой ревизии. Потенциальные формулы в текстовых ячейках экранируются. Совместимость с конкретным импортом 1С не подтверждена.

Ошибки

Типичная ошибка приложения:

{
  "code": "revision_conflict",
  "message": "Ревизия заказа устарела",
  "details": [],
  "request_id": "<UUID>"
}

Ответы, прошедшие middleware контекста, содержат X-Request-ID: сохраняйте его при разборе ошибок. Ранний отказ по размеру запроса может иметь сокращённое тело.

HTTPПричина / действие
401Ключ отсутствует, недействителен или отозван
403Роль не разрешает операцию
404Ресурс не найден
409Конфликт ключа или ревизии, неготовый набор/план, устаревший план, неверное состояние
413Превышен лимит запроса, файла или таблицы
422Некорректные поля, количество или ограничения заказа
500Внутренняя ошибка
503Ошибка доступа к БД; повторите изменяющий запрос с тем же ключом идемпотентности

Ошибка фоновой обработки хранится в job.error: успешная постановка задачи ещё не означает успешный импорт или расчёт.

Примеры запросов

В Swagger UI авторизуйтесь, выберите endpoint, нажмите Try it out и укажите уникальный Idempotency-Key для изменения данных.

Импорт и ожидание результата · PowerShell

$baseUrl = 'http://localhost:8000'
$apiKey = (Get-Content -Raw var/admin.key).Trim()
$readHeaders = @{ Authorization = "Bearer $apiKey" }
$writeHeaders = @{
    Authorization = "Bearer $apiKey"
    'Idempotency-Key' = [guid]::NewGuid().ToString()
}

$import = Invoke-RestMethod -Method Post -Uri "$baseUrl/api/v1/datasets/sample" -Headers $writeHeaders -ContentType 'application/json' -Body '{"as_of":"2026-09-22"}'
$import
Invoke-RestMethod -Uri "$baseUrl/api/v1/jobs/$($import.job_id)" -Headers $readHeaders

Повторяйте последний GET до succeeded или failed. При ошибке посмотрите error и логи worker. После успеха используйте $import.dataset_id для создания плана.

Создание плана · JSON

POST /api/v1/plans, с авторизацией и новым Idempotency-Key:

{
  "dataset_id": "<dataset_id из импорта>",
  "scenario": {
    "lead_time_days": 30,
    "review_days": 30,
    "safety_days": 14,
    "category_safety_days": {"1": 21, "7": 7},
    "growth_percent": 0,
    "remove_outliers": true,
    "estimate_stockouts": true,
    "use_seasonality": true,
    "use_trend": true
  }
}

Замените placeholder реальным UUID. Ответ содержит plan_id и job_id. Дождитесь succeeded, затем запросите /api/v1/plans/{plan_id}/recommendations?risk=critical или весь список без фильтра.

Создание, правка и утверждение заказа · JSON

Создать черновики: POST /api/v1/orders с {"plan_id":"<UUID>"}. Выберите заказ из order_ids и получите его через GET /api/v1/orders/{id}.

Правка: PATCH /api/v1/orders/{id}:

{
  "revision": 1,
  "lines": [
    {
      "line_id": "<UUID строки заказа>",
      "quantity": "120.0000",
      "reason": "Количество скорректировано после проверки потребности"
    }
  ]
}

Количество замените допустимым для выбранного товара. Передайте возвращённую ревизию в POST /api/v1/orders/{id}/approve, например {"revision":2}, затем скачайте /api/v1/orders/{id}/export. Каждый новый POST/PATCH получает отдельный ключ идемпотентности.

Загрузка поддерживаемого XLSX · Bash / curl

API_KEY="$(tr -d '\r\n' < var/admin.key)"
curl --fail-with-body -X POST http://localhost:8000/api/v1/datasets/upload \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(python3 -c 'import uuid; print(uuid.uuid4())')" \
  -F 'supplier=iek' \
  -F 'as_of=2026-09-22' \
  -F 'files=@/path/to/sales.xlsx' \
  -F 'files=@/path/to/stocks.xlsx'

Замените пути реальными файлами поддерживаемой схемы. Content-Type: multipart/form-data с boundary выставит curl.

Демонстрация

После запуска Docker, создания var/admin.key и установки venv:

СредаКоманда
Windows.\.venv\Scripts\python.exe scripts/demo.py
Linux / macOS.venv/bin/python scripts/demo.py

Другой адрес и ключ задаются аргументами --url http://127.0.0.1:8000 --key-file var/admin.key.

Скрипт проверяет readiness, импортирует 12 файлов, ждёт worker, рассчитывает план, создаёт черновики, сохраняет проверочную правку с причиной, утверждает заказы и скачивает CSV. Всё выполняется через HTTP API. Поставщикам ничего не отправляется.

Результаты в var/:

  • demo-summary.json — идентификаторы, сводки и время выполнения;
  • optistock-<supplier>-<order_id>.csv — экспорт каждого созданного заказа.

Повторный запуск переиспользует импорт, но создаёт новый план с учётом уже утверждённых заказов. Число рекомендаций и новых заказов может измениться. Для освобождения обязательств используйте отмену соответствующих заказов через API.

Зафиксированный результат проверки

В VERIFICATION.md описан отдельный локальный запуск от 23 сентября 2026 года на Docker Desktop ARM64, Python 3.13 и PostgreSQL 17.11:

ПоказательРезультат того запуска
Исходные XLSX12
Уникальные пары поставщик / код3 909
IEK / Systeme Electric3 185 / 724
Операции с числовым количеством248 884
Товары с месячной историей3 017
Рекомендации к закупке491
Товары с дефицитом до поставки162
Товары с insufficient_data892
Строки заказов IEK / Systeme Electric335 / 156
Полный HTTP-сценарий, один замер25,3 с

Это результаты конкретного тестового сценария, а не гарантии производительности или точности прогноза. Параметры: срез 2026-09-22, поставка 30 дней, пересмотр 30 дней, страховое покрытие 14 дней.

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

Нужны установленный venv и запущенная PostgreSQL. configure.py задаёт OPTISTOCK_TEST_DATABASE_URL, а Docker при первой инициализации создаёт optistock_test.

Тесты очищают таблицы тестовой БД перед каждым тестом. Используйте отдельную БД с именем, заканчивающимся на _test. SQLite не поддерживается.

Windows · PowerShell
.\.venv\Scripts\python.exe scripts/test.py -q
.\.venv\Scripts\ruff.exe check backend tests scripts migrations
.\.venv\Scripts\ruff.exe format --check backend tests scripts migrations
Linux / macOS · Bash
.venv/bin/python scripts/test.py -q
.venv/bin/ruff check backend tests scripts migrations
.venv/bin/ruff format --check backend tests scripts migrations

scripts/test.py применяет миграции к тестовой БД, запускает pytest и выполняет alembic check для сравнения моделей со схемой миграций.

ФайлОбласть проверки
tests/test_planning.pyПотребность, MOQ, поздние поставки, выбросы, stockout и сценарии
tests/test_workflow.pyЦикл заказа, роли, идемпотентность, ревизии, конкуренция, worker, экспорт
tests/test_limits.pyОграничения запросов и некорректные загрузки
tests/test_agent.py, tests/test_case_criteria.pyWorkflow агента и критерии кейса
tests/test_backtest.pyВременная корректность исторической проверки
tests/test_samples.pyИмпорт исходного комплекта XLSX
tests/test_assistant.pyДоступ к AI, реестр инструментов, цикл function calling и его бюджеты

Тест исходного комплекта пропускается при отсутствии папки IEK. В последнем запуске — 48 backend-тестов (ruff и alembic check без замечаний), плюс сохранённые ранее 14 обычных браузерных тестов и отдельный 1 live E2E. Это результаты прежних запусков; текущий результат следует получать командами выше. Проверки frontend и требования к Playwright описаны в frontend/README.md; workflow находится в .github/workflows/frontend.yml.

Эксплуатация и устранение проблем

Основные команды

docker compose ps -a
docker compose logs --tail 100 api worker migrate
docker compose restart api worker
docker compose down

docker compose down сохраняет volumes; флаг -v удаляет постоянные данные БД и загруженные файлы. API и worker работают без root, с read-only корневой файловой системой, ограничением ресурсов и ротацией Docker-логов.

Резервное копирование

Нужны обе части: дамп PostgreSQL и копия volume documents с XLSX. Хеши в БД не заменяют файлы. Для согласованной копии приостановите изменяющие запросы и обработку задач на время снимка.

Создание дампа внутри контейнера и копирование на хост подходит также для Windows PowerShell, где перенаправление бинарного вывода в старых версиях может повредить файл:

docker compose exec -T db pg_dump -U optistock -d optistock -Fc -f /tmp/optistock.dump
docker compose cp db:/tmp/optistock.dump var/optistock.dump

Папка var/ должна существовать. Volume documents архивируйте средствами вашей Docker-среды; проверяйте восстановление вместе с дампом в отдельной БД. Результат выполненной проверки восстановления описан в VERIFICATION.md.

Частые проблемы

СимптомЧто проверить
Compose требует парольВыполните python scripts/configure.py; существующий .env проверьте на заполнение обязательных полей
Ошибка подключения после изменения пароляИзменение .env не меняет пароль существующей роли PostgreSQL: инициализация происходит только на пустом volume
API не становится readyЛоги db, migrate, api; миграция должна завершиться успешно
/ возвращает 404Откройте /docs; корневая страница не реализована
Задача остаётся queuedWorker должен быть запущен и подключён к той же БД
sample_files_missingВ обеих папках должно быть по 6 XLSX; проверьте mounts и OPTISTOCK_SAMPLE_ROOT
Worker не находит файлAPI и worker должны использовать общее файловое хранилище
Задача failedПрочитайте job.error, устраните причину, вызовите /jobs/{id}/retry
401 / 403Проверьте ключ, активность и роль через /api/v1/me
idempotency_conflictДля изменённого тела нужен новый ключ; сетевой повтор сохраняет прежний
revision_conflictЗагрузите заказ заново и используйте текущую ревизию
stale_planСоздайте новый план с актуальными обязательствами
order_constraintsПроверьте MOQ, кратность и коэффициент единиц в объяснении
approval_requiredПеред экспортом заказ должен быть approved

Compose рассчитан на один узел. Для внешнего размещения нужны HTTPS reverse proxy, ограниченный доступ к БД, персональные ключи и проверяемое резервное копирование. Привязки к 127.0.0.1 рассчитаны на локальный доступ.

Ограничения и развитие

Граница MVPТекущее поведение
Качество прогнозаТочность на будущих продажах не доказана; экономия и вероятности дефицита не заявляются
Клиентские аномалииНет ID клиента; анализируются документы, а не покупатели
StockoutНулевой месячный снимок — приближение, а не доказанный интервал отсутствия товара
СезонностьПрофиль поставщика с неподтверждёнными единицами — явно отмеченное приближение
Остатки и условияНедостающие значения заменяются правилами сценария и отражаются в предупреждениях
Складской охватОбъединённый тестовый сценарий поставщика, без модели отдельного согласованного склада
ИнтеграцииНет отправки поставщикам, приёмки поставок и подтверждённого обмена с 1С
Интерфейс и входReact и Swagger; API-ключи и локальный dev proxy; OIDC не реализован
ДоступностьБД и файловый volume — единичные точки отказа; HA-кластера нет

React-интерфейс, графики исходного и очищенного спроса и инструменты исторической проверки уже реализованы. Следующие направления — расширение сравнения сценариев и проверки качества на новых данных; при расширении эксплуатации — OIDC и объектное хранилище.

Документация

ДокументСодержание
frontend/README.mdИнтерфейс, три языка, подключение API, сборка и браузерные проверки
JURY_GUIDE.mdТрёхминутная демонстрация и текст для сдачи
CASE_EVIDENCE.mdДоказательства выполнения критериев и ограничения
MVP_IMPLEMENTATION.mdТекущий объём MVP и принятые решения
VERIFICATION.mdРезультаты конкретного запуска тестов, demo и восстановления
LOGISTICS_CASE.mdТребования кейса и бизнес-контекст
DATA_REVIEW.mdАнализ данных и ограничений
BACKEND_ARCHITECTURE.mdАрхитектурная проработка; предложения сверяйте с текущим кодом
PRODUCT_REVIEW.mdПродуктовый разбор и сценарии
TECHNICAL_REFERENCE_REVIEW.mdАнализ внешнего технического референса
HACKATHON_PREP.mdПодготовка к хакатону и организационный контекст

При расхождениях ранних проектных материалов с реализацией ориентируйтесь на текущий код, OpenAPI и MVP_IMPLEMENTATION.md. Файл лицензии в репозитории не добавлен; конкретная открытая лицензия этим README не заявляется.


OptiStock · Данные → объяснимый расчёт → согласованный заказ

Вернуться к началу

Звёзды
⭐ 0
Форки
0
Язык
TypeScript
Последний push
в прошлом месяце
Коммиты
16
Авторы
5
Файлы
133
Ветки
3

Авторы коммитов

Erasyl 7syrymzaksylyk20-cmd 4Alikhan Talgat 2Erasyl 2alitalgat 1

История коммитов

  • 2026-09-23 17:56docs: document the AI assistant tools, budgets and the short-history outlier fallbackErasyl
  • 2026-09-23 17:54merge: README expansion from mainErasyl
  • 2026-09-23 17:53feat: give the AI assistant a real tool loop, a UI and short-history outlier handlingErasyl
  • 2026-09-23 17:51docs: expand README with architecture, setup and API referencealitalgat
  • 2026-09-23 17:45Update README.mdAlikhan Talgat
  • 2026-09-23 17:44Update README.mdAlikhan Talgat
  • 2026-09-23 17:38merge: i18n interface languages into assistant branchErasyl
  • 2026-09-23 17:30feat: add durable OpenAI analysis API and document remaining MVP workErasyl
Все коммиты (16)
  • 2026-09-23 17:25feat: add English, Russian and Kazakh interface languagessyrymzaksylyk20-cmd
  • 2026-09-23 16:48fix: make demand corrections auditable and prepare jury demosyrymzaksylyk20-cmd
  • 2026-09-23 16:39feat: add procurement agent and verify complete replenishment workflowsyrymzaksylyk20-cmd
  • 2026-09-23 15:48feat: add complete OptiStock React frontendsyrymzaksylyk20-cmd
  • 2026-09-23 15:41Update README.mdErasyl
  • 2026-09-23 15:41Delete .github/workflows directoryErasyl
  • 2026-09-23 14:38feat: build OptiStock backend MVP with durable planning and approvalsErasyl
  • 2026-09-23 13:56docs: define Supply Planner requirements and backend architectureErasyl
Структура репозитория (133 файлов)
.dockerignore
.env.example
.gitattributes
.github/workflows/frontend.yml
.gitignore
BACKEND_ARCHITECTURE.md
CASE_EVIDENCE.md
DATA_REVIEW.md
Dockerfile
HACKATHON_PREP.md
IEK/MOQ  ИЭК.xlsx
IEK/Динамика продаж_2025-2026.xlsx
IEK/Ежемесячные остатки продукции за последние 2 года  ИЭК.xlsx
IEK/Ежемесячные продажи в количественном выражении за последние 2 года.xlsx
IEK/Путь ИЭК 22.09.2026.xlsx
IEK/Сезонность ИЭК.xlsx
JURY_GUIDE.md
LOGISTICS_CASE.md
MVP_IMPLEMENTATION.md
NEXT_STEPS_TZ.md
PRODUCT_REVIEW.md
README.md
Systeme electric/MOQ SystemElectric.xlsx
Systeme electric/Динамика продаж_Syseme Electric_2025-2026.xlsx
Systeme electric/Ежемесячные остатки SystemElectric 2024-2026.xlsx
Systeme electric/Ежемесячные продажи в кол-м выражении SystemElectric 2024-2026.xlsx
Systeme electric/Сезонность SystemElectric 2024-2026.xlsx
Systeme electric/Товар в пути_SystemElectric на 22.09.2026.xlsx
TECHNICAL_REFERENCE_REVIEW.md
VERIFICATION.md
alembic.ini
backend/optistock/__init__.py
backend/optistock/agent.py
backend/optistock/api.py
backend/optistock/assistant.py
backend/optistock/backtest.py
backend/optistock/cli.py
backend/optistock/config.py
backend/optistock/db.py
backend/optistock/errors.py
backend/optistock/ingestion.py
backend/optistock/middleware.py
backend/optistock/models.py
backend/optistock/planning.py
backend/optistock/schemas.py
backend/optistock/services.py
backend/optistock/tools.py
backend/optistock/worker.py
compose.yaml
docker/Dockerfile.db
docker/init-db.sh
frontend/.dockerignore
frontend/.env.example
frontend/.gitignore
frontend/.oxlintrc.json
frontend/.prettierignore
frontend/.prettierrc.json
frontend/Dockerfile
frontend/README.md
frontend/e2e/agent-live.spec.ts
frontend/e2e/api.spec.ts
frontend/e2e/i18n.spec.ts
frontend/e2e/workspace.spec.ts
frontend/index.html
frontend/nginx.conf
frontend/package-lock.json
frontend/package.json
frontend/playwright.config.ts
frontend/public/favicon.svg
frontend/public/mountains.svg
frontend/src/App.tsx
frontend/src/components/AssistantPanel.tsx
frontend/src/components/DemandHistory.tsx
frontend/src/components/ImportDialog.tsx
frontend/src/components/InventoryTable.tsx
frontend/src/components/LanguageSelector.tsx
frontend/src/components/Layout.tsx
frontend/src/components/MetricCard.tsx
frontend/src/components/ProductDrawer.tsx
frontend/src/components/charts.tsx
frontend/src/components/ui.tsx
frontend/src/i18n/assistant.ts
frontend/src/i18n/domain.ts
frontend/src/i18n/errors.ts
frontend/src/i18n/extra.ts
frontend/src/i18n/index.ts
frontend/src/i18n/messages.ts
frontend/src/lib/api.ts
frontend/src/lib/demo.ts
frontend/src/lib/format.ts
frontend/src/lib/useExplanation.ts
frontend/src/main.tsx
frontend/src/pages/Agent.tsx
frontend/src/pages/Analytics.tsx
frontend/src/pages/Dashboard.tsx
frontend/src/pages/Forecast.tsx
frontend/src/pages/Inventory.tsx
frontend/src/pages/Orders.tsx
frontend/src/pages/Reports.tsx
frontend/src/pages/Settings.tsx
frontend/src/pages/Suppliers.tsx
frontend/src/store.tsx
frontend/src/styles-assistant.css
frontend/src/styles-i18n.css
frontend/src/styles-responsive.css
frontend/src/styles.css
frontend/src/types.ts
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
migrations/env.py
migrations/script.py.mako
migrations/versions/0cdaac70ddf4_initial_schema.py
migrations/versions/91f823ab4100_procurement_agent.py
migrations/versions/c391b6e1a102_openai_assistant.py
pyproject.toml
requirements.lock
scripts/backtest.py
scripts/configure.py
scripts/demo.py
scripts/jury_demo.py
scripts/local_dev.py
scripts/test.py
tests/conftest.py
tests/test_agent.py
tests/test_assistant.py
tests/test_backtest.py
tests/test_case_criteria.py
tests/test_limits.py
tests/test_planning.py
tests/test_samples.py
tests/test_workflow.py
Ветки (3)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.