Add offline RefreshPrices, fix sync bugs, implement auto-restart
- Implement RefreshPrices for local-first mode - Update prices from local_components.current_price cache - Graceful degradation when component not found - Add PriceUpdatedAt timestamp to LocalConfiguration model - Support both authenticated and no-auth price refresh - Fix sync duplicate entry bug - pushConfigurationUpdate now ensures server_id exists before update - Fetch from LocalConfiguration.ServerID or search on server if missing - Update local config with server_id after finding - Add application auto-restart after settings save - Implement restartProcess() using syscall.Exec - Setup handler signals restart via channel - Setup page polls /health endpoint and redirects when ready - Add "Back" button on setup page when settings exist - Fix setup handler password handling - Use PasswordEncrypted field consistently - Support empty password by using saved value - Improve sync status handling - Add fallback for is_offline check in SyncStatusPartial - Enhance background sync logging with prefixes - Update CLAUDE.md documentation - Mark Phase 2.5 tasks as complete - Add UI Improvements section with future tasks - Update SQLite tables documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -195,7 +195,9 @@ func setConfigDefaults(cfg *config.Config) {
|
||||
|
||||
// runSetupMode starts a minimal server that only serves the setup page
|
||||
func runSetupMode(local *localdb.LocalDB) {
|
||||
setupHandler, err := handlers.NewSetupHandler(local, "web/templates")
|
||||
restartSig := make(chan struct{}, 1)
|
||||
|
||||
setupHandler, err := handlers.NewSetupHandler(local, "web/templates", restartSig)
|
||||
if err != nil {
|
||||
slog.Error("failed to create setup handler", "error", err)
|
||||
os.Exit(1)
|
||||
@@ -242,9 +244,21 @@ func runSetupMode(local *localdb.LocalDB) {
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
slog.Info("setup mode server stopped")
|
||||
select {
|
||||
case <-quit:
|
||||
slog.Info("setup mode server stopped")
|
||||
case <-restartSig:
|
||||
slog.Info("restarting application with saved settings...")
|
||||
|
||||
// Graceful shutdown
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
srv.Shutdown(ctx)
|
||||
|
||||
// Restart process with same arguments
|
||||
restartProcess()
|
||||
}
|
||||
}
|
||||
|
||||
func setupLogger(cfg config.LoggingConfig) {
|
||||
@@ -336,8 +350,8 @@ func setupRouter(db *gorm.DB, cfg *config.Config, local *localdb.LocalDB, dbUser
|
||||
return nil, nil, fmt.Errorf("creating sync handler: %w", err)
|
||||
}
|
||||
|
||||
// Setup handler (for reconfiguration)
|
||||
setupHandler, err := handlers.NewSetupHandler(local, "web/templates")
|
||||
// Setup handler (for reconfiguration) - no restart signal in normal mode
|
||||
setupHandler, err := handlers.NewSetupHandler(local, "web/templates", nil)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("creating setup handler: %w", err)
|
||||
}
|
||||
@@ -620,6 +634,26 @@ func setupRouter(db *gorm.DB, cfg *config.Config, local *localdb.LocalDB, dbUser
|
||||
return router, syncService, nil
|
||||
}
|
||||
|
||||
// restartProcess restarts the current process with the same arguments
|
||||
func restartProcess() {
|
||||
executable, err := os.Executable()
|
||||
if err != nil {
|
||||
slog.Error("failed to get executable path", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
args := os.Args
|
||||
env := os.Environ()
|
||||
|
||||
slog.Info("executing restart", "executable", executable, "args", args)
|
||||
|
||||
err = syscall.Exec(executable, args, env)
|
||||
if err != nil {
|
||||
slog.Error("failed to restart process", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func requestLogger() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
|
||||
Reference in New Issue
Block a user