Implements automatic repair mechanism for pending changes with sync errors:
- Projects: validates and fixes empty name/code fields
- Configurations: ensures project references exist or assigns system project
- Clears errors and resets attempts to give changes another sync chance
Backend:
- LocalDB.RepairPendingChanges() with smart validation logic
- POST /api/sync/repair endpoint
- Detailed repair results with remaining errors
Frontend:
- Auto-repair section in sync modal shown when errors exist
- "ИСПРАВИТЬ" button with clear explanation of actions
- Real-time feedback with result messages
Co-Authored-By: Claude Opus 4.6 <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>
**Problem:**
Pricelist page showed empty list in offline mode even though
local pricelists existed in SQLite cache.
**Solution:**
Modified PricelistHandler.List() to fallback to local pricelists:
1. Check if server list is empty (offline)
2. Load from localDB.GetLocalPricelists()
3. Convert LocalPricelist to summary format
4. Add "synced_from": "local" field
5. Add "offline": true flag
**Response format:**
```json
{
"offline": true,
"total": 4,
"pricelists": [
{
"version": "2026-02-02-002",
"created_by": "sync",
"synced_from": "local",
"is_active": true
}
]
}
```
**Impact:**
- ✅ Local pricelists visible in offline mode
- ✅ UI can show cached pricelist versions
- ✅ Users can browse pricelists without connection
- ✅ Clear indication of local/remote source
Part of Phase 2.5: Full Offline Mode
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
**Problem:**
Configurator was broken in offline mode - no component search
and no price calculation because /api/components returned empty list.
**Solution:**
Added local component fallback to ComponentHandler:
1. **ComponentHandler with localDB** (component.go)
- Added localDB parameter to NewComponentHandler
- List() now fallbacks to local_components when offline
- Converts LocalComponent to ComponentView format
- Preserves prices from local cache
2. **Updated initialization** (main.go)
- Pass localDB to NewComponentHandler
**Impact:**
- ✅ Component search works offline
- ✅ Prices load from local_components table
- ✅ Configuration creation fully functional offline
- ✅ Price calculation works with cached prices
**Testing:**
- Verified /api/components returns local components
- Verified current_price field populated from cache
- Search, filtering, and pagination work correctly
Fixes critical Phase 2.5 offline mode issue.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
**Changes:**
1. **Admin menu always visible** (base.html)
- Removed 'hidden' class from "Администратор цен" link
- Menu no longer depends on write permission check
- Users can access pricing/pricelists pages in offline mode
2. **Online status checks for mutations** (admin_pricing.html)
- Added checkOnlineStatus() helper function
- createPricelist() checks online before creating
- deletePricelist() checks online before deleting
- Clear user feedback when operations blocked offline
**User Impact:**
- Admin menu accessible in both online and offline modes
- View-only access to pricelists when offline
- Clear error messages when attempting mutations offline
- Better offline-first UX
Part of Phase 2.5: Full Offline Mode
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed application freezing in offline mode by preventing unnecessary
reconnection attempts:
**Changes:**
1. **DSN timeouts** (localdb.go)
- Added timeout=3s, readTimeout=3s, writeTimeout=3s to MySQL DSN
- Reduces connection timeout from 75s to 3s when MariaDB unreachable
2. **Fast /api/db-status** (main.go)
- Check connection status before attempting GetDB()
- Avoid reconnection attempts on every status request
- Returns cached offline status instantly
3. **Optimized sync service** (sync/service.go)
- GetStatus() checks connection status before GetDB()
- NeedSync() skips server check if already offline
- Prevents repeated 3s timeouts on every sync info request
4. **Local pricelist fallback** (pricelist.go)
- GetLatest() returns local pricelists when server offline
- UI can now display pricelist version in offline mode
5. **Better UI error messages** (configs.html)
- 404 shows "Не загружен" instead of "Ошибка загрузки"
- Network errors show "Не доступен" in gray
- Distinguishes between missing data and real errors
**Performance:**
- Before: 75s timeout on every offline request
- After: <5ms response time in offline mode
- Cached error state prevents repeated connection attempts
**User Impact:**
- UI no longer freezes when loading pages offline
- Instant page loads and API responses
- Pricelist version displays correctly in offline mode
- Clear visual feedback for offline state
Fixes Phase 2.5 offline mode performance issues.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Updated sync-related code to use ConnectionManager instead of direct
database references:
- SyncService now creates repositories on-demand when connection available
- SyncHandler uses ConnectionManager for lazy DB access
- Added ComponentFilter and ListComponents to localdb for offline queries
- All sync operations check connection status before attempting MariaDB access
This completes the transition to offline-first architecture where all
database access goes through ConnectionManager.
Part of Phase 2.5: Full Offline Mode
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Introduced ConnectionManager to support offline-first architecture:
- New internal/db/connection.go with thread-safe connection management
- Lazy connection establishment (5s timeout, 10s cooldown)
- Automatic ping caching (30s interval) to avoid excessive checks
- Updated middleware/offline.go to use ConnectionManager.IsOnline()
- Updated sync/worker.go to use ConnectionManager instead of direct DB
This enables the application to start without MariaDB and gracefully
handle offline/online transitions.
Part of Phase 2.5: Full Offline Mode
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed two critical issues preventing offline-first operation:
1. **Instant startup** - Removed blocking GetDB() call during server
initialization. Server now starts in <10ms instead of 1+ minute.
- Changed setupRouter() to use lazy DB connection via ConnectionManager
- mariaDB connection is now nil on startup, established only when needed
- Fixes timeout issues when MariaDB is unreachable
2. **Offline mode nil pointer panics** - Added graceful degradation
when database is offline:
- ComponentService.GetCategories() returns DefaultCategories if repo is nil
- ComponentService.List/GetByLotName checks for nil repo
- PricelistService methods return empty/error responses in offline mode
- All methods properly handle nil repositories
**Before**: Server startup took 1min+ and crashed with nil pointer panic
when trying to load /configurator page offline.
**After**: Server starts instantly and serves pages in offline mode using
DefaultCategories and SQLite data.
Related to Phase 2.5: Full Offline Mode (local-first architecture)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create htmx-powered partial template for sync status display
- Show Online/Offline indicator with color coding (green/red)
- Display pending changes count badge when there are unsynced items
- Add Sync button to push pending changes (appears only when needed)
- Auto-refresh every 30 seconds via htmx polling
- Replace JavaScript-based sync indicator with server-rendered partial
- Integrate SyncStatusPartial handler with template rendering
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Consolidate UI TODO items into single sync status partial task
- Move conflict resolution to Phase 4
- Add LOCAL_FIRST_INTEGRATION.md with architecture guide
- Add unified repository interface for future use
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add development phases (pricelists, projects, local SQLite, price versioning)
- Add new table schemas (qt_pricelists, qt_projects, qt_specifications)
- Add local SQLite database structure for offline work
- Remove Docker files (distributing as binary only)
- Disable RBAC for initial phases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add price_updated_at field to qt_configurations table to track when prices were last updated
- Add RefreshPrices() method in configuration service to update all component prices with current values from database
- Add POST /api/configs/:uuid/refresh-prices API endpoint for price updates
- Add "Refresh Prices" button in configurator UI next to Save button
- Display last price update timestamp in human-readable format (e.g., "5 min ago", "2 hours ago")
- Create migration 004_add_price_updated_at.sql for database schema update
- Update CLAUDE.md documentation with new API endpoint and schema changes
- Add MIGRATION_PRICE_REFRESH.md with detailed migration instructions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add is_hidden field to hide components from configurator
- Add colored dot indicator showing component usage status:
- Green: available in configurator
- Cyan: used as source for meta-articles
- Gray: hidden from configurator
- Optimize price recalculation with caching and skip unchanged
- Show current lot name during price recalculation
- Add Dockerfile (Alpine-based multi-stage build)
- Add docker-compose.yml and .dockerignore
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>