# Startup Pipeline<no value>


`BackgroundManager::start()` in `replay-control-app/src/api/background.rs` orchestrates an ordered background pipeline and independent filesystem watchers.

## Entry Point

```
BackgroundManager::start(state)
  -> tokio::spawn(run_pipeline)    // sequential phases
  -> spawn_storage_watcher()       // independent
  -> spawn_rom_watcher()           // independent
```

If storage is unavailable at boot, only the storage watcher is spawned. When storage appears (None -> Some transition via `refresh_storage()`), the full pipeline starts.

## Phase 1: Auto-Import

**Method**: `phase_auto_import()`

Checks for `<storage>/.replay-control/launchbox-metadata.xml` (or legacy `Metadata.xml`). If the file exists **and** the `game_metadata` table is empty, triggers `ImportPipeline::start_import_no_enrich()`.

The import claims its own `Activity::Import` via `try_start_activity`. The pipeline waits in a 500ms poll loop for the import to finish before proceeding.

## Phase 2: Cache Verification

**Method**: `phase_cache_verification()`

Claims `Activity::Startup { phase: Scanning }`. Works directly with the DB and filesystem (no cache layer) to avoid circular dependencies.

Loads `game_library_meta` to get cached directory mtimes and ROM counts, then detects three cases:

1. **Fresh DB**: `game_library_meta` is empty -- runs `populate_all_systems()` (full scan + enrich for every system with games)
2. **Stale mtime**: filesystem directory mtime differs from stored value -- re-scans that system via `scan_and_cache_system()` + `enrich_system_cache()`
3. **Interrupted scan**: meta says `rom_count > 0` but `game_library` has 0 rows for that system -- re-scans

After all systems are verified, runs `metadata_pool.checkpoint()` to fold WAL writes back into the main DB file.

## Phase 3: Thumbnail Index Rebuild

**Method**: `phase_auto_rebuild_thumbnail_index()`

Updates activity to `StartupPhase::RebuildingIndex`. Detects evidence of data loss:

- `data_sources` has libretro-thumbnails entries but `thumbnail_index` is empty (DB was recreated after corruption)
- No `data_sources` entries but image files exist on disk (DB was deleted)

When triggered, scans `<storage>/.replay-control/media/<system>/boxart/` directories and bulk-inserts filenames into `thumbnail_index`. This is a disk-only rebuild -- no GitHub API calls needed.

Skips entirely when both tables are empty (first-time setup).

## Storage Watcher

**Method**: `spawn_storage_watcher()`

Dual mechanism:
1. **notify watcher** (inotify on Linux): watches `replay.cfg` for immediate config change detection (skin changes, storage mode changes)
2. **Poll loop**: 10-second interval while waiting for storage, 60-second interval once connected. Calls `refresh_storage()` which detects storage appearance/disappearance

On storage transition (None -> Some), opens DB pools and starts the full background pipeline. On disappearance (Some -> None), closes pools.

## ROM Watcher

**Method**: `spawn_rom_watcher()`

Only starts for local storage kinds (SD, USB, NVMe) -- skipped for NFS because inotify doesn't detect changes from other NFS clients.

Uses `notify::recommended_watcher` in recursive mode on the `roms/` directory. Events are debounced (3-second window) to batch rapid filesystem changes (bulk copy). On change:

- Extracts the affected system folder name from the event path
- Triggers `get_roms()` + `enrich_system_cache()` for that system
- Top-level changes (new system directory) trigger a `get_systems()` refresh
