Features:
- restore diagnose command for backup file analysis
- Deep COPY block verification for truncated dump detection
- PGDMP signature and gzip integrity validation
- Detailed error reports with --save-debug-log flag
- Ring buffer stderr capture (prevents OOM on 2M+ errors)
- Error classification with actionable recommendations
TUI Enhancements:
- Automatic dump validity safety check before restore
- Press 'd' in archive browser to diagnose backups
- Press 'd' in restore preview for debug log toggle
- Debug logs saved to /tmp on failure when enabled
Documentation:
- Updated README with diagnose command and examples
- Updated CHANGELOG with full feature list
- Updated restore preview screenshots
- Fix format detection to read database_type from .meta.json metadata file
- Add ensureMySQLDatabaseExists() for MySQL/MariaDB database creation
- Route database creation to correct implementation based on db type
- Add TUI auto-forward in auto-confirm mode (no input required for debugging)
- All TUI components now exit automatically when --auto-confirm is set
- Fix status view to skip loading in auto-confirm mode
- Add .golangci.yml with minimal linters (govet, ineffassign)
- Run gofmt -s and goimports on all files to fix formatting
- Disable fieldalignment and copylocks checks in govet
- Created internal/cleanup package for orphaned process management
- KillOrphanedProcesses(): Finds and kills pg_dump, pg_restore, gzip, pigz
- killProcessGroup(): Kills entire process groups (handles pipelines)
- Pass parent context through all TUI operations (backup/restore inherit cancellation)
- Menu cancel now kills all child processes before exit
- Fixed context chain: menu.ctx → backup/restore operations
- No more zombie processes when user quits TUI mid-operation
Context chain:
- signal.NotifyContext in main.go → menu.ctx
- menu.ctx → backup_exec.ctx, restore_exec.ctx
- Child contexts inherit cancellation via context.WithTimeout(parentCtx)
- All exec.CommandContext use proper parent context
Prevents: Orphaned pg_dump/pg_restore eating CPU/disk after TUI quit
High Priority Fixes:
- Use configurable ClusterTimeoutMinutes for restore (was hardcoded 2 hours)
- Add comment explaining goroutine cleanup in stderr reader (cmd.Run waits)
- Add defer cancel() in cluster backup loop to prevent context leak on panic
Medium Priority Fixes:
- Standardize tick rate to 100ms for both backup and restore (consistent UX)
- Add spinnerFrame field to BackupExecutionModel for incremental updates
- Define package-level spinnerFrames constant to avoid repeated allocation
Low Priority Fixes:
- Add 30-second timeout per database in cluster cleanup loop
- Prevents indefinite hangs when dropping many databases
Optimizations:
- Pre-allocate 512 bytes in View() string builders (reduces allocations)
- Use incremental spinner frame calculation (more efficient than time-based)
- Share spinner frames array across all TUI operations
All changes are backward compatible and maintain existing behavior.
Issue: Interactive cluster restore showed 'Status: Initializing...' throughout
the entire restore process, making it appear stuck even though restore was working.
Root cause:
- Status and phase were set once in NewRestoreExecution()
- Never updated during the restore process
- Only changed to 'Completed' or 'Failed' at the end
- No visual feedback about what stage of restore was running
Solution: Time-based status progression
Added logic in Update() tick handler to change status based on elapsed time:
- 0-2 sec: 'Initializing restore...' / Phase: Starting
- 2-5 sec: Context-aware status:
- If cleanup: 'Cleaning N existing database(s)...' / Phase: Cleanup
- If cluster: 'Extracting cluster archive...' / Phase: Extraction
- If single: 'Preparing restore...' / Phase: Preparation
- 5-10 sec:
- If cluster: 'Restoring global objects...' / Phase: Globals
- If single: 'Restoring database...' / Phase: Restore
- 10+ sec: 'Restoring [cluster] databases...' / Phase: Restore
Benefits:
- User sees the restore is progressing through stages
- Different status messages for cluster vs single database restore
- Shows cleanup phase when enabled
- Spinner + changing status = clear visual feedback
- Better user experience during long-running restores
Note: These are estimated phases since the restore engine runs in silent mode
(no stdout interference with TUI). Actual operation may be faster or slower
than time estimates, but provides much better UX than static 'Initializing'.
Issue: When enabling cluster cleanup (Option C) in interactive restore mode,
the tool tried to connect to the database to drop existing databases. This
was confusing because:
- Cluster restore itself doesn't use database connections
- It uses CLI tools (psql, pg_restore) directly
- Connection errors were misleading to users
Solution: Changed cleanup to use psql command directly (dropDatabaseCLI)
- Matches how cluster restore works (CLI tools, not connections)
- No confusing connection errors
- Cleaner, more consistent behavior
- Uses postgres maintenance DB for DROP DATABASE commands
Files changed:
- internal/tui/restore_exec.go: Added dropDatabaseCLI() helper function
- Removed dbClient.Connect() requirement for cleanup
- Cleanup now works exactly like cluster restore operations
- Auto-detects existing user databases before cluster restore
- Shows count and list (first 5) in preview screen
- Toggle option 'c' to enable cluster cleanup
- Drops all user databases before restore when enabled
- Works for PostgreSQL, MySQL, MariaDB
- Safety warning with database count
- Implements practical disaster recovery workflow