Files
PriceForge/bible/history.md

3.7 KiB

Change History

Architectural decisions and significant refactoring are recorded here. Every architectural decision MUST be documented in this file.


2026-02-20: Seen Registry Deduplication by Partnumber

Decision

Changed qt_vendor_partnumber_seen semantics to one row per partnumber (vendor/source are no longer part of uniqueness).

Rationale

  • Eliminates duplicate seen rows when the same partnumber appears both with vendor and without vendor.
  • Keeps ignore behavior consistent regardless of vendor presence.
  • Simplifies operational cleanup and prevents re-creation of vendor/no-vendor duplicates.

Constraints

  • partnumber is now the unique key in seen registry.
  • Ignore checks are resolved by partnumber only.
  • Stock provenance must be preserved (source_type='stock') when stock data exists for the partnumber.

Files

  • Migration: migrations/025_dedup_vendor_seen_by_partnumber.sql
  • Service: internal/services/stock_import.go
  • Service: internal/services/vendor_mapping.go
  • Model: internal/models/lot.go

2026-02-18: Global Vendor Partnumber Mapping

Decision

Implemented global vendor partnumber → LOT mapping with bundle support and seen-based ignore logic.

Key rules

  • lot_partnumbers is the canonical mapping contract (1:1 per key).
  • Composite mappings use internal bundle tables (qt_lot_bundles, qt_lot_bundle_items).
  • Ignore logic moved from stock_ignore_rules to qt_vendor_partnumber_seen.is_ignored.
  • Resolver order: exact (vendor, partnumber) → fallback (vendor='', partnumber).

Rationale

  • Preserves external/client contracts (lot_partnumbers, LOT-based pricelists).
  • Avoids multi-row ambiguity in lot_partnumbers.
  • Supports complex assembled vendor SKUs without client-side changes.
  • Centralizes ignore behavior across all sources via seen-registry.

Constraints

  • Bundle LOT is internal and must stay hidden in regular LOT list by default.
  • Resolver order is mandatory and fixed.
  • Bundle allocation for missing estimate: fallback from previous active warehouse pricelist; if absent → 0.

Files

  • Migration: migrations/023_vendor_partnumber_global_mapping.sql
  • Backfill: migrations/024_backfill_vendor_seen_from_stock_and_ignore.sql
  • Resolver: internal/lotmatch/matcher.go
  • Service: internal/services/vendor_mapping.go
  • Warehouse calc: internal/warehouse/snapshot.go
  • Stock import: internal/services/stock_import.go
  • API: internal/handlers/pricing.go, cmd/pfs/main.go

2026-02-10: LOT Page Refactoring

Decision

Moved LOT management to a dedicated /lot page. Removed LOT tab from Pricing Admin.

What changed

  • Created web/templates/lot.html — two tabs: LOT (component management) and Mappings (partnumber ↔ LOT).
  • Removed LOT tab from admin_pricing.html; default tab changed to estimate.
  • Removed "Сопоставление partnumber → LOT" section from Warehouse tab.
  • Updated navigation: LOT → /lot, Pricing Admin → /admin/pricing.
  • Added Lot() handler in internal/handlers/web.go.
  • Added /lot route in cmd/pfs/main.go.

Rationale

Separation of concerns: LOT/component management is distinct from pricing administration.


Warehouse Pricing: Weighted Average

Decision

Warehouse pricelist uses weighted_avg (quantity-weighted average) as the sole price calculation method. Commit edff712 switched from weighted_median to weighted_avg.

  • price_method field always contains "weighted_avg".
  • No price_period_days, price_coefficient, manual_price, meta_prices in warehouse pricelists.

Architecture Conventions

All future architectural decisions must be documented here with:

  • Date
  • Decision summary
  • Rationale
  • Constraints / invariants
  • Affected files