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>
5.9 KiB
5.9 KiB
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).
Принцип работы:
- Backend: Хендлер создает фоновую задачу через
taskManager.Submit()и возвращаетtask_id - Frontend: Получает
task_idи делает polling через/api/tasks/:idкаждые 500ms - Уведомления: Система автоматически показывает toast-уведомления при завершении задачи
Типы задач:
TaskTypeRecalculate- пересчет всех цен компонентовTaskTypeStockImport- импорт складской справки из .mxl/.xlsxTaskTypePricelistCreate- создание прайслиста (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.
При создании прайслистов:
- Estimate: Загружаем категории из
lot.lot_categoryдля всех компонентов - Warehouse: Загружаем категории из
lot.lot_categoryдля всех позиций - Сохраняем в поле
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.