Files
QuoteForge/LOCAL_FIRST_INTEGRATION.md
Michael Chus 1f739a3ab2 Update CLAUDE.md TODO list and add local-first documentation
- 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>
2026-02-01 22:20:23 +03:00

6.1 KiB
Raw Blame History

Local-First Architecture Integration Guide

Overview

QuoteForge теперь поддерживает local-first архитектуру: приложение ВСЕГДА работает с SQLite (localdb), MariaDB используется только для синхронизации.

Реализованные компоненты

1. Конвертеры моделей (internal/localdb/converters.go)

Конвертеры между MariaDB и SQLite моделями:

  • ConfigurationToLocal() / LocalToConfiguration()
  • PricelistToLocal() / LocalToPricelist()
  • ComponentToLocal() / LocalToComponent()

2. LocalDB методы (internal/localdb/localdb.go)

Добавлены методы для работы с pending changes:

  • MarkChangesSynced(ids []int64) - помечает изменения как синхронизированные
  • GetPendingCount() - возвращает количество несинхронизированных изменений

3. Sync Service расширения (internal/services/sync/service.go)

Новые методы:

  • SyncPricelistsIfNeeded() - проверяет и скачивает новые прайслисты при необходимости
  • PushPendingChanges() - отправляет все pending changes на сервер
  • pushSingleChange() - обрабатывает один pending change
  • pushConfigurationCreate/Update/Delete() - специфичные методы для конфигураций

ВАЖНО: Конструктор изменен - теперь требует ConfigurationRepository:

syncService := sync.NewService(pricelistRepo, configRepo, local)

4. LocalConfigurationService (internal/services/local_configuration.go)

Новый сервис для работы с конфигурациями в local-first режиме:

  • Все операции CRUD работают через SQLite
  • Автоматически добавляет изменения в pending_changes
  • При создании конфигурации (если online) проверяет новые прайслисты
localConfigService := services.NewLocalConfigurationService(
    localDB,
    syncService,
    quoteService,
    isOnlineFunc,
)

5. Sync Handler расширения (internal/handlers/sync.go)

Новые endpoints:

  • POST /api/sync/push - отправить pending changes на сервер
  • GET /api/sync/pending/count - получить количество pending changes
  • GET /api/sync/pending - получить список pending changes

Интеграция

Шаг 1: Обновить main.go

// В cmd/server/main.go
syncService := sync.NewService(pricelistRepo, configRepo, local)

// Создать isOnline функцию
isOnlineFunc := func() bool {
    sqlDB, err := db.DB()
    if err != nil {
        return false
    }
    return sqlDB.Ping() == nil
}

// Создать LocalConfigurationService
localConfigService := services.NewLocalConfigurationService(
    local,
    syncService,
    quoteService,
    isOnlineFunc,
)

Шаг 2: Обновить ConfigurationHandler

Заменить ConfigurationService на LocalConfigurationService в handlers:

// Было:
configHandler := handlers.NewConfigurationHandler(configService, exportService)

// Стало:
configHandler := handlers.NewConfigurationHandler(localConfigService, exportService)

Шаг 3: Добавить endpoints для sync

В роутере добавить:

syncGroup := router.Group("/api/sync")
{
    syncGroup.POST("/push", syncHandler.PushPendingChanges)
    syncGroup.GET("/pending/count", syncHandler.GetPendingCount)
    syncGroup.GET("/pending", syncHandler.GetPendingChanges)
}

Как это работает

Создание конфигурации

  1. Пользователь создает конфигурацию
  2. LocalConfigurationService.Create():
    • Если online → SyncPricelistsIfNeeded() проверяет новые прайслисты
    • Сохраняет конфигурацию в SQLite
    • Добавляет в pending_changes с operation="create"
  3. Конфигурация доступна локально сразу

Синхронизация с сервером

Manual sync:

POST /api/sync/push

Background sync (TODO):

  • Периодический worker вызывает syncService.PushPendingChanges()
  • Проверяет online статус
  • Отправляет все pending changes на сервер
  • Удаляет успешно синхронизированные записи

Offline режим

  1. Все операции работают нормально через SQLite
  2. Изменения копятся в pending_changes
  3. При восстановлении соединения автоматически синхронизируются

Pending Changes Queue

Таблица pending_changes:

type PendingChange struct {
    ID         int64     // Auto-increment
    EntityType string    // "configuration", "project", "specification"
    EntityUUID string    // UUID сущности
    Operation  string    // "create", "update", "delete"
    Payload    string    // JSON snapshot сущности
    CreatedAt  time.Time
    Attempts   int       // Счетчик попыток синхронизации
    LastError  string    // Последняя ошибка синхронизации
}

TODO для Phase 2.5

  • Background sync worker (автоматическая синхронизация каждые N минут)
  • Conflict resolution (при конфликтах обновления)
  • UI: pending counter в header
  • UI: manual sync button
  • UI: conflict alerts
  • Retry logic для failed pending changes
  • RefreshPrices для local mode (через local_components)

Testing

# Compile
go build ./cmd/server

# Run
./quoteforge

# Check pending changes
curl http://localhost:8080/api/sync/pending/count

# Manual sync
curl -X POST http://localhost:8080/api/sync/push