Files
PriceForge/CLAUDE.md
Michael Chus f64c4fd6b2 feat: optimize background tasks and fix warehouse pricelist workflow
Optimize task retention from 5 minutes to 30 seconds to reduce polling overhead since toast notifications are shown only once. Add conditional warehouse pricelist creation via checkbox. Fix category storage in warehouse pricelists to properly load from lot table. Replace SSE with task polling for all long operations. Add comprehensive logging for debugging while minimizing noise from polling endpoints.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-16 11:08:10 +03:00

5.9 KiB
Raw Blame History

PriceForge - Claude Code Instructions

Overview

Администратор цен для работы с прайслистами, складскими справками и алертами. Источник данных: MariaDB. Локальная БД используется только для настроек и техданных приложения.

Scope

  • Управление ценами и котировками компонентов
  • Управление прайслистами и их версиями
  • Импорт складских справок
  • Алерты по ценам/свежести данных
  • Подготовка к интеграции с API B2B площадок для автоматических котировок

API Endpoints

Group Endpoints
Setup GET/POST /setup, POST /setup/test, GET /setup/status
System GET /health, GET /api/ping, GET /api/db-status, GET /api/current-user
Components GET /api/components, GET /api/components/:lot_name, GET /api/categories
Pricelists CRUD /api/pricelists, GET /api/pricelists/latest
Pricing Admin /api/admin/pricing/*
Sync (diagnostics/minimal) GET /api/sync/status, GET /api/sync/info, POST /api/sync/components, POST /api/sync/pricelists

Commands

# Development
go run ./cmd/pfs
make run

# Build
make build
make build-release

# Version
./bin/pfs -version

Tech Stack

Go 1.22+ | Gin | GORM | MariaDB 11 | htmx + Tailwind CDN | excelize

Pricelist Sources

Estimate

  • Создается из snapshot текущих цен компонентов (qt_lot_metadata)
  • Сохраняет все настройки ценообразования: price_period_days, price_coefficient, manual_price, meta_prices
  • Это основной прайслист для расчетов и оценок

Warehouse

  • Создается из складских справок (stock_log)
  • ВАЖНО: НЕ должен загружать настройки цен из lot_metadata
  • Использует только weighted median (взвешенная медиана по количеству) из stock_log
  • Поле price_method всегда содержит "weighted_median"
  • Не содержит price_period_days, price_coefficient, manual_price, meta_prices
  • Это фактические складские цены без дополнительной обработки

Competitor

  • Зарезервировано для будущих интеграций с API B2B площадок

Background Tasks (Фоновые задачи)

ВАЖНО: Все долгие операции выполняются через Task Manager, НЕ через SSE (Server-Sent Events).

Принцип работы:

  1. Backend: Хендлер создает фоновую задачу через taskManager.Submit() и возвращает task_id
  2. Frontend: Получает task_id и делает polling через /api/tasks/:id каждые 500ms
  3. Уведомления: Система автоматически показывает toast-уведомления при завершении задачи

Типы задач:

  • TaskTypeRecalculate - пересчет всех цен компонентов
  • TaskTypeStockImport - импорт складской справки из .mxl/.xlsx
  • TaskTypePricelistCreate - создание прайслиста (estimate/warehouse/competitor)

Структура задачи:

type Task struct {
    ID        string                 // UUID задачи
    Type      TaskType              // Тип задачи
    Status    TaskStatus            // running | completed | error
    Progress  int                   // 0-100
    Message   string                // Текущее сообщение для UI
    Result    map[string]interface{} // Результат при completed
    Error     string                // Текст ошибки при error
    CreatedAt time.Time
    DoneAt    *time.Time
}

Пример использования:

taskID := h.taskManager.Submit(tasks.TaskTypeStockImport, func(ctx context.Context, progressCb func(int, string)) (map[string]interface{}, error) {
    // Выполнение задачи
    progressCb(50, "Половина выполнена")

    // Возврат результата
    return map[string]interface{}{
        "rows_total": 100,
        "inserted": 95,
    }, nil
})
c.JSON(http.StatusOK, gin.H{"task_id": taskID})

Категории товаров (lot_category)

Источник данных:

Категории берутся из таблицы lot (поле lot_category), НЕ из qt_lot_metadata.

При создании прайслистов:

  1. Estimate: Загружаем категории из lot.lot_category для всех компонентов
  2. Warehouse: Загружаем категории из lot.lot_category для всех позиций
  3. Сохраняем в поле lot_category таблицы qt_pricelist_items

В модели:

type PricelistItem struct {
    LotCategory *string `gorm:"column:lot_category;size:50" json:"category,omitempty"`
    // JSON поле называется "category" для фронтенда
}

ВАЖНО:

  • Категория НЕ виртуальное поле - она сохраняется в БД при создании прайслиста
  • JOIN с таблицей lot нужен только для lot_description, категория уже есть в qt_pricelist_items

Notes

  • Главная страница должна вести на /admin/pricing.
  • В UI не должно быть ссылок на конфигуратор, проекты и экспорт.
  • НЕ использовать SSE - только фоновые задачи через Task Manager.