Added structured changelog documentation:
- Created releases/memory/ directory to track changes between tags
- Each version has a .md file (v1.2.1.md, etc.) documenting commits and impact
- Updated CLAUDE.md with release notes reference
- Updated README.md with releases section
- Updated .gitignore to track releases/memory/ while ignoring other release artifacts
This helps reviewers and developers understand changes between versions
before making new updates to the codebase.
Initial entry: v1.2.1.md documenting the pricelist refactor and
configurator component substitution fix.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
After the recent refactor that removed CurrentPrice from local_components,
the configurator's autocomplete was filtering out all components because
it checked for the now-removed current_price field.
Instead, now load prices from the API when the user starts typing in a
component search field:
- Added ensurePricesLoaded() to fetch prices via /api/quote/price-levels
- Added componentPricesCache to store loaded prices
- Updated all 3 autocomplete modes (single, multi, section) to load prices
- Changed price checks from c.current_price to hasComponentPrice()
- Updated cart item creation to use cached prices
Components without prices are still filtered out as required, but the check
now uses API data rather than a removed database field.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
## Overview
Removed the CurrentPrice and SyncedAt fields from local_components, transitioning to a
pricelist-based pricing model where all prices are sourced from local_pricelist_items
based on the configuration's selected pricelist.
## Changes
### Data Model Updates
- **LocalComponent**: Now stores only metadata (LotName, LotDescription, Category, Model)
- Removed: CurrentPrice, SyncedAt (both redundant)
- Pricing is now exclusively sourced from local_pricelist_items
- **LocalConfiguration**: Added pricelist selection fields
- Added: WarehousePricelistID, CompetitorPricelistID
- These complement the existing PricelistID (Estimate)
### Migrations
- Added migration "drop_component_unused_fields" to remove CurrentPrice and SyncedAt columns
- Added migration "add_warehouse_competitor_pricelists" to add new pricelist fields
### Component Sync
- Removed current_price from MariaDB query
- Removed CurrentPrice assignment in component creation
- SyncComponentPrices now exclusively updates based on pricelist_items via quote calculation
### Quote Calculation
- Added PricelistID field to QuoteRequest
- Updated local-first path to use pricelist_items instead of component.CurrentPrice
- Falls back to latest estimate pricelist if PricelistID not specified
- Maintains offline-first behavior: local queries work without MariaDB
### Configuration Refresh
- Removed fallback on component.CurrentPrice
- Prices are only refreshed from local_pricelist_items
- If price not found in pricelist, original price is preserved
### API Changes
- Removed CurrentPrice from ComponentView
- Components API no longer returns pricing information
- Pricing is accessed via QuoteService or PricelistService
### Code Cleanup
- Removed UpdateComponentPricesFromPricelist() method
- Removed EnsureComponentPricesFromPricelists() method
- Updated UnifiedRepository to remove offline pricing logic
- Updated converters to remove CurrentPrice mapping
## Architecture Impact
- Components = metadata store only
- Prices = managed by pricelist system
- Quote calculation = owns all pricing logic
- Local-first behavior preserved: SQLite queries work offline, no MariaDB dependency
## Testing
- Build successful
- All code compiles without errors
- Ready for migration testing with existing databases
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add comprehensive database permissions documentation:
- Full list of required tables with their purpose
- Separate sections for: existing user grants, new user creation, and important notes
- Clarifies that sync tables (qt_client_local_migrations, qt_client_schema_state,
qt_pricelist_sync_status) must be created by DB admin - app doesn't need CREATE TABLE
- Explains read-only vs read-write permissions for each table
- Uses placeholder '<DB_USER>' instead of hardcoded usernames
This helps administrators set up proper permissions without CREATE TABLE requirements,
fixing the sync blockage issue in v1.1.0.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Sync was blocked because the migration registry table creation required
CREATE TABLE permissions that the database user might not have.
Changes:
- Check if migration registry tables exist before attempting to create them
- Skip creation if table exists and user lacks CREATE permissions
- Use information_schema to reliably check table existence
- Apply same fix to user sync status table creation
- Gracefully handle ALTER TABLE failures for backward compatibility
This allows sync to proceed even if the client is a read-limited database user,
as long as the required tables have already been created by an administrator.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Solve pagination issue where configs reference projects not in the
paginated list (default 10 items, but there could be 50+ projects).
Changes:
- Add GET /api/projects/all endpoint that returns ALL projects without
pagination as simple {uuid, name} objects
- Update frontend loadProjectsForConfigUI() to use /api/projects/all
instead of /api/projects?status=all
- Ensures all projects are available in projectNameByUUID for config
display, regardless of total project count
This fixes cases where project names don't display in /configs page
for configs that reference projects outside the paginated range.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Update filename format to include both project and quotation names:
YYYY-MM-DD (PROJECT-NAME) QUOTATION-NAME BOM.csv
Changes:
- Add ProjectName field to ExportRequest (optional)
- Update ExportCSV: use project_name if provided, otherwise fall back to name
- Update ExportConfigCSV: use config name for both project and quotation
Example filenames:
2026-02-09 (OPS-1957) config1 BOM.csv
2026-02-09 (MyProject) MyQuotation BOM.csv
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Fix issue where frontend was ignoring server's Content-Disposition
header and using only config name + '.csv' for exported files.
Added getFilenameFromResponse() helper to extract proper filename
from Content-Disposition header and use it for downloaded files.
Applied to both:
- exportCSV() function
- exportCSVWithCustomPrice() function
Now files are downloaded with correct format:
YYYY-MM-DD (PROJECT-NAME) BOM.csv
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Change exported CSV filename format from:
YYYY-MM-DD NAME SPEC.csv
To:
YYYY-MM-DD (NAME) BOM.csv
Applied to both:
- POST /api/export/csv (direct export)
- GET /api/configs/:uuid/export (config export)
All tests passing.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Remove unused stockMappingsCache variable (dead code after selectStockMappingRow removal)
- Move data-description from SVG to button element for reliable access
- Add disabled guard on bulk add/ignore buttons to prevent duplicate requests
- Return explicit error in UpsertIgnoreRule when rule already exists
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>