feat: Add PWA support and consolidate CSS design system

- Add PWA manifest, icons (192x192, 512x512), and service worker
- Register service worker in index.html with Apple mobile web app support
- Consolidate CSS variables and design tokens documentation
- Update PrimeVue overrides for consistent theming
- Refactor data-entry components to use shared CSS patterns
- Add frontend-style-auditor agent for style consistency checks
- Minor OCR validation and job worker improvements
- Update start-prod.sh configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-06 14:00:21 +00:00
parent b2fe26da3a
commit 1bb3a382de
33 changed files with 1846 additions and 513 deletions

View File

@@ -353,9 +353,9 @@ async def start_job_worker() -> bool:
logger.info("[JobWorker] Pre-warming OCR worker pool (background)...")
warmup_success = await ocr_worker_pool.prewarm(timeout=90.0)
if warmup_success:
logger.info("[JobWorker] OCR worker pool pre-warmed successfully")
logger.info("[JobWorker] OCR worker pool pre-warmed successfully")
else:
logger.warning("[JobWorker] ⚠️ Worker pool pre-warm failed, first request will be slower")
logger.warning("[JobWorker] Worker pool pre-warm failed, first request will be slower")
asyncio.create_task(_background_prewarm())

View File

@@ -238,7 +238,7 @@ class PaymentSumRule(ValidationRule):
return ValidationResult(
is_valid=False,
confidence_penalty=0.4,
message=f"Payment sum {payment_sum:.2f} RON Total {total:.2f} RON (diff: {diff:.2f} RON). Consider auto-correction.",
message=f"Payment sum {payment_sum:.2f} RON != Total {total:.2f} RON (diff: {diff:.2f} RON). Consider auto-correction.",
severity="error"
)
@@ -299,7 +299,7 @@ class TVAEntriesSumRule(ValidationRule):
return ValidationResult(
is_valid=False,
confidence_penalty=0.2,
message=f"TVA entries sum {entries_sum:.2f} RON TVA total {tva_total:.2f} RON (diff: {diff:.2f} RON)",
message=f"TVA entries sum {entries_sum:.2f} RON != TVA total {tva_total:.2f} RON (diff: {diff:.2f} RON)",
severity="warning"
)
@@ -783,7 +783,7 @@ class OCRValidationEngine:
else:
warnings.append(msg)
print(f" {msg}", flush=True)
print(f" [X] {msg}", flush=True)
# Track confidence penalty for the relevant field based on rule
if result.confidence_penalty > 0:
@@ -797,7 +797,7 @@ class OCRValidationEngine:
if f in extraction_result:
confidence_adjustments[f] = result.confidence_penalty
else:
print(f" {rule.rule_name}: {result.message}", flush=True)
print(f" [OK] {rule.rule_name}: {result.message}", flush=True)
# Step 2: Cross-field validation
print("\n[Validation] Step 2: Cross-field validation...", flush=True)
@@ -812,7 +812,7 @@ class OCRValidationEngine:
else:
warnings.append(msg)
print(f" {msg}", flush=True)
print(f" [X] {msg}", flush=True)
# Track confidence penalty for the relevant field based on rule
if result.confidence_penalty > 0:
@@ -826,7 +826,7 @@ class OCRValidationEngine:
if f in extraction_result:
confidence_adjustments[f] = result.confidence_penalty
else:
print(f" {rule.rule_name}: {result.message}", flush=True)
print(f" [OK] {rule.rule_name}: {result.message}", flush=True)
# Step 3: Inter-OCR consistency checks
if light_result and medium_result:
@@ -845,7 +845,7 @@ class OCRValidationEngine:
if not result.is_valid:
msg = f"[Inter-OCR] {result.message}"
warnings.append(msg)
print(f" {msg}", flush=True)
print(f" [X] {msg}", flush=True)
# Store ratio for metadata
ratio = max(
@@ -854,7 +854,7 @@ class OCRValidationEngine:
) / min(light_result["amount"], medium_result["amount"])
inter_ocr_ratios["amount"] = ratio
else:
print(f" {result.message}", flush=True)
print(f" [OK] {result.message}", flush=True)
# Determine if manual review is needed
# Only flag for review if there are errors OR high-severity warnings

View File

@@ -124,7 +124,7 @@ class OCRService:
# Check if memory is high - force GC before processing
if mem_before > self._memory_threshold_mb:
print(f"[OCR Service] ⚠️ Memory high ({mem_before:.0f}MB > {self._memory_threshold_mb}MB), forcing GC...", flush=True)
print(f"[OCR Service] WARNING: Memory high ({mem_before:.0f}MB > {self._memory_threshold_mb}MB), forcing GC...", flush=True)
gc.collect()
mem_after_gc = get_memory_usage_mb()
print(f"[OCR Service] Memory after pre-GC: {mem_after_gc:.0f}MB", flush=True)
@@ -188,7 +188,7 @@ class OCRService:
extraction.raw_text = "\n\n".join(raw_texts)
elapsed_ms = int((time.time() - start_time) * 1000)
extraction.processing_time_ms = elapsed_ms
print(f"[OCR] ✓✓✓ EARLY EXIT at Step 1 - All fields found! ({elapsed_ms}ms) ✓✓✓", flush=True)
print(f"[OCR] *** EARLY EXIT at Step 1 - All fields found! ({elapsed_ms}ms) ***", flush=True)
# Cleanup before return
del image
if images:
@@ -244,7 +244,7 @@ class OCRService:
extraction.ocr_engine = "paddle-adaptive"
elapsed_ms = int((time.time() - start_time) * 1000)
extraction.processing_time_ms = elapsed_ms
print(f"[OCR] ✓✓✓ EARLY EXIT at Step 2 - All fields found after merge! ({elapsed_ms}ms) ✓✓✓", flush=True)
print(f"[OCR] *** EARLY EXIT at Step 2 - All fields found after merge! ({elapsed_ms}ms) ***", flush=True)
# Cleanup before return
del image
if images:
@@ -399,7 +399,7 @@ class OCRService:
print(f" - Needs Manual Review: {extraction.needs_manual_review}", flush=True)
if extraction.validation_warnings:
for warning in extraction.validation_warnings:
print(f" ⚠️ {warning}", flush=True)
print(f" [!] {warning}", flush=True)
return True, message, extraction
@@ -611,7 +611,7 @@ class OCRService:
print(f"[OCR] Missing: {', '.join(missing)} - continuing", flush=True)
return False
print(f"[OCR] All 5 fields found with {ext.overall_confidence:.0%} confidence", flush=True)
print(f"[OCR] OK: All 5 fields found with {ext.overall_confidence:.0%} confidence", flush=True)
return True
def _complement_extraction(

View File

@@ -157,7 +157,7 @@ class EventMonitor:
# Changes detected!
logger.info(
f"Schema {schema} (company {company_id}): "
f"id_act changed {cached_watermark} {current_max}"
f"id_act changed {cached_watermark} -> {current_max}"
)
# Update watermark