- 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>
6.1 KiB
6.1 KiB
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 changepushConfigurationCreate/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 changesGET /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)
}
Как это работает
Создание конфигурации
- Пользователь создает конфигурацию
LocalConfigurationService.Create():- Если online →
SyncPricelistsIfNeeded()проверяет новые прайслисты - Сохраняет конфигурацию в SQLite
- Добавляет в
pending_changesс operation="create"
- Если online →
- Конфигурация доступна локально сразу
Синхронизация с сервером
Manual sync:
POST /api/sync/push
Background sync (TODO):
- Периодический worker вызывает
syncService.PushPendingChanges() - Проверяет online статус
- Отправляет все pending changes на сервер
- Удаляет успешно синхронизированные записи
Offline режим
- Все операции работают нормально через SQLite
- Изменения копятся в
pending_changes - При восстановлении соединения автоматически синхронизируются
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