fix: systematic element matching bug in enhancement pipeline

- Problem: Element ID collisions between similar elements (logo h1 vs hero h1)
  causing content to be injected into wrong elements
- Root cause: Enhancer used naive tag+class matching instead of parser's
  sophisticated semantic analysis for element identification

Systematic solution:
- Enhanced parser architecture with exported utilities (GetClasses, ContainsClass)
- Added FindElementInDocument() with content-based semantic matching
- Replaced naive findAndInjectNodes() with parser-based element matching
- Removed code duplication between parser and enhancer packages

Backend improvements:
- Moved ID generation to backend for single source of truth
- Added ElementContext struct for frontend-backend communication
- Updated API handlers to support context-based content ID generation

Frontend improvements:
- Enhanced getElementMetadata() to extract semantic context
- Updated save flow to handle both enhanced and non-enhanced elements
- Improved API client to use backend-generated content IDs

Result:
- Unique content IDs: navbar-logo-200530 vs hero-title-a1de7b
- Precise element matching using content validation
- Single source of truth for DOM utilities in parser package
- Eliminated 40+ lines of duplicate code while fixing core bug
This commit is contained in:
2025-09-11 14:14:57 +02:00
parent f73e21ce6e
commit ef1d1083ce
12 changed files with 575 additions and 314 deletions

View File

@@ -104,10 +104,36 @@ export class InsertrCore {
// Get element metadata
getElementMetadata(element) {
const existingId = element.getAttribute('data-content-id');
if (existingId) {
// Enhanced site - use existing ID
return {
contentId: existingId,
contentType: element.getAttribute('data-content-type') || this.detectContentType(element),
element: element,
hasExistingId: true
};
} else {
// Non-enhanced site - prepare context for backend ID generation
return {
contentId: null, // Backend will generate
contentType: this.detectContentType(element),
element: element,
elementContext: this.extractElementContext(element),
hasExistingId: false
};
}
}
// Extract element context for backend ID generation
extractElementContext(element) {
return {
contentId: element.getAttribute('data-content-id') || this.generateDeterministicId(element),
contentType: element.getAttribute('data-content-type') || this.detectContentType(element),
element: element
tag: element.tagName.toLowerCase(),
classes: Array.from(element.classList),
original_content: element.textContent.trim(),
parent_context: this.getSemanticContext(element),
purpose: this.getPurpose(element)
};
}