Fix sync errors for duplicate projects and add modal scrolling

Root cause: Projects with duplicate (code, variant) pairs fail to sync
due to unique constraint on server. Example: multiple "OPS-1934" projects
with variant="Dell" where one already exists on server.

Fixes:
1. Sync service now detects duplicate (code, variant) on server and links
   local project to existing server project instead of failing
2. Local repair checks for duplicate (code, variant) pairs and deduplicates
   by appending UUID suffix to variant
3. Modal now scrollable with fixed header/footer (max-h-90vh)

This allows users to sync projects that were created offline with
conflicting codes/variants without losing data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 21:25:22 +03:00
parent b153afbf51
commit 8508ee2921
3 changed files with 48 additions and 9 deletions

View File

@@ -1088,7 +1088,9 @@ func (l *LocalDB) RepairPendingChanges() (int, []string, error) {
return repaired, remainingErrors, nil
}
// repairProjectChange validates and fixes project data
// repairProjectChange validates and fixes project data.
// Note: This only validates local data. Server-side conflicts (like duplicate code+variant)
// are handled by sync service layer with deduplication logic.
func (l *LocalDB) repairProjectChange(change *PendingChange) error {
project, err := l.GetProjectByUUID(change.EntityUUID)
if err != nil {
@@ -1123,6 +1125,20 @@ func (l *LocalDB) repairProjectChange(change *PendingChange) error {
modified = true
}
// Check for local duplicates with same (code, variant)
var duplicate LocalProject
err = l.db.Where("code = ? AND variant = ? AND uuid != ?", project.Code, project.Variant, project.UUID).
First(&duplicate).Error
if err == nil {
// Found local duplicate - deduplicate by appending UUID suffix to variant
if project.Variant == "" {
project.Variant = project.UUID[:8]
} else {
project.Variant = project.Variant + "-" + project.UUID[:8]
}
modified = true
}
if modified {
if err := l.SaveProject(project); err != nil {
return fmt.Errorf("saving repaired project: %w", err)