Refactor scheduler and settings UI
This commit is contained in:
@@ -5,6 +5,107 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-03-07: Embedded Scheduler with MariaDB Advisory Locks
|
||||
|
||||
### Decision
|
||||
|
||||
Moved periodic cron-style maintenance from an external `cmd/cron` runtime requirement into the main `pfs` application. Every app instance may run the scheduler loop, but each job is serialized across the shared MariaDB using advisory locks.
|
||||
|
||||
### What changed
|
||||
|
||||
- Added embedded scheduler in `internal/scheduler/scheduler.go`.
|
||||
- Added persisted scheduler state table `qt_scheduler_runs` via migration `030_add_scheduler_runs.sql`.
|
||||
- `pfs` now starts the scheduler on boot when `scheduler.enabled = true`.
|
||||
- Added `GET /api/admin/pricing/scheduler-runs` and scheduler status table on the Settings page (`/setup`).
|
||||
- Consolidated DB settings into `/setup`; removed the obsolete connection-settings modal flow and duplicate `/api/connection-settings*` routes.
|
||||
- Added config section `scheduler` with per-job intervals:
|
||||
- `alerts_interval`
|
||||
- `update_prices_interval`
|
||||
- `update_popularity_interval`
|
||||
- `reset_weekly_counters_interval`
|
||||
- `reset_monthly_counters_interval`
|
||||
- Coordination between multiple app instances uses MariaDB `GET_LOCK/RELEASE_LOCK` with one lock per job.
|
||||
- `cmd/cron` remains available as a manual one-shot utility, but is no longer required for normal operation.
|
||||
|
||||
### Rationale
|
||||
|
||||
PriceForge is deployed as local applications without a dedicated always-on server process that could own cron scheduling centrally. Embedding the scheduler into each app keeps the system self-contained while DB advisory locks prevent simultaneous job execution against the same database.
|
||||
|
||||
### Constraints
|
||||
|
||||
- Scheduler safety depends on MariaDB advisory locks; without DB connectivity, jobs do not run.
|
||||
- Jobs are interval-based from `last_finished_at` stored in `qt_scheduler_runs`.
|
||||
- Duplicate scheduler loops across multiple app instances are acceptable because only one instance acquires the per-job lock at a time.
|
||||
|
||||
### Files
|
||||
|
||||
- Scheduler: `internal/scheduler/scheduler.go`
|
||||
- Scheduler tests: `internal/scheduler/scheduler_test.go`
|
||||
- Config: `internal/config/config.go`, `config.example.yaml`
|
||||
- App startup: `cmd/pfs/main.go`
|
||||
- Migration: `migrations/030_add_scheduler_runs.sql`
|
||||
|
||||
## 2026-03-07: Remove Unused BOM Storage
|
||||
|
||||
### Decision
|
||||
|
||||
Removed `qt_bom` and `qt_configurations.bom_id` because the schema was never adopted by runtime code and created dead database surface area.
|
||||
|
||||
### What changed
|
||||
|
||||
- Added migration `029_drop_unused_qt_bom.sql` to drop:
|
||||
- foreign key `fk_qt_configurations_bom`
|
||||
- index `idx_qt_configurations_bom_id` if present
|
||||
- column `qt_configurations.bom_id`
|
||||
- table `qt_bom`
|
||||
- Removed `BOM` model from `internal/models/lot.go`.
|
||||
- Removed `Configuration.BOMID` from `internal/models/configuration.go`.
|
||||
- Removed `BOM` from `internal/models/models.go` auto-migration registry.
|
||||
|
||||
### Rationale
|
||||
|
||||
The repository had schema and model stubs for BOM persistence, but no handler, service, repository, sync path, or UI used them. Keeping unused schema increases maintenance cost and confuses future changes.
|
||||
|
||||
### Constraints
|
||||
|
||||
- This removal is safe only because no runtime code reads or writes `qt_bom` or `qt_configurations.bom_id`.
|
||||
- Historical BOM payloads in `qt_bom` are not migrated elsewhere; the table is treated as disposable unused state.
|
||||
|
||||
### Files
|
||||
|
||||
- Migration: `migrations/029_drop_unused_qt_bom.sql`
|
||||
- Models: `internal/models/lot.go`, `internal/models/configuration.go`, `internal/models/models.go`
|
||||
|
||||
## 2026-03-07: Purge LOT Names Polluting Seen Registry
|
||||
|
||||
### Decision
|
||||
|
||||
Rows in `qt_vendor_partnumber_seen` where `partnumber` is actually equal to `lot.lot_name` are treated as polluted data from external systems and must not appear in Global Vendor Mappings UI.
|
||||
|
||||
### What changed
|
||||
|
||||
- Added `purgeSeenLotNames` in `internal/services/seen_cleanup.go`.
|
||||
- `VendorMappingService.List` now deletes polluted seen rows before building the Vendor Mappings list.
|
||||
- `GetUnmappedPartnumbers` now explicitly excludes `qt_vendor_partnumber_seen.partnumber` values that match an existing `lot.lot_name`.
|
||||
- Added regression test coverage in `internal/services/vendor_mapping_test.go`.
|
||||
|
||||
### Rationale
|
||||
|
||||
Another application writes non-partnumber LOT identifiers into `qt_vendor_partnumber_seen`. Those rows are noise for operators and should not be shown as unmapped vendor partnumbers.
|
||||
|
||||
### Constraints
|
||||
|
||||
- Only polluted seen rows are removed: if a value equal to `lot.lot_name` also has an explicit mapping in `lot_partnumbers`, it is preserved.
|
||||
- The cleanup targets the seen registry only; canonical PN mappings in `lot_partnumbers` are not touched.
|
||||
|
||||
### Files
|
||||
|
||||
- Service: `internal/services/seen_cleanup.go`
|
||||
- Service: `internal/services/vendor_mapping.go`
|
||||
- Handler: `internal/handlers/pricing.go`
|
||||
- Tests: `internal/services/vendor_mapping_test.go`
|
||||
- Docs: `bible-local/vendor-mapping.md`
|
||||
|
||||
## 2026-02-21: Partnumber Book Snapshots for QuoteForge
|
||||
|
||||
### Decision
|
||||
|
||||
Reference in New Issue
Block a user