Files
QuoteForge/bible-local/03-database.md
Mikhail Chusavitin f915866f83 docs: document final RFQ_LOG MariaDB schema (2026-03-21)
Expand 03-database.md with complete table structure reference for all
23 tables in the final schema: active QuoteForge tables, competitor
subsystem, legacy RFQ tables, and server-side-only tables.

Also clarifies access patterns per group and notes removal of
qt_client_local_migrations from the schema.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:24:03 +03:00

14 KiB

03 - Database

SQLite

SQLite is the local runtime database.

Main tables:

Table Purpose
local_components synced component metadata
local_pricelists local pricelist headers
local_pricelist_items local pricelist rows, the only runtime price source
local_projects user projects
local_configurations user configurations
local_configuration_versions immutable revision snapshots
local_partnumber_books partnumber book headers
local_partnumber_book_items PN -> LOT catalog payload
pending_changes sync queue
connection_settings encrypted MariaDB connection settings
app_settings local app state
local_schema_migrations applied local migration markers

Rules:

  • cache tables may be rebuilt if local migration recovery requires it;
  • user-authored tables must not be dropped as a recovery shortcut;
  • local_pricelist_items is the only valid runtime source of prices;
  • configuration items and vendor_spec are stored as JSON payloads inside configuration rows.

MariaDB

MariaDB is the central sync database (RFQ_LOG). Final schema as of 2026-03-21.

QuoteForge tables (qt_* and stock_*)

Runtime read:

  • qt_categories — pricelist categories
  • qt_lot_metadata — component metadata, price settings
  • qt_pricelists — pricelist headers (source: estimate / warehouse / competitor)
  • qt_pricelist_items — pricelist rows
  • stock_log — raw supplier price log, source for pricelist generation
  • stock_ignore_rules — patterns to skip during stock import
  • qt_partnumber_books — partnumber book headers
  • qt_partnumber_book_items — PN→LOT catalog payload

Runtime read/write:

  • qt_projects — projects
  • qt_configurations — configurations
  • qt_client_schema_state — per-client sync status and version tracking
  • qt_pricelist_sync_status — pricelist sync timestamps per user

Insert-only tracking:

  • qt_vendor_partnumber_seen — vendor partnumbers encountered during sync

Server-side only (not queried by client runtime):

  • qt_component_usage_stats — aggregated component popularity stats (written by server jobs)
  • qt_pricing_alerts — price anomaly alerts (models exist in Go; feature disabled in runtime)
  • qt_schema_migrations — server migration history (applied via go run ./cmd/qfs -migrate)
  • qt_scheduler_runs — server background job tracking (no Go code references it in this repo)

Competitor subsystem (server-side only, not used by QuoteForge Go code)

  • qt_competitors — competitor registry
  • partnumber_log_competitors — competitor price log (FK → qt_competitors)

These tables exist in the schema and are maintained by another tool or workflow. QuoteForge references competitor pricelists only via qt_pricelists (source='competitor').

Legacy RFQ tables (pre-QuoteForge, no Go code references)

  • lot — original component registry (data preserved; superseded by qt_lot_metadata)
  • lot_log — original supplier price log (superseded by stock_log)
  • supplier — supplier registry (FK target for lot_log and machine_log)
  • machine — device model registry
  • machine_log — device price/quote log

These tables are retained for historical data. QuoteForge does not read or write them at runtime.

Rules:

  • QuoteForge runtime must not depend on any legacy RFQ tables;
  • stock enrichment happens during sync and is persisted into SQLite;
  • normal UI requests must not query MariaDB tables directly;
  • qt_client_local_migrations was removed from the schema on 2026-03-21 (was in earlier drafts).

MariaDB Table Structures

Full column reference as of 2026-03-21 (RFQ_LOG final schema).

qt_categories

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
code varchar(20) UNIQUE NOT NULL
name varchar(100) NOT NULL
name_ru varchar(100)
display_order bigint DEFAULT 0
is_required tinyint(1) DEFAULT 0

qt_client_schema_state

PK: (username, hostname)

Column Type Notes
username varchar(100)
hostname varchar(255) DEFAULT ''
last_applied_migration_id varchar(128)
app_version varchar(64)
last_sync_at datetime
last_sync_status varchar(32)
pending_changes_count int DEFAULT 0
pending_errors_count int DEFAULT 0
configurations_count int DEFAULT 0
projects_count int DEFAULT 0
estimate_pricelist_version varchar(128)
warehouse_pricelist_version varchar(128)
competitor_pricelist_version varchar(128)
last_sync_error_code varchar(128)
last_sync_error_text text
last_checked_at datetime NOT NULL
updated_at datetime NOT NULL

qt_component_usage_stats

PK: lot_name

Column Type Notes
lot_name varchar(255)
quotes_total bigint DEFAULT 0
quotes_last30d bigint DEFAULT 0
quotes_last7d bigint DEFAULT 0
total_quantity bigint DEFAULT 0
total_revenue decimal(14,2) DEFAULT 0
trend_direction enum('up','stable','down') DEFAULT 'stable'
trend_percent decimal(5,2) DEFAULT 0
last_used_at datetime(3)

qt_competitors

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
name varchar(255) NOT NULL
code varchar(100) UNIQUE NOT NULL
delivery_basis varchar(50) DEFAULT 'DDP'
currency varchar(10) DEFAULT 'USD'
column_mapping longtext JSON
is_active tinyint(1) DEFAULT 1
created_at timestamp
updated_at timestamp ON UPDATE
price_uplift decimal(8,4) DEFAULT 1.3 effective_price = price / price_uplift

qt_configurations

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
uuid varchar(36) UNIQUE NOT NULL
user_id bigint UNSIGNED
owner_username varchar(100) NOT NULL
app_version varchar(64)
project_uuid char(36) FK → qt_projects.uuid ON DELETE SET NULL
name varchar(200) NOT NULL
items longtext JSON NOT NULL component list
total_price decimal(12,2)
notes text
is_template tinyint(1) DEFAULT 0
created_at datetime(3)
custom_price decimal(12,2)
server_count bigint DEFAULT 1
server_model varchar(100)
support_code varchar(20)
article varchar(80)
pricelist_id bigint UNSIGNED FK → qt_pricelists.id
warehouse_pricelist_id bigint UNSIGNED FK → qt_pricelists.id
competitor_pricelist_id bigint UNSIGNED FK → qt_pricelists.id
disable_price_refresh tinyint(1) DEFAULT 0
only_in_stock tinyint(1) DEFAULT 0
line_no int position within project
price_updated_at timestamp
vendor_spec longtext JSON

qt_lot_metadata

PK: lot_name

Column Type Notes
lot_name varchar(255)
category_id bigint UNSIGNED FK → qt_categories.id
vendor varchar(50)
model varchar(100)
specs longtext JSON
current_price decimal(12,2) cached computed price
price_method enum('manual','median','average','weighted_median') DEFAULT 'median'
price_period_days bigint DEFAULT 90
price_updated_at datetime(3)
request_count bigint DEFAULT 0
last_request_date date
popularity_score decimal(10,4) DEFAULT 0
price_coefficient decimal(5,2) DEFAULT 0 markup %
manual_price decimal(12,2)
meta_prices varchar(1000) raw price samples JSON
meta_method varchar(20) method used for last compute
meta_period_days bigint DEFAULT 90
is_hidden tinyint(1) DEFAULT 0

qt_partnumber_books

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
version varchar(30) UNIQUE NOT NULL
created_at timestamp
created_by varchar(100)
is_active tinyint(1) DEFAULT 0 only one active at a time
partnumbers_json longtext DEFAULT '[]' flat list of partnumbers

qt_partnumber_book_items

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
partnumber varchar(255) UNIQUE NOT NULL
lots_json longtext NOT NULL JSON array of lot_names
description varchar(10000)

qt_pricelists

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
source varchar(20) DEFAULT 'estimate' 'estimate' / 'warehouse' / 'competitor'
version varchar(20) NOT NULL UNIQUE with source
created_at datetime(3)
created_by varchar(100)
is_active tinyint(1) DEFAULT 1
usage_count bigint DEFAULT 0
expires_at datetime(3)
notification varchar(500) shown to clients on sync

qt_pricelist_items

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
pricelist_id bigint UNSIGNED NOT NULL FK → qt_pricelists.id
lot_name varchar(255) NOT NULL INDEX with pricelist_id
lot_category varchar(50)
price decimal(12,2) NOT NULL
price_method varchar(20)
price_period_days bigint DEFAULT 90
price_coefficient decimal(5,2) DEFAULT 0
manual_price decimal(12,2)
meta_prices varchar(1000)

qt_pricelist_sync_status

PK: username

Column Type Notes
username varchar(100)
last_sync_at datetime NOT NULL
updated_at datetime NOT NULL
app_version varchar(64)

qt_pricing_alerts

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
lot_name varchar(255) NOT NULL
alert_type enum('high_demand_stale_price','price_spike','price_drop','no_recent_quotes','trending_no_price')
severity enum('low','medium','high','critical') DEFAULT 'medium'
message text NOT NULL
details longtext JSON
status enum('new','acknowledged','resolved','ignored') DEFAULT 'new'
created_at datetime(3)

qt_projects

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
uuid char(36) UNIQUE NOT NULL
owner_username varchar(100) NOT NULL
code varchar(100) NOT NULL UNIQUE with variant
variant varchar(100) DEFAULT '' UNIQUE with code
name varchar(200)
tracker_url varchar(500)
is_active tinyint(1) DEFAULT 1
is_system tinyint(1) DEFAULT 0
created_at timestamp
updated_at timestamp ON UPDATE

qt_schema_migrations

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
filename varchar(255) UNIQUE NOT NULL
applied_at datetime(3)

qt_scheduler_runs

PK: job_name

Column Type Notes
job_name varchar(100)
last_started_at datetime
last_finished_at datetime
last_status varchar(20) DEFAULT 'idle'
last_error text
updated_at timestamp ON UPDATE

qt_vendor_partnumber_seen

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
source_type varchar(32) NOT NULL
vendor varchar(255) DEFAULT ''
partnumber varchar(255) UNIQUE NOT NULL
description varchar(10000)
last_seen_at datetime(3) NOT NULL
is_ignored tinyint(1) DEFAULT 0
is_pattern tinyint(1) DEFAULT 0
ignored_at datetime(3)
ignored_by varchar(100)
created_at datetime(3)
updated_at datetime(3)

stock_ignore_rules

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
target varchar(20) NOT NULL UNIQUE with match_type+pattern
match_type varchar(20) NOT NULL
pattern varchar(500) NOT NULL
created_at timestamp

stock_log

Column Type Notes
stock_log_id bigint UNSIGNED PK AUTO_INCREMENT
partnumber varchar(255) NOT NULL INDEX with date
supplier varchar(255)
date date NOT NULL
price decimal(12,2) NOT NULL
quality varchar(255)
comments text
vendor varchar(255) INDEX
qty decimal(14,3)

partnumber_log_competitors

Column Type Notes
id bigint UNSIGNED PK AUTO_INCREMENT
competitor_id bigint UNSIGNED NOT NULL FK → qt_competitors.id
partnumber varchar(255) NOT NULL
description varchar(500)
vendor varchar(255)
price decimal(12,2) NOT NULL
price_loccur decimal(12,2) local currency price
currency varchar(10)
qty decimal(12,4) DEFAULT 1
date date NOT NULL
created_at timestamp

Legacy tables (lot / lot_log / machine / machine_log / supplier)

Retained for historical data only. Not queried by QuoteForge.

lot: lot_name (PK, char 255), lot_category, lot_description lot_log: lot_log_id AUTO_INCREMENT, lot (FK→lot), supplier (FK→supplier), date, price double, quality, comments supplier: supplier_name (PK, char 255), supplier_comment machine: machine_name (PK, char 255), machine_description machine_log: machine_log_id AUTO_INCREMENT, date, supplier (FK→supplier), country, opty, type, machine (FK→machine), customer_requirement, variant, price_gpl, price_estimate, qty, quality, carepack, lead_time_weeks, prepayment_percent, price_got, Comment

Migrations

SQLite:

  • schema creation and additive changes go through GORM AutoMigrate;
  • data fixes, index repair, and one-off rewrites go through runLocalMigrations;
  • local migration state is tracked in local_schema_migrations.

MariaDB:

  • SQL files live in migrations/;
  • they are applied by go run ./cmd/qfs -migrate.