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

179 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`:
```go
syncService := sync.NewService(pricelistRepo, configRepo, local)
```
### 4. LocalConfigurationService (`internal/services/local_configuration.go`)
Новый сервис для работы с конфигурациями в local-first режиме:
- Все операции CRUD работают через SQLite
- Автоматически добавляет изменения в pending_changes
- При создании конфигурации (если online) проверяет новые прайслисты
```go
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
```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:
```go
// Было:
configHandler := handlers.NewConfigurationHandler(configService, exportService)
// Стало:
configHandler := handlers.NewConfigurationHandler(localConfigService, exportService)
```
### Шаг 3: Добавить endpoints для sync
В роутере добавить:
```go
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:**
```bash
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`:
```go
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
```bash
# 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
```