# `migration.rs` – Storage Schema Migrations

## Purpose
`migration.rs` handles **versioned migrations** of the on‑disk data format used by Todozi.
When the storage schema evolves (new fields, renamed keys, moved files), migration functions transform old data into the new layout without data loss.

## Core Functions

| Function | Description |
|----------|-------------|
| `run_migrations(storage_dir: &Path) -> Result<()>` | Detects the current schema version, determines which migration steps are pending, and applies them in order. |
| `migration_v1_to_v2()` | Example migration that renames a field, updates JSON structures, or moves a file to a new location. |
| `migration_v2_to_v3()` | Subsequent migration step that may introduce new collections or change HLX namespaces. |
| `detect_version(storage_dir: &Path) -> Result<u32>` | Reads a version marker (e.g., `tdz.hlx` key `schema_version`) to decide which migrations are needed. |

## Typical Migration Flow (Mermaid)

```mermaid
flowchart TD
    A[Storage::new()] --> B[detect_version]
    B --> C{Version < CURRENT?}
    C -- Yes --> D[run_migrations]
    D --> E[Apply migration steps sequentially]
    E --> F[Update version marker]
    C -- No --> G[Proceed with normal operation]
```

1. **Initialisation** – `Storage::new()` calls `run_migrations` before any data is read.
2. **Version detection** – The stored schema version is compared with the binary’s `CURRENT_SCHEMA_VERSION`.
3. **Apply migrations** – Each migration function receives the storage directory path and performs atomic file operations (write‑to‑temp + rename) to guarantee consistency.
4. **Update marker** – After all pending migrations succeed, the version key in `tdz.hlx` is bumped to the latest version.

## Safety Guarantees

* **Atomic updates** – All file writes are performed on a temporary file followed by a rename, ensuring no partially‑written state.
* **Idempotent migrations** – Each migration checks that it hasn’t already been applied (e.g., by looking for the presence of a new field) before making changes.
* **Rollback on failure** – If any step returns an error, the migration process aborts and the storage remains at its previous version, allowing the user to retry after fixing the issue.

## Integration Points

| Module | Interaction |
|--------|-------------|
| `src/storage.rs` | Calls `run_migrations` during initialisation. |
| `src/lib.rs` | Exposes a `migrate()` convenience wrapper for CLI use (`todozi migrate`). |
| `src/cli.rs` | Provides the `migrate` sub‑command (`todozi migrate --dry-run --force`). |
| `src/tests.rs` | Contains integration tests that create a mock old‑version layout, invoke `run_migrations`, and assert the presence of new fields. |

## When to Run Migrations

- After **upgrading Todozi** to a new version that changes the on‑disk schema.
- When **importing data** from an older Todozi export.
- As part of **CI pipelines** that validate that a fresh install can successfully migrate legacy data.

## Example CLI Usage

```sh
# Show what migrations would run (dry‑run)
todozi migrate --dry-run

# Force apply all pending migrations
todozi migrate --force

# Run migrations with verbose output
todozi migrate --verbose
```

The command prints each step, e.g.:

```
🔄 Detected schema version 1 → 3
✅ Applied migration v1 → v2: renamed `tasks.json` to `tasks_v1.json`
✅ Applied migration v2 → v3: added `tags` field to all tasks
🔢 Updated schema version to 3
```

## Best Practices for Developers

1. **Add a new migration function** (`migration_vX_to_vY`) whenever the data model changes.
2. **Increment `CURRENT_SCHEMA_VERSION`** in `src/migration.rs` to reflect the latest version.
3. **Write tests** that simulate an old layout and verify the migration results.
4. **Avoid destructive changes** (e.g., deleting user data) unless absolutely necessary; instead, migrate to a new structure and keep the old data as a backup.

---

*Generated by GPT‑OSS – documentation for the `migration.rs` module.*
