Local-first runtime cleanup and recovery hardening

This commit is contained in:
Mikhail Chusavitin
2026-03-07 23:18:07 +03:00
parent 4e977737ee
commit 06397a6bd1
53 changed files with 1856 additions and 2080 deletions

View File

@@ -203,18 +203,6 @@ func (LocalComponent) TableName() string {
return "local_components"
}
// LocalRemoteMigrationApplied tracks remote SQLite migrations received from server and applied locally.
type LocalRemoteMigrationApplied struct {
ID string `gorm:"primaryKey;size:128" json:"id"`
Checksum string `gorm:"size:128;not null" json:"checksum"`
AppVersion string `gorm:"size:64" json:"app_version,omitempty"`
AppliedAt time.Time `gorm:"not null" json:"applied_at"`
}
func (LocalRemoteMigrationApplied) TableName() string {
return "local_remote_migrations_applied"
}
// LocalSyncGuardState stores latest sync readiness decision for UI and preflight checks.
type LocalSyncGuardState struct {
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
@@ -248,25 +236,52 @@ func (PendingChange) TableName() string {
// LocalPartnumberBook stores a version snapshot of the PN→LOT mapping book (pull-only from PriceForge)
type LocalPartnumberBook struct {
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
ServerID int `gorm:"uniqueIndex;not null" json:"server_id"`
Version string `gorm:"not null" json:"version"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
IsActive bool `gorm:"not null;default:true" json:"is_active"`
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
ServerID int `gorm:"uniqueIndex;not null" json:"server_id"`
Version string `gorm:"not null" json:"version"`
CreatedAt time.Time `gorm:"not null" json:"created_at"`
IsActive bool `gorm:"not null;default:true" json:"is_active"`
PartnumbersJSON LocalStringList `gorm:"column:partnumbers_json;type:text" json:"partnumbers_json"`
}
func (LocalPartnumberBook) TableName() string {
return "local_partnumber_books"
}
// LocalPartnumberBookItem stores a single PN→LOT mapping within a book snapshot
type LocalPartnumberBookLot struct {
LotName string `json:"lot_name"`
Qty float64 `json:"qty"`
}
type LocalPartnumberBookLots []LocalPartnumberBookLot
func (l LocalPartnumberBookLots) Value() (driver.Value, error) {
return json.Marshal(l)
}
func (l *LocalPartnumberBookLots) Scan(value interface{}) error {
if value == nil {
*l = make(LocalPartnumberBookLots, 0)
return nil
}
var bytes []byte
switch v := value.(type) {
case []byte:
bytes = v
case string:
bytes = []byte(v)
default:
return errors.New("type assertion failed for LocalPartnumberBookLots")
}
return json.Unmarshal(bytes, l)
}
// LocalPartnumberBookItem stores the canonical PN composition pulled from PriceForge.
type LocalPartnumberBookItem struct {
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
BookID uint `gorm:"not null;index:idx_local_book_pn,priority:1" json:"book_id"`
Partnumber string `gorm:"not null;index:idx_local_book_pn,priority:2" json:"partnumber"`
LotName string `gorm:"not null" json:"lot_name"`
IsPrimaryPN bool `gorm:"not null;default:false" json:"is_primary_pn"`
Description string `json:"description,omitempty"`
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
Partnumber string `gorm:"not null" json:"partnumber"`
LotsJSON LocalPartnumberBookLots `gorm:"column:lots_json;type:text" json:"lots_json"`
Description string `json:"description,omitempty"`
}
func (LocalPartnumberBookItem) TableName() string {