16 KiB
QuoteForge
Server Configuration & Quotation Tool
QuoteForge — корпоративный инструмент для конфигурирования серверов и формирования коммерческих предложений (КП). Приложение интегрируется с существующей базой данных RFQ_LOG.
Возможности
Для пользователей
- 📱 Mobile-first интерфейс — удобная работа с телефона и планшета
- 🖥️ Конфигуратор серверов — пошаговый выбор компонентов с проверкой совместимости
- 💰 Автоматический расчёт цен — актуальные цены на основе истории закупок
- 📊 Экспорт в CSV/XLSX — готовые спецификации для клиентов
- 💾 Сохранение конфигураций — история и шаблоны для повторного использования
Для ценовых администраторов
- 📈 Умный расчёт цен — медиана, взвешенная медиана, среднее
- 🎯 Система алертов — уведомления о популярных компонентах с устаревшими ценами
- 📉 Аналитика использования — какие компоненты востребованы в КП
- ⚙️ Гибкие настройки — периоды расчёта, методы, ручные переопределения
Индикация актуальности цен
| Цвет | Статус | Условие |
|---|---|---|
| 🟢 Зелёный | Свежая | < 30 дней, ≥ 3 источника |
| 🟡 Жёлтый | Нормальная | 30-60 дней |
| 🟠 Оранжевый | Устаревающая | 60-90 дней |
| 🔴 Красный | Устаревшая | > 90 дней или нет данных |
Технологии
- Backend: Go 1.22+, Gin, GORM
- Frontend: HTML, Tailwind CSS, htmx
- Database: MariaDB 11+
- Export: excelize (XLSX), encoding/csv
Требования
- Go 1.22 или выше
- MariaDB 11.x (или MySQL 8.x)
- ~50 MB дискового пространства
Установка
1. Клонирование репозитория
git clone https://github.com/your-company/quoteforge.git
cd quoteforge
2. Настройка конфигурации
cp config.example.yaml config.yaml
Отредактируйте config.yaml:
server:
host: "0.0.0.0"
port: 8080
mode: "release"
database:
host: "localhost"
port: 3306
name: "RFQ_LOG"
user: "quoteforge"
password: "your-secure-password"
auth:
jwt_secret: "your-jwt-secret-min-32-chars"
token_expiry: "24h"
3. Миграции базы данных
go run ./cmd/qfs -migrate
Мигратор OPS -> проекты (preview/apply)
Переносит квоты, чьи названия начинаются с OPS-xxxx (где x — цифра), в проект OPS-xxxx.
Если проекта нет, он будет создан; если архивный — реактивирован.
Сначала всегда смотрите preview:
go run ./cmd/migrate_ops_projects -config config.yaml
Применение изменений:
go run ./cmd/migrate_ops_projects -config config.yaml -apply
Без интерактивного подтверждения:
go run ./cmd/migrate_ops_projects -config config.yaml -apply -yes
Минимальные права БД для пользователя квотаций
Если нужен пользователь, который может работать с конфигурациями, но не может создавать/удалять прайслисты:
-- 1) Создать (или оставить существующего) пользователя
CREATE USER IF NOT EXISTS 'quote_user'@'%' IDENTIFIED BY 'DB_PASSWORD_PLACEHOLDER';
-- 2) Сбросить лишние права (без пересоздания пользователя)
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'quote_user'@'%';
-- 3) Чтение данных для конфигуратора и синка
GRANT SELECT ON RFQ_LOG.lot TO 'quote_user'@'%';
GRANT SELECT ON RFQ_LOG.qt_lot_metadata TO 'quote_user'@'%';
GRANT SELECT ON RFQ_LOG.qt_categories TO 'quote_user'@'%';
GRANT SELECT ON RFQ_LOG.qt_pricelists TO 'quote_user'@'%';
GRANT SELECT ON RFQ_LOG.qt_pricelist_items TO 'quote_user'@'%';
-- 4) Работа с конфигурациями
GRANT SELECT, INSERT, UPDATE ON RFQ_LOG.qt_configurations TO 'quote_user'@'%';
FLUSH PRIVILEGES;
SHOW GRANTS FOR 'quote_user'@'%';
Важно:
- не выдавайте
INSERT/UPDATE/DELETEнаqt_pricelistsиqt_pricelist_items, если пользователь не должен управлять прайслистами; - если используется host-специфичный аккаунт (
'quote_user'@'192.168.x.x'), назначьте права и для него; - после смены DB-настроек через
/setupприложение перезапускается автоматически и подхватывает нового пользователя.
4. Импорт метаданных компонентов
go run ./cmd/importer
5. Запуск
# Development
go run ./cmd/qfs
# Production (with Makefile - recommended)
make build-release # Builds with version info
./bin/qfs -version # Check version
# Production (manual)
VERSION=$(git describe --tags --always --dirty)
CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=$VERSION" -o bin/qfs ./cmd/qfs
./bin/qfs -version
Makefile команды:
make build-release # Оптимизированная сборка с версией
make build-all # Сборка для всех платформ (Linux, macOS, Windows)
make build-windows # Только для Windows
make run # Запуск dev сервера
make test # Запуск тестов
make clean # Очистка bin/
make help # Показать все команды
Приложение будет доступно по адресу: http://localhost:8080
Локальная SQLite база (state)
Локальная база приложения хранится в профиле пользователя и не зависит от расположения бинарника.
Имя файла: qfs.db.
- macOS:
~/Library/Application Support/QuoteForge/qfs.db - Linux:
$XDG_STATE_HOME/quoteforge/qfs.db(или~/.local/state/quoteforge/qfs.db) - Windows:
%LOCALAPPDATA%\\QuoteForge\\qfs.db
Можно переопределить путь через -localdb или переменную окружения QFS_DB_PATH.
Версионность конфигураций (local-first)
Для local_configurations используется append-only versioning через полные snapshot-версии:
- таблица:
local_configuration_versions - для каждого изменения создаётся новая версия (
version_no = max + 1) local_configurations.current_version_idуказывает на активную версию- старые версии не изменяются и не удаляются в обычном потоке
- rollback не "перематывает" историю, а создаёт новую версию из выбранного snapshot
При backfill (миграция 006_add_local_configuration_versions.sql) для существующих конфигураций создаётся v1 и проставляется current_version_id.
Rollback
Rollback выполняется API-методом:
POST /api/configs/:uuid/rollback
{
"target_version": 3,
"note": "optional"
}
Результат:
- создаётся новая версия
vNсdataиз целевой версии change_note = "rollback to v{target_version}"(+ note, если передан)current_version_idпереключается на новую версию- конфигурация уходит в
sync_status = pending
Локальный config.yaml
По умолчанию qfs ищет config.yaml в той же user-state папке, где лежит qfs.db (а не рядом с бинарником).
Можно переопределить путь через -config или QFS_CONFIG_PATH.
Docker
# Сборка образа
docker build -t quoteforge .
# Запуск с docker-compose
docker-compose up -d
Структура проекта
quoteforge/
├── cmd/
│ ├── server/main.go # Main HTTP server
│ └── importer/main.go # Import metadata from lot table
├── internal/
│ ├── config/ # Конфигурация
│ ├── models/ # GORM модели
│ ├── handlers/ # HTTP handlers
│ ├── services/ # Бизнес-логика
│ ├── middleware/ # Auth, CORS, etc.
│ └── repository/ # Работа с БД
├── web/
│ ├── templates/ # HTML шаблоны
│ └── static/ # CSS, JS, изображения
├── migrations/ # SQL миграции
├── config.yaml # Конфигурация
├── Dockerfile
├── docker-compose.yml
└── go.mod
Роли пользователей
| Роль | Описание |
|---|---|
viewer |
Просмотр, создание квот, экспорт |
editor |
+ сохранение конфигураций |
pricing_admin |
+ управление ценами и алертами |
admin |
Полный доступ, управление пользователями |
API
Документация API доступна по адресу /api/docs (в разработке).
Основные endpoints:
POST /api/auth/login # Авторизация
GET /api/components # Список компонентов
POST /api/quote/calculate # Расчёт цены
POST /api/export/xlsx # Экспорт в Excel
GET /api/configs # Сохранённые конфигурации
GET /api/configs/:uuid/versions # Список версий конфигурации
GET /api/configs/:uuid/versions/:version # Получить конкретную версию
POST /api/configs/:uuid/rollback # Rollback на указанную версию
POST /api/configs/:uuid/reactivate # Вернуть архивную конфигурацию в активные
Sync payload для versioning
События в pending_changes для конфигураций содержат:
configuration_uuidoperation(create/update/rollback)current_version_idиcurrent_version_nosnapshot(текущее состояние конфигурации)idempotency_keyиconflict_policy(last_write_wins)
Это позволяет push-слою отправлять на сервер актуальное состояние и готовит основу для будущего conflict resolution.
Cron Jobs
QuoteForge now includes automated cron jobs for maintenance tasks. These can be run using the built-in cron functionality in the Docker container.
Docker Compose Setup
The Docker setup includes a dedicated cron service that runs the following jobs:
- Alerts check: Every hour (0 * * * *)
- Price updates: Daily at 2 AM (0 2 * * *)
- Usage counter reset: Weekly on Sunday at 1 AM (0 1 * * 0)
- Popularity score updates: Daily at 3 AM (0 3 * * *)
To enable cron jobs in Docker, run:
docker-compose up -d
Manual Cron Job Execution
You can also run cron jobs manually using the quoteforge-cron binary:
# Check and generate alerts
go run ./cmd/cron -job=alerts
# Recalculate all prices
go run ./cmd/cron -job=update-prices
# Reset usage counters
go run ./cmd/cron -job=reset-counters
# Update popularity scores
go run ./cmd/cron -job=update-popularity
Cron Job Details
- Alerts check: Generates alerts for components with high demand and stale prices, trending components without prices, and components with no recent quotes
- Price updates: Recalculates prices for all components using configured methods (median, weighted median, average)
- Usage counter reset: Resets weekly and monthly usage counters for components
- Popularity score updates: Recalculates popularity scores based on supplier quote activity
Разработка
# Запуск в режиме разработки (hot reload)
go run ./cmd/qfs
# Запуск тестов
go test ./...
# Сборка для Linux
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/qfs ./cmd/qfs
Переменные окружения
| Переменная | Описание | По умолчанию |
|---|---|---|
QF_DB_HOST |
Хост базы данных | localhost |
QF_DB_PORT |
Порт базы данных | 3306 |
QF_DB_NAME |
Имя базы данных | RFQ_LOG |
QF_DB_USER |
Пользователь БД | — |
QF_DB_PASSWORD |
Пароль БД | — |
QF_JWT_SECRET |
Секрет для JWT | — |
QF_SERVER_PORT |
Порт сервера | 8080 |
QFS_DB_PATH |
Полный путь к локальной SQLite БД | OS-specific user state dir |
QFS_STATE_DIR |
Каталог state (если QFS_DB_PATH не задан) |
OS-specific user state dir |
QFS_CONFIG_PATH |
Полный путь к config.yaml |
OS-specific user state dir |
Интеграция с существующей БД
QuoteForge интегрируется с существующей базой RFQ_LOG:
lot— справочник компонентов (только чтение)lot_log— история цен от поставщиков (только чтение)supplier— справочник поставщиков (только чтение)
Новые таблицы QuoteForge имеют префикс qt_:
qt_users— пользователи приложенияqt_lot_metadata— расширенные данные компонентовqt_configurations— сохранённые конфигурацииqt_pricing_alerts— алерты для администраторов
Поддержка
По вопросам работы приложения обращайтесь:
- Email: mike@mchus.pro
- Internal: @mchus
Лицензия
Данное программное обеспечение является собственностью компании и предназначено исключительно для внутреннего использования. Распространение, копирование или модификация без письменного разрешения запрещены.
См. файл LICENSE для подробностей.