diff --git a/bible-local/02-architecture.md b/bible-local/02-architecture.md index bd24cc6..cc3b67e 100644 --- a/bible-local/02-architecture.md +++ b/bible-local/02-architecture.md @@ -40,14 +40,25 @@ Readiness guard: ## Pricing contract -Prices come only from `local_pricelist_items`. +`local_pricelist_items` is the single source of truth for both prices and component catalog (lot_name + lot_category). There is no separate component catalog table. Rules: -- `local_components` is metadata-only; -- quote calculation must not read prices from components; +- `local_components` table has been removed; do not recreate it; +- component list for the configurator autocomplete comes from `local_pricelist_items` via `ListComponents`; +- quote calculation reads prices from `local_pricelist_items` only; - latest pricelist selection ignores snapshots without items; - auto pricelist mode stays auto and must not be persisted as an explicit resolved ID. +## lot_name case handling + +lot_names in `local_pricelist_items` may be stored in mixed case in databases synced before normalization was enforced. `NormalizeLotName` (uppercase + trim) is applied at sync time via `PricelistItemToLocal`, but existing rows are not retroactively updated. + +Rules: +- all SQLite queries that filter by `lot_name` must use `UPPER(lot_name) IN ?` or `UPPER(lot_name) = ?` with an uppercased input — never a bare `=` or `IN` on a string that may have been sourced from user input or a legacy row; +- result map keys must preserve the original case passed by the caller (build a `uppercase → original` index before the query); +- `GetLocalPricesForLots` is the canonical pattern: it uppercases the input list, queries with `UPPER(lot_name) IN ?`, and returns keys that match the input lot_names; +- frontend JS must never infer a component category from the lot_name prefix; `lot_category` from `local_pricelist_items` is the only valid source; items without a category fall into the "Other" tab. + ## Pricing tab layout The Pricing tab (Ценообразование) has two tables: Buy (Цена покупки) and Sale (Цена продажи). @@ -133,7 +144,7 @@ full contract and JSON schemas. | `required_categories` | Per-config-type badge on tabs with unfilled required categories | Rules: -- sync runs after `SyncComponents`; failure is non-fatal (Warn log only); +- sync runs as part of the pricelist pull; failure is non-fatal (Warn log only); - `local_qt_settings` is a read-only cache — never written by user actions; - absent or unparseable settings: QF uses hardcoded fallbacks for that key only; - `config_types[].categories` is an allowlist: a category absent from all types is shown everywhere; diff --git a/bible-local/03-database.md b/bible-local/03-database.md index 2da1dd7..e082b37 100644 --- a/bible-local/03-database.md +++ b/bible-local/03-database.md @@ -8,9 +8,8 @@ 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_pricelist_items` | pricelist rows; the only runtime source of prices and component catalog | | `local_projects` | user projects | | `local_configurations` | user configurations | | `local_configuration_versions` | immutable revision snapshots | @@ -25,8 +24,9 @@ Main tables: 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. +- `local_pricelist_items` is the only valid runtime source of prices and component catalog; do not add a separate component cache table; +- configuration `items` and `vendor_spec` are stored as JSON payloads inside configuration rows; +- `local_components` table has been removed; any reference to it is dead code. ## MariaDB