Skip to main content
The backup system provides automated daily backups and manual backup/restore functionality to protect your tattoo studio’s data.

How Backups Work

The system uses SQLite’s native backup API to create consistent database snapshots.

Backup Location

Backups are stored in:
{database_directory}/backups/backup_YYYYMMDD_HHMMSS.db
Example:
data/
├── tattoostudio.db          ← Active database
└── backups/
    ├── backup_20260304_093012.db
    ├── backup_20260303_082544.db
    └── backup_20260302_091823.db
Backup files are complete, standalone SQLite databases that can be opened independently.

Automated Daily Backups

The system automatically creates backups once per day:
1
How It Works
2
  • On application start - Check if a backup exists for today
  • Timezone check - Uses America/Hermosillo timezone
  • Create backup - If none exists for today, create one
  • Update settings - Store last backup timestamp in settings.json
  • Cleanup old backups - Keep only the most recent 20 backups
  • 3
    Viewing Last Backup
    4
    The status bar shows:
    5
    Último respaldo: 04/03/2026 09:30
    
    6
    or
    7
    Último respaldo: —
    
    8
    if no backup has been created yet.
    The automatic backup runs silently in the background and doesn’t interrupt your work.

    Creating Manual Backups

    Create backups on-demand before major operations:
    1
    Step 1: Access Backup Function
    2
    From the main menu or settings, click Crear Respaldo or Backup Now.
    3
    Step 2: Confirm Creation
    4
    The system:
    5
  • Connects to the active database (read-only)
  • Creates a timestamped backup file
  • Uses SQLite’s backup() API for consistency
  • Closes connections
  • Updates settings.json with timestamp
  • 6
    Step 3: Verify Success
    7
    A success message displays the backup location:
    8
    Respaldo creado exitosamente:
    /path/to/data/backups/backup_20260304_142305.db
    
    Manual backups count toward the 20-backup limit. Old backups are automatically deleted when the limit is exceeded.

    Listing Available Backups

    View all available backup files:

    Backup Information

    Each backup shows:
    • name - Filename (e.g., backup_20260304_142305.db)
    • display - Friendly date/time (e.g., “04/03/2026 14:23”)
    • size - File size in bytes
    • path - Full file path
    Backups are listed newest first.

    Using the Service

    from services.backups import list_backups
    
    backups = list_backups()
    for backup in backups:
        print(f"{backup['display']} - {backup['name']}")
    

    Restoring from Backup

    Critical: Restoring a backup will overwrite your current database. This action cannot be undone. Always create a backup before restoring.
    1
    Step 1: Choose Backup File
    2
    From the backup list, select the backup you want to restore.
    3
    Consider:
    4
  • Date/time of the backup
  • Why you need to restore (data loss, corruption, rollback)
  • How much recent data will be lost
  • 5
    Step 2: Confirm Restore
    6
    The system asks for confirmation:
    7
    ¿Está seguro que desea restaurar este respaldo?
    
    Backup: 04/03/2026 09:30
    
    Advertencia: Esto sobrescribirá la base de datos actual.
    Se creará una copia de seguridad de la BD actual antes de continuar.
    
    8
    Step 3: Automatic Safety Backup
    9
    Before restoring, the system:
    10
  • Creates a safety copy of the current database
  • Names it: tattoostudio.db.before_restore_20260304_143012
  • Stores it alongside the main database
  • 11
    The safety copy allows you to recover if the restore doesn’t go as planned.
    12
    Step 4: Restore Process
    13
  • Close database connections - Ensure exclusive access
  • Copy backup file - Overwrite active database
  • Verify integrity - Confirm database is readable
  • Success message - “Respaldo restaurado exitosamente”
  • 14
    Step 5: Restart Application
    15
    For complete safety:
    16
  • Close Tattoo Studio Manager
  • Restart the application
  • Verify data is correct
  • Check recent records
  • Backup Configuration

    Settings Storage

    Backup metadata in settings.json:
    {
      "last_backup_at": "2026-03-04T09:30:12-07:00",
      "studio": { ... },
      "agenda_hours": { ... }
    }
    

    Maximum Backups

    The system keeps the 20 most recent backups. Configure in services/backups.py:
    MAX_BACKUPS = 20  # Change this value if needed
    
    Adjust MAX_BACKUPS based on your disk space and backup frequency needs.

    Backup Best Practices

    Before Major Changes

    Always create a manual backup before:
    • Database migrations
    • Bulk data operations
    • Software updates
    • Schema changes

    External Storage

    Copy backups to external drives or cloud storage periodically for disaster recovery.

    Test Restores

    Periodically test restoring to a different location to verify backup integrity.

    Document Restores

    Keep a log of when and why you restore backups for audit purposes.

    Backup Retention

    Automatic Cleanup

    When backups exceed MAX_BACKUPS:
    files = sorted(backup_dir.glob("backup_*.db"), 
                   key=lambda p: p.stat().st_mtime, 
                   reverse=True)
    for old_backup in files[MAX_BACKUPS:]:
        old_backup.unlink()  # Delete oldest backups
    

    Manual Management

    To preserve specific backups:
    1. Copy them outside the backups/ directory
    2. Rename them to prevent automatic deletion
    3. Store them with descriptive names:
      important_before_migration_20260304.db
      quarter_end_20260331.db
      

    Troubleshooting

    Possible causes:
    • Database is locked by another process
    • Insufficient disk space
    • Permission denied in backup directory
    Solutions:
    • Close other database connections
    • Free up disk space
    • Check folder permissions
    Possible causes:
    • Database file corrupted
    • Application still running
    • Insufficient permissions
    Solutions:
    • Verify backup file opens in SQLite
    • Close application completely
    • Run as administrator (if needed)
    • Use the safety backup to recover
    Possible causes:
    • Application not running overnight
    • Backup failed silently
    • Timezone mismatch
    Solutions:
    • Create manual backup
    • Check disk space
    • Verify timezone settings
    • Review error logs
    Possible causes:
    • Wrong directory
    • Files deleted manually
    • Database location changed
    Solutions:
    • Check {database_directory}/backups/
    • Search for backup_*.db files
    • Verify database path in settings

    Technical Details

    Backup Method

    The system uses SQLite’s backup() API:
    src = sqlite3.connect(str(db_path))
    dst = sqlite3.connect(str(dest))
    src.backup(dst)  # Consistent snapshot
    dst.close()
    src.close()
    
    Advantages:
    • Consistent snapshot (no partial writes)
    • Handles large databases efficiently
    • Works while database is in use
    • Native SQLite feature

    Timezone Handling

    All timestamps use:
    from zoneinfo import ZoneInfo
    TZ = ZoneInfo("America/Hermosillo")
    now = datetime.now(TZ)
    
    This ensures:
    • Consistent date detection
    • Accurate “today” checks
    • Correct display times

    Safety Backup Naming

    Restore safety backups use:
    safety = db_path.with_suffix(
        db_path.suffix + f".before_restore_{timestamp}"
    )
    
    Example: tattoostudio.db.before_restore_20260304_143012
    This naming prevents conflicts and clearly identifies the safety backup’s purpose.

    Build docs developers (and LLMs) love