schema-sync 1.0.0

Production-grade schema synchronization for multi-tenant databases
Documentation
**Developer:** s4gor  
**Github:** https://github.com/s4gor

---

# Schema Sync

Production-grade schema synchronization for multi-tenant databases.

## Overview

Schema Sync is designed to manage schema synchronization across multiple tenant schemas in a single database. It provides a robust, extensible foundation for detecting, analyzing, and managing schema differences safely.

## Architecture

### Design Philosophy

This crate is designed **extension-first**. All core abstractions are trait-based, allowing:

- **Multi-database support**: PostgreSQL, MySQL, SQLite, and more
- **Pluggable migration engines**: SQL files, Rust code, external tools
- **Multiple operation modes**: Sync, dry-run, validation, audit
- **Flexible snapshot storage**: Filesystem, database, version control

### Core Components

```
┌─────────────────────────────────────────────────────────────┐
│                        CLI Layer                             │
│  (dry-run, diff, validation, audit modes)                   │
└───────────────────────┬─────────────────────────────────────┘
┌───────────────────────▼─────────────────────────────────────┐
│                    Engine Layer                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ Planner  │→ │ Executor │→ │  Diff    │→ │ Snapshot │   │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘   │
└───────────────────────┬─────────────────────────────────────┘
┌───────────────────────▼─────────────────────────────────────┐
│                  Adapter Layer                               │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Database   │  │  Migration   │  │   Schema     │      │
│  │   Adapter    │  │   Runner     │  │  Inspector   │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└───────────────────────┬─────────────────────────────────────┘
┌───────────────────────▼─────────────────────────────────────┐
│              Database-Specific Implementations               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                 │
│  │PostgreSQL│  │  MySQL   │  │  SQLite  │                 │
│  └──────────┘  └──────────┘  └──────────┘                 │
└─────────────────────────────────────────────────────────────┘
```

### Key Abstractions

#### 1. DatabaseAdapter

The main entry point for database operations. Provides:
- Connection management
- Factory methods for inspectors and runners
- Database-specific configuration

**Why this abstraction exists**: Allows different database types to be plugged in without changing core logic.

#### 2. SchemaInspector

Read-only schema introspection. Produces normalized `SchemaSnapshot` objects.

**Why this abstraction exists**: 
- Enables audit mode without write permissions
- Allows dry-run mode to calculate diffs without locks
- Supports testing with mock inspectors

#### 3. MigrationRunner

Executes schema changes. Supports different migration strategies.

**Why this abstraction exists**:
- Pluggable migration engines (SQL files, Rust code, external tools)
- Different strategies per database type
- Testing with mock runners

#### 4. Planner

Creates executable migration plans from schema diffs.

**Why this abstraction exists**:
- Dry-run mode can show what would happen
- Validation of plans before execution
- Different planning strategies (safe ordering, dependency resolution)

#### 5. Executor

Orchestrates the execution of migration plans.

**Why this abstraction exists**:
- Different execution strategies (transactional, non-transactional)
- Progress reporting
- Retry logic

#### 6. DiffCalculator

Calculates differences between schema snapshots.

**Why this abstraction exists**:
- Different diff algorithms
- Three-way merge support
- Conflict detection

#### 7. SnapshotStore

Stores and retrieves schema snapshots.

**Why this abstraction exists**:
- Multiple storage backends (filesystem, database, version control)
- Version history
- Deterministic versioning

## Future Extensions

### 1. Dry-Run / Diff Mode

Preview schema changes without applying them. Output formats:
- Human-readable text
- Machine-readable JSON

**Implementation**: Use `Engine::sync_tenant()` with `execute=false`.

### 2. CI / Validation Mode

Run in CI to ensure all tenants match expected schema. Exit non-zero if mismatch detected.

**Implementation**: Use `Engine::sync_tenant()` in dry-run mode for all tenants, check `already_in_sync` flag.

### 3. Multi-Database Support

PostgreSQL (primary), MySQL, SQLite support through adapter implementations.

**Implementation**: Implement `DatabaseAdapter`, `SchemaInspector`, and `MigrationRunner` traits for each database type.

### 4. Read-Only Audit Mode

Detect drift without locks. Safe for production observability.

**Implementation**: Use `SchemaInspector` directly, no `MigrationRunner` needed.

### 5. Pluggable Migration Engine

Support SQL file migrations, Rust-based migrations, external tools (diesel, sqlx).

**Implementation**: Implement `MigrationRunner` trait with different strategies.

### 6. Schema Snapshot System

Store normalized schema snapshots. Allow diffing schema version A vs B.

**Implementation**: Use `SnapshotStore` trait implementations.

### 7. Tenant Isolation Guarantees

No cross-tenant leakage. Strict tenant scoping. Explicit locking strategy per tenant.

**Implementation**: All operations require `TenantContext`. `MigrationRunner::acquire_lock()` ensures isolation.

## Module Structure

```
src/
├── lib.rs           # Main library entry point
├── adapters.rs      # Database adapter traits
├── diff.rs          # Schema diff calculation
├── engine.rs        # Main engine orchestration
├── errors.rs        # Error types
├── planner.rs       # Migration planning
├── executor.rs      # Migration execution
├── snapshot.rs      # Schema snapshots
└── cli.rs           # CLI types and context
```

## Usage

### Basic Sync

```rust
use schema_sync::prelude::*;

let adapter = PostgresAdapter::new("postgresql://...").await?;
let engine = Engine::from_adapter(/* ... */);

let tenant = TenantContext::new("tenant_123");
let result = engine.sync_tenant(&tenant, Some(&target_snapshot), true).await?;
```

### Dry-Run Mode

```rust
let result = engine.sync_tenant(&tenant, Some(&target_snapshot), false).await?;
if !result.diff.is_empty() {
    println!("Would apply {} changes", result.diff.change_count());
}
```

### CI Validation

```rust
let tenants = engine.list_tenants().await?;
for tenant in tenants {
    let result = engine.sync_tenant(&tenant, None, false).await?;
    if !result.already_in_sync {
        eprintln!("Schema mismatch for {}", tenant.id());
        std::process::exit(1);
    }
}
```

## Design Principles

1. **Trait-Based Extensibility**: All database operations go through traits
2. **Separation of Concerns**: Clear boundaries between inspection, planning, and execution
3. **Tenant Isolation**: Every operation is scoped to a tenant context
4. **Mode-Agnostic Core**: Engine doesn't know about CLI modes
5. **Async-First**: All I/O operations are async
6. **Deterministic Behavior**: Same inputs always produce same outputs
7. **Minimal Macros**: Prefer traits and generics over macros

## Status

This is the **foundation layer** of schema-sync. It provides:

✅ Core trait definitions  
✅ Data structures for schemas, diffs, and plans  
✅ Architecture for extensibility  
✅ Example usage patterns  

🚧 **Not yet implemented**:
- Concrete database adapters (PostgreSQL, MySQL, SQLite)
- Concrete planner, executor, diff calculator implementations
- CLI implementation
- Snapshot store implementations

## Contributing

When implementing database adapters or other components:

1. Implement the appropriate traits
2. Keep database-specific logic in adapter implementations
3. Ensure tenant isolation in all operations
4. Write tests with mock implementations
5. Document any database-specific behavior

## License

MIT OR Apache-2.0