Files
QuoteForge/bible-local/02-architecture.md
T
2026-03-17 18:34:28 +03:00

91 lines
3.8 KiB
Markdown

# 02 - Architecture
## Local-first rule
SQLite is the runtime source of truth.
MariaDB is sync transport plus setup and migration tooling.
```text
browser -> Gin handlers -> SQLite
-> pending_changes
background sync <------> MariaDB
```
Rules:
- user CRUD must continue when MariaDB is offline;
- runtime handlers and pages must read and write SQLite only;
- MariaDB access in runtime code is allowed only inside sync and setup flows;
- no live MariaDB fallback for reads that already exist in local cache.
## Sync contract
Bidirectional:
- projects;
- configurations;
- `vendor_spec`;
- pending change metadata.
Pull-only:
- components;
- pricelists and pricelist items;
- partnumber books and partnumber book items.
Readiness guard:
- every sync push/pull runs a preflight check;
- blocked sync returns `423 Locked` with a machine-readable reason;
- local work continues even when sync is blocked.
- sync metadata updates must preserve project `updated_at`; sync time belongs in `synced_at`, not in the user-facing last-modified timestamp.
- pricelist pull must persist a new local snapshot atomically: header and items appear together, and `last_pricelist_sync` advances only after item download succeeds.
- UI sync status must distinguish "last sync failed" from "up to date"; if the app can prove newer server pricelist data exists, the indicator must say local cache is incomplete.
## Pricing contract
Prices come only from `local_pricelist_items`.
Rules:
- `local_components` is metadata-only;
- quote calculation must not read prices from components;
- latest pricelist selection ignores snapshots without items;
- auto pricelist mode stays auto and must not be persisted as an explicit resolved ID.
## Configuration versioning
Configuration revisions are append-only snapshots stored in `local_configuration_versions`.
Rules:
- the editable working configuration is always the implicit head named `main`; UI must not switch the user to a numbered revision after save;
- create a new revision when spec, BOM, or pricing content changes;
- revision history is retrospective: the revisions page shows past snapshots, not the current `main` state;
- rollback creates a new head revision from an old snapshot;
- rename, reorder, project move, and similar operational edits do not create a new revision snapshot;
- revision deduplication includes `items`, `server_count`, `total_price`, `custom_price`, `vendor_spec`, pricelist selectors, `disable_price_refresh`, and `only_in_stock`;
- BOM updates must use version-aware save flow, not a direct SQL field update;
- current revision pointer must be recoverable if legacy or damaged rows are found locally.
## Sync UX
UI-facing sync status must never block on live MariaDB calls.
Rules:
- navbar sync indicator and sync info modal read only local cached state from SQLite/app settings;
- background/manual sync may talk to MariaDB, but polling endpoints must stay fast even on slow or broken connections;
- any MariaDB timeout/invalid-connection during sync must invalidate the cached remote handle immediately so UI stops treating the connection as healthy.
## Naming collisions
UI-driven rename and copy flows use one suffix convention for conflicts.
Rules:
- configuration and variant names must auto-resolve collisions with `_копия`, then `_копия2`, `_копия3`, and so on;
- copy checkboxes and copy modals must prefill `_копия`, not ` (копия)`;
- the literal variant name `main` is reserved and must not be allowed for non-main variants.
## Vendor BOM contract
Vendor BOM is stored in `vendor_spec` on the configuration row.
Rules:
- PN to LOT resolution uses the active local partnumber book;
- canonical persisted mapping is `lot_mappings[]`;
- QuoteForge does not use legacy BOM tables such as `qt_bom`, `qt_lot_bundles`, or `qt_lot_bundle_items`.