# Module Fixes Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** 修复 migration、tracing、cli、permission 四个模块的关键问题，实现自动回滚、完整追踪、schema差异检测和权限整合。

**Architecture:** 按依赖顺序实施：Migration（基础）→ Tracing（可观测性）→ CLI（工具层）→ Permission（安全层）。每个模块独立实施，通过 trait 抽象保持解耦。

**Tech Stack:** Rust 1.85+, Sea-ORM 2.0.0-rc.27, sqlparser 0.47, OpenTelemetry, tokio, lru, dashmap

---

## Phase 1: Migration 模块 - 自动生成回滚 SQL

### Task 1.1: 创建元数据跟踪结构

**Files:**
- Create: `src/migration/metadata.rs`
- Modify: `src/migration/mod.rs`

**Step 1: Write the failing test**

```rust
// tests/migration/unit/metadata_test.rs
#[cfg(test)]
mod tests {
    use super::super::metadata::{MigrationMetadata, TableSnapshot};

    #[test]
    fn test_create_metadata() {
        let metadata = MigrationMetadata::new(1, "test_migration".to_string(), "CREATE TABLE test (id INT);");
        assert_eq!(metadata.version, 1);
        assert_eq!(metadata.name, "test_migration");
        assert!(metadata.table_snapshots.is_empty());
    }

    #[test]
    fn test_add_table_snapshot() {
        let mut metadata = MigrationMetadata::new(1, "test".to_string(), "CREATE TABLE test (id INT);");
        let snapshot = TableSnapshot::new("test".to_string());
        metadata.add_table_snapshot(snapshot);
        assert_eq!(metadata.table_snapshots.len(), 1);
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test migration_unit -- metadata_test --no-fail-fast`
Expected: FAIL with "cannot find MigrationMetadata in this scope"

**Step 3: Write minimal implementation**

```rust
// src/migration/metadata.rs
use std::collections::HashMap;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableSnapshot {
    pub table_name: String,
    pub columns: Vec<ColumnDefinition>,
    pub constraints: Vec<ConstraintDefinition>,
}

impl TableSnapshot {
    pub fn new(table_name: String) -> Self {
        Self {
            table_name,
            columns: Vec::new(),
            constraints: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnDefinition {
    pub name: String,
    pub data_type: String,
    pub nullable: bool,
    pub default_value: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstraintDefinition {
    pub name: Option<String>,
    pub constraint_type: String,
    pub columns: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MigrationMetadata {
    pub version: u32,
    pub name: String,
    pub up_sql: String,
    pub down_sql: Option<String>,
    pub table_snapshots: HashMap<String, TableSnapshot>,
}

impl MigrationMetadata {
    pub fn new(version: u32, name: String, up_sql: String) -> Self {
        Self {
            version,
            name,
            up_sql,
            down_sql: None,
            table_snapshots: HashMap::new(),
        }
    }

    pub fn add_table_snapshot(&mut self, snapshot: TableSnapshot) {
        self.table_snapshots.insert(snapshot.table_name.clone(), snapshot);
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test migration_unit -- metadata_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/migration/metadata.rs tests/migration/unit/metadata_test.rs src/migration/mod.rs
git commit -m "feat(migration): add metadata tracking structure"
```

---

### Task 1.2: 实现 SQL 逆向生成器基础

**Files:**
- Create: `src/migration/sql_reverser.rs`
- Modify: `src/migration/mod.rs`

**Step 1: Write the failing test**

```rust
// tests/migration/unit/sql_reverser_test.rs
#[cfg(test)]
mod tests {
    use super::super::sql_reverser::SqlReverser;

    #[test]
    fn test_reverse_create_table() {
        let up_sql = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255));";
        let reverser = SqlReverser::new();
        let down_sql = reverser.reverse(up_sql).unwrap();
        assert!(down_sql.contains("DROP TABLE"));
        assert!(down_sql.contains("users"));
    }

    #[test]
    fn test_reverse_add_column() {
        let up_sql = "ALTER TABLE users ADD COLUMN email VARCHAR(255);";
        let reverser = SqlReverser::new();
        let down_sql = reverser.reverse(up_sql).unwrap();
        assert!(down_sql.contains("DROP COLUMN"));
        assert!(down_sql.contains("email"));
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test migration_unit -- sql_reverser_test --no-fail-fast`
Expected: FAIL with "cannot find SqlReverser in this scope"

**Step 3: Write minimal implementation**

```rust
// src/migration/sql_reverser.rs
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
use sqlparser::ast::{Statement, SqlOption};

pub struct SqlReverser {
    dialect: GenericDialect,
}

impl SqlReverser {
    pub fn new() -> Self {
        Self {
            dialect: GenericDialect {},
        }
    }

    pub fn reverse(&self, up_sql: &str) -> Result<String, String> {
        let statements = Parser::parse_sql(&self.dialect, up_sql)
            .map_err(|e| format!("Failed to parse SQL: {}", e))?;

        let mut down_statements = Vec::new();

        for stmt in statements {
            let down_sql = self.reverse_statement(&stmt)?;
            down_statements.push(down_sql);
        }

        Ok(down_statements.join(";\n"))
    }

    fn reverse_statement(&self, stmt: &Statement) -> Result<String, String> {
        match stmt {
            Statement::CreateTable { name, .. } => {
                let table_name = name.to_string();
                Ok(format!("DROP TABLE IF EXISTS {}", table_name))
            }
            Statement::AlterTable { name, operations, .. } => {
                let table_name = name.to_string();
                self.reverse_alter_table(&table_name, operations)
            }
            _ => Err(format!("Unsupported statement type: {:?}", stmt)),
        }
    }

    fn reverse_alter_table(&self, table_name: &str, operations: &[sqlparser::ast::AlterTableOperation]) -> Result<String, String> {
        let mut down_operations = Vec::new();

        for op in operations {
            match op {
                sqlparser::ast::AlterTableOperation::AddColumn { column_def, .. } => {
                    let column_name = &column_def.name.value;
                    down_operations.push(format!("ALTER TABLE {} DROP COLUMN {}", table_name, column_name));
                }
                sqlparser::ast::AlterTableOperation::RenameColumn { old_column_name, new_column_name } => {
                    down_operations.push(format!(
                        "ALTER TABLE {} RENAME COLUMN {} TO {}",
                        table_name, new_column_name, old_column_name
                    ));
                }
                _ => return Err(format!("Unsupported alter operation: {:?}", op)),
            }
        }

        Ok(down_operations.join(";\n"))
    }
}

impl Default for SqlReverser {
    fn default() -> Self {
        Self::new()
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test migration_unit -- sql_reverser_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/migration/sql_reverser.rs tests/migration/unit/sql_reverser_test.rs src/migration/mod.rs
git commit -m "feat(migration): add SQL reverser for basic operations"
```

---

### Task 1.3: 实现列变更操作

**Files:**
- Create: `src/migration/column_changes.rs`
- Modify: `src/migration/mod.rs`

**Step 1: Write the failing test**

```rust
// tests/migration/unit/column_changes_test.rs
#[cfg(test)]
mod tests {
    use super::super::column_changes::{ColumnChange, ColumnChangeType};

    #[test]
    fn test_rename_column() {
        let change = ColumnChange::new(
            ColumnChangeType::RenameColumn,
            "users".to_string(),
            "old_name".to_string(),
            "new_name".to_string(),
        );
        assert_eq!(change.table_name, "users");
        assert_eq!(change.column_name, "old_name");
        assert_eq!(change.new_column_name, Some("new_name".to_string()));
    }

    #[test]
    fn test_modify_column() {
        let change = ColumnChange::new(
            ColumnChangeType::ModifyColumn,
            "users".to_string(),
            "age".to_string(),
            "INT".to_string(),
        );
        assert_eq!(change.change_type, ColumnChangeType::ModifyColumn);
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test migration_unit -- column_changes_test --no-fail-fast`
Expected: FAIL with "cannot find ColumnChange in this scope"

**Step 3: Write minimal implementation**

```rust
// src/migration/column_changes.rs
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ColumnChangeType {
    RenameColumn,
    ModifyColumn,
    NullabilityChanged,
    DefaultChanged,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnChange {
    pub change_type: ColumnChangeType,
    pub table_name: String,
    pub column_name: String,
    pub new_column_name: Option<String>,
    pub new_type: Option<String>,
    pub nullable: Option<bool>,
    pub default_value: Option<String>,
}

impl ColumnChange {
    pub fn new(
        change_type: ColumnChangeType,
        table_name: String,
        column_name: String,
        value: String,
    ) -> Self {
        Self {
            change_type,
            table_name,
            column_name,
            new_column_name: match change_type {
                ColumnChangeType::RenameColumn => Some(value.clone()),
                _ => None,
            },
            new_type: match change_type {
                ColumnChangeType::ModifyColumn => Some(value.clone()),
                _ => None,
            },
            nullable: None,
            default_value: None,
        }
    }

    pub fn with_nullable(mut self, nullable: bool) -> Self {
        self.nullable = Some(nullable);
        self
    }

    pub fn with_default(mut self, default: String) -> Self {
        self.default_value = Some(default);
        self
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test migration_unit -- column_changes_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/migration/column_changes.rs tests/migration/unit/column_changes_test.rs src/migration/mod.rs
git commit -m "feat(migration): add column change operations"
```

---

### Task 1.4: 集成回滚功能到 executor

**Files:**
- Modify: `src/migration/executor.rs`

**Step 1: Write the failing test**

```rust
// tests/migration/integration/rollback_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::{DbPool, migration::executor::MigrationExecutor};

    #[tokio::test]
    async fn test_rollback_with_generated_sql() {
        let pool = DbPool::new("sqlite::memory:").await.unwrap();
        let mut executor = MigrationExecutor::new(pool.connection()).await.unwrap();

        // 创建测试表
        executor.execute_raw("CREATE TABLE test_rollback (id INT PRIMARY KEY, name VARCHAR(255));").await.unwrap();

        // 执行迁移
        executor.execute_raw("INSERT INTO test_rollback VALUES (1, 'test');").await.unwrap();

        // 验证数据存在
        let result = executor.execute_raw("SELECT COUNT(*) FROM test_rollback;").await.unwrap();
        assert!(result.rows_affected() > 0);

        // 回滚（应该执行实际的 DROP TABLE）
        let reverser = dbnexus::migration::sql_reverser::SqlReverser::new();
        let down_sql = reverser.reverse("CREATE TABLE test_rollback (id INT PRIMARY KEY, name VARCHAR(255));").unwrap();
        executor.execute_raw(&down_sql).await.unwrap();

        // 验证表已删除
        let result = executor.execute_raw("SELECT COUNT(*) FROM test_rollback;").await;
        assert!(result.is_err());
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test migration_integration -- rollback_test --no-fail-fast`
Expected: FAIL with current rollback not executing SQL

**Step 3: Modify executor to use generated SQL**

```rust
// src/migration/executor.rs
use crate::migration::sql_reverser::SqlReverser;

pub async fn rollback_migration(&mut self, version: u32) -> Result<(), crate::error::DbError> {
    // 查找迁移
    let migration = self.history.applied_migrations
        .iter()
        .find(|m| m.version == version)
        .ok_or_else(|| crate::error::DbError::MigrationNotFound(version))?;

    // 生成回滚 SQL
    let reverser = SqlReverser::new();
    let down_sql = match &migration.down_sql {
        Some(sql) => sql.clone(),
        None => reverser.reverse(&migration.up_sql)
            .map_err(|e| crate::error::DbError::InvalidMigration(e))?,
    };

    // 执行回滚 SQL
    let backend = self.connection.get_database_backend();
    let statement = sea_orm::Statement::from_string(backend, down_sql);

    let txn: sea_orm::DatabaseTransaction = self.connection.begin().await?;
    txn.execute(statement).await
        .map_err(|e| crate::error::DbError::MigrationRollbackFailed(e))?;
    txn.commit().await?;

    // 从历史记录中移除
    self.history.applied_migrations.retain(|m| m.version != version);

    Ok(())
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test migration_integration -- rollback_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/migration/executor.rs tests/migration/integration/rollback_test.rs
git commit -m "feat(migration): integrate SQL reverser into rollback"
```

---

## Phase 2: Tracing 模块 - 完整分布式追踪功能

### Task 2.1: 创建 TracingContext 结构

**Files:**
- Create: `src/tracing/context.rs`
- Modify: `src/tracing.rs`

**Step 1: Write the failing test**

```rust
// tests/tracing/unit/context_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::tracing::context::TracingContext;

    #[test]
    fn test_create_span() {
        let context = TracingContext::new("test_span");
        assert_eq!(context.span_name(), "test_span");
    }

    #[test]
    fn test_drop_ends_span() {
        {
            let _context = TracingContext::new("test_span");
            // span 在这里结束
        }
        // 验证 span 已结束（通过检查内部状态）
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test tracing_unit -- context_test --no-fail-fast`
Expected: FAIL with "cannot find TracingContext in this scope"

**Step 3: Write minimal implementation**

```rust
// src/tracing/context.rs
use std::sync::Arc;
use opentelemetry::trace::{Span, Tracer, TracerProvider};
use opentelemetry::global;

pub struct TracingContext {
    tracer: Arc<dyn Tracer + Send + Sync>,
    span: Arc<Span>,
}

impl TracingContext {
    pub fn new(name: &str) -> Self {
        let tracer = global::tracer_provider().tracer("dbnexus");
        let span = tracer.start(name);

        Self {
            tracer: Arc::new(tracer),
            span: Arc::new(span),
        }
    }

    pub fn span_name(&self) -> &str {
        self.span.name()
    }

    pub fn start_child(&self, name: &str) -> Self {
        let span = self.tracer.start_with_context(name, &self.span);
        Self {
            tracer: self.tracer.clone(),
            span: Arc::new(span),
        }
    }
}

impl Drop for TracingContext {
    fn drop(&mut self) {
        self.span.end();
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test tracing_unit -- context_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/tracing/context.rs tests/tracing/unit/context_test.rs src/tracing.rs
git commit -m "feat(tracing): add TracingContext with span management"
```

---

### Task 2.2: 实现属性记录功能

**Files:**
- Create: `src/tracing/attributes.rs`
- Modify: `src/tracing/context.rs`

**Step 1: Write the failing test**

```rust
// tests/tracing/unit/attributes_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::tracing::{context::TracingContext, attributes::AttributeValue};

    #[test]
    fn test_set_string_attribute() {
        let context = TracingContext::new("test_span");
        context.set_attribute("key", AttributeValue::String("value".to_string()));
        // 验证属性已设置
    }

    #[test]
    fn test_set_numeric_attribute() {
        let context = TracingContext::new("test_span");
        context.set_attribute("count", AttributeValue::I64(42));
        // 验证属性已设置
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test tracing_unit -- attributes_test --no-fail-fast`
Expected: FAIL with "no method named set_attribute found"

**Step 3: Write minimal implementation**

```rust
// src/tracing/attributes.rs
use opentelemetry::KeyValue;

#[derive(Debug, Clone)]
pub enum AttributeValue {
    String(String),
    I64(i64),
    F64(f64),
    Bool(bool),
    Array(Vec<AttributeValue>),
}

impl AttributeValue {
    pub fn to_key_value(&self, key: &str) -> KeyValue {
        match self {
            AttributeValue::String(v) => KeyValue::new(key, v.clone()),
            AttributeValue::I64(v) => KeyValue::new(key, *v),
            AttributeValue::F64(v) => KeyValue::new(key, *v),
            AttributeValue::Bool(v) => KeyValue::new(key, *v),
            AttributeValue::Array(_) => KeyValue::new(key, "array".to_string()),
        }
    }
}
```

```rust
// src/tracing/context.rs (添加方法)
use crate::tracing::attributes::AttributeValue;

impl TracingContext {
    pub fn set_attribute(&self, key: &str, value: AttributeValue) {
        self.span.set_attribute(value.to_key_value(key));
    }

    pub fn set_attributes(&self, attributes: Vec<(String, AttributeValue)>) {
        for (key, value) in attributes {
            self.set_attribute(&key, value);
        }
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test tracing_unit -- attributes_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/tracing/attributes.rs src/tracing/context.rs tests/tracing/unit/attributes_test.rs src/tracing.rs
git commit -m "feat(tracing): add attribute recording"
```

---

### Task 2.3: 实现错误追踪功能

**Files:**
- Create: `src/tracing/error.rs`
- Modify: `src/tracing/context.rs`

**Step 1: Write the failing test**

```rust
// tests/tracing/unit/error_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::tracing::context::TracingContext;
    use std::io;

    #[test]
    fn test_record_error() {
        let context = TracingContext::new("test_span");
        let error = io::Error::new(io::ErrorKind::NotFound, "test error");
        context.record_error(&error);
        // 验证错误已记录
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test tracing_unit -- error_test --no-fail-fast`
Expected: FAIL with "no method named record_error found"

**Step 3: Write minimal implementation**

```rust
// src/tracing/context.rs (添加方法)
use opentelemetry::trace::Status;

impl TracingContext {
    pub fn record_error(&self, error: &dyn std::error::Error) {
        let error_message = error.to_string();
        self.span.record_error(&error_message);
        self.span.set_status(Status::Error {
            description: error_message.into(),
            code: None,
        });
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test tracing_unit -- error_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/tracing/context.rs tests/tracing/unit/error_test.rs
git commit -m "feat(tracing): add error tracking"
```

---

### Task 2.4: 实现采样率配置

**Files:**
- Create: `src/tracing/sampler.rs`
- Modify: `src/tracing.rs`

**Step 1: Write the failing test**

```rust
// tests/tracing/unit/sampler_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::tracing::sampler::create_trace_provider_with_sampling;

    #[test]
    fn test_create_with_sampling() {
        let provider = create_trace_provider_with_sampling(0.5);
        assert!(provider.is_some());
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test tracing_unit -- sampler_test --no-fail-fast`
Expected: FAIL with "cannot find create_trace_provider_with_sampling"

**Step 3: Write minimal implementation**

```rust
// src/tracing/sampler.rs
use opentelemetry::trace::{TraceError, TracerProvider};
use opentelemetry_sdk::trace::{Sampler, TracerProvider as SdkTracerProvider};
use opentelemetry::trace::TraceId;

pub fn create_trace_provider_with_sampling(sampling_rate: f64) -> Result<SdkTracerProvider, TraceError> {
    let sampler = Sampler::TraceIdRatioBased(sampling_rate.clamp(0.0, 1.0));
    Ok(SdkTracerProvider::builder()
        .with_sampler(sampler)
        .build())
}
```

```rust
// src/tracing.rs (更新 init 函数)
use crate::tracing::sampler::create_trace_provider_with_sampling;

pub async fn init_with_sampling(
    exporter: &str,
    endpoint: &str,
    sampling_rate: f64,
) -> Result<TracingGuard, String> {
    let provider = match exporter.to_lowercase().as_str() {
        "otlp" => init_otlp(endpoint).await?,
        "stdout" => init_stdout()?,
        _ => init_stdout()?,
    };

    // 应用采样率
    let sampled_provider = create_trace_provider_with_sampling(sampling_rate)
        .map_err(|e| format!("Failed to create sampler: {}", e))?;

    global::set_tracer_provider(sampled_provider);
    global::set_text_map_propagator(opentelemetry::sdk::propagation::TraceContextPropagator::new());

    Ok(TracingGuard { _provider: provider })
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test tracing_unit -- sampler_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/tracing/sampler.rs src/tracing.rs tests/tracing/unit/sampler_test.rs
git commit -m "feat(tracing): add sampling rate configuration"
```

---

## Phase 3: CLI 模块 - Schema 差异检测功能

### Task 3.1: 创建 Schema 解析器

**Files:**
- Create: `src/cli/schema.rs`
- Modify: `src/cli/src/main.rs`

**Step 1: Write the failing test**

```rust
// tests/cli/unit/schema_test.rs
#[cfg(test)]
mod tests {
    use dbnexus_cli::schema::{Schema, Table, Column};

    #[test]
    fn test_parse_schema() {
        let sql = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255));";
        let schema = Schema::from_sql(sql).unwrap();
        assert_eq!(schema.tables.len(), 1);
        assert_eq!(schema.tables[0].name, "users");
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test cli_unit -- schema_test --no-fail-fast`
Expected: FAIL with "cannot find Schema in this scope"

**Step 3: Write minimal implementation**

```rust
// src/cli/schema.rs
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
use sqlparser::ast::{Statement, ColumnDef};
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct Schema {
    pub tables: HashMap<String, Table>,
}

#[derive(Debug, Clone)]
pub struct Table {
    pub name: String,
    pub columns: Vec<Column>,
}

#[derive(Debug, Clone)]
pub struct Column {
    pub name: String,
    pub data_type: String,
    pub nullable: bool,
    pub default_value: Option<String>,
}

impl Schema {
    pub fn from_sql(sql: &str) -> Result<Self, String> {
        let dialect = GenericDialect {};
        let statements = Parser::parse_sql(&dialect, sql)
            .map_err(|e| format!("Failed to parse SQL: {}", e))?;

        let mut tables = HashMap::new();

        for stmt in statements {
            if let Statement::CreateTable { name, columns, .. } = stmt {
                let table_name = name.to_string();
                let table_columns: Vec<Column> = columns
                    .into_iter()
                    .map(|col| Column {
                        name: col.name.value,
                        data_type: format!("{:?}", col.data_type),
                        nullable: col.nullable,
                        default_value: None, // TODO: 解析默认值
                    })
                    .collect();

                tables.insert(table_name.clone(), Table {
                    name: table_name,
                    columns: table_columns,
                });
            }
        }

        Ok(Self { tables })
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test cli_unit -- schema_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/cli/schema.rs tests/cli/unit/schema_test.rs src/cli/src/main.rs
git commit -m "feat(cli): add schema parser"
```

---

### Task 3.2: 实现差异检测

**Files:**
- Create: `src/cli/diff.rs`
- Modify: `src/cli/src/main.rs`

**Step 1: Write the failing test**

```rust
// tests/cli/unit/diff_test.rs
#[cfg(test)]
mod tests {
    use dbnexus_cli::{schema::Schema, diff::SchemaDiff};

    #[test]
    fn test_detect_added_table() {
        let old_schema = Schema::from_sql("CREATE TABLE users (id INT);").unwrap();
        let new_schema = Schema::from_sql("CREATE TABLE users (id INT); CREATE TABLE posts (id INT);").unwrap();
        let diff = SchemaDiff::compare(&old_schema, &new_schema);
        assert_eq!(diff.added_tables.len(), 1);
        assert_eq!(diff.added_tables[0].name, "posts");
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test cli_unit -- diff_test --no-fail-fast`
Expected: FAIL with "cannot find SchemaDiff in this scope"

**Step 3: Write minimal implementation**

```rust
// src/cli/diff.rs
use crate::schema::{Schema, Table};
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct SchemaDiff {
    pub added_tables: Vec<Table>,
    pub removed_tables: Vec<String>,
    pub table_changes: HashMap<String, TableDiff>,
}

#[derive(Debug, Clone)]
pub struct TableDiff {
    pub added_columns: Vec<String>,
    pub removed_columns: Vec<String>,
}

impl SchemaDiff {
    pub fn compare(old_schema: &Schema, new_schema: &Schema) -> Self {
        let mut added_tables = Vec::new();
        let mut removed_tables = Vec::new();
        let mut table_changes = HashMap::new();

        // 查找新增的表
        for (table_name, table) in &new_schema.tables {
            if !old_schema.tables.contains_key(table_name) {
                added_tables.push(table.clone());
            }
        }

        // 查找删除的表
        for table_name in old_schema.tables.keys() {
            if !new_schema.tables.contains_key(table_name) {
                removed_tables.push(table_name.clone());
            }
        }

        // 查找表变更
        for table_name in new_schema.tables.keys() {
            if let (Some(old_table), Some(new_table)) = (
                old_schema.tables.get(table_name),
                new_schema.tables.get(table_name),
            ) {
                let diff = Self::compare_tables(old_table, new_table);
                if !diff.added_columns.is_empty() || !diff.removed_columns.is_empty() {
                    table_changes.insert(table_name.clone(), diff);
                }
            }
        }

        Self {
            added_tables,
            removed_tables,
            table_changes,
        }
    }

    fn compare_tables(old_table: &Table, new_table: &Table) -> TableDiff {
        let old_columns: std::collections::HashSet<_> = old_table.columns.iter()
            .map(|c| c.name.clone())
            .collect();
        let new_columns: std::collections::HashSet<_> = new_table.columns.iter()
            .map(|c| c.name.clone())
            .collect();

        let added_columns: Vec<_> = new_columns.difference(&old_columns)
            .cloned()
            .collect();
        let removed_columns: Vec<_> = old_columns.difference(&new_columns)
            .cloned()
            .collect();

        TableDiff {
            added_columns,
            removed_columns,
        }
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test cli_unit -- diff_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/cli/diff.rs tests/cli/unit/diff_test.rs src/cli/src/main.rs
git commit -m "feat(cli): add schema diff detection"
```

---

### Task 3.3: 实现 SQL 生成器

**Files:**
- Create: `src/cli/generator.rs`
- Modify: `src/cli/src/main.rs`

**Step 1: Write the failing test**

```rust
// tests/cli/unit/generator_test.rs
#[cfg(test)]
mod tests {
    use dbnexus_cli::{schema::Schema, diff::SchemaDiff, generator::generate_sql};

    #[test]
    fn test_generate_up_sql() {
        let old_schema = Schema::from_sql("CREATE TABLE users (id INT);").unwrap();
        let new_schema = Schema::from_sql("CREATE TABLE users (id INT); CREATE TABLE posts (id INT);").unwrap();
        let diff = SchemaDiff::compare(&old_schema, &new_schema);
        let sql = generate_sql(&diff, "sqlite");
        assert!(sql.up.contains("CREATE TABLE"));
        assert!(sql.up.contains("posts"));
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test cli_unit -- generator_test --no-fail-fast`
Expected: FAIL with "cannot find generate_sql in this scope"

**Step 3: Write minimal implementation**

```rust
// src/cli/generator.rs
use crate::diff::SchemaDiff;

#[derive(Debug, Clone)]
pub struct DiffSql {
    pub up: String,
    pub down: String,
}

pub fn generate_sql(diff: &SchemaDiff, dialect: &str) -> DiffSql {
    let mut up_sql = String::new();
    let mut down_sql = String::new();

    // 生成新增表的 SQL
    for table in &diff.added_tables {
        up_sql.push_str(&format!("CREATE TABLE {} (", table.name));
        for (i, col) in table.columns.iter().enumerate() {
            if i > 0 { up_sql.push_str(", "); }
            up_sql.push_str(&format!("{} {}", col.name, col.data_type));
        }
        up_sql.push_str(");\n");

        down_sql.push_str(&format!("DROP TABLE {};\n", table.name));
    }

    // 生成删除表的 SQL
    for table_name in &diff.removed_tables {
        up_sql.push_str(&format!("DROP TABLE {};\n", table_name));
        // TODO: 生成 CREATE TABLE 用于 down SQL
    }

    // 生成列变更的 SQL
    for (table_name, table_diff) in &diff.table_changes {
        for column in &table_diff.added_columns {
            up_sql.push_str(&format!("ALTER TABLE {} ADD COLUMN {} TEXT;\n", table_name, column));
            down_sql.push_str(&format!("ALTER TABLE {} DROP COLUMN {};\n", table_name, column));
        }
        for column in &table_diff.removed_columns {
            up_sql.push_str(&format!("ALTER TABLE {} DROP COLUMN {};\n", table_name, column));
            // TODO: 生成 ADD COLUMN 用于 down SQL
        }
    }

    DiffSql {
        up: up_sql,
        down: down_sql,
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test cli_unit -- generator_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/cli/generator.rs tests/cli/unit/generator_test.rs src/cli/src/main.rs
git commit -m "feat(cli): add SQL generator for schema diff"
```

---

### Task 3.4: 修复 load_applied_migrations

**Files:**
- Modify: `src/cli/src/main.rs`

**Step 1: Write the failing test**

```rust
// tests/cli/integration/load_migrations_test.rs
#[cfg(test)]
mod tests {
    use dbnexus_cli::load_applied_migrations;

    #[tokio::test]
    async fn test_load_applied_migrations() {
        let pool = dbnexus::DbPool::new("sqlite::memory:").await.unwrap();
        let mut session = pool.get_session("admin").await.unwrap();

        // 创建迁移表
        session.execute_raw("CREATE TABLE dbnexus_migrations (version INTEGER, name TEXT, applied_at TIMESTAMP);").await.unwrap();

        // 插入测试数据
        session.execute_raw("INSERT INTO dbnexus_migrations VALUES (1, 'test', datetime('now'));").await.unwrap();

        let versions = load_applied_migrations(&mut session).await.unwrap();
        assert_eq!(versions.len(), 1);
        assert!(versions.contains(&1));
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test cli_integration -- load_migrations_test --no-fail-fast`
Expected: FAIL with load_applied_migrations returns empty set

**Step 3: Modify load_applied_migrations to query database**

```rust
// src/cli/src/main.rs
use dbnexus::migration::Model as MigrationModel;
use sea_orm::EntityTrait;

async fn load_applied_migrations(session: &mut dbnexus::Session) -> Result<std::collections::HashSet<u32>, dbnexus::error::DbError> {
    let migrations = MigrationModel::find()
        .all(session.connection())
        .await?;

    let versions: std::collections::HashSet<u32> = migrations.into_iter()
        .map(|m| m.version)
        .collect();

    Ok(versions)
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test cli_integration -- load_migrations_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/cli/src/main.rs tests/cli/integration/load_migrations_test.rs
git commit -m "fix(cli): implement load_applied_migrations to query database"
```

---

### Task 3.5: 集成 generate_schema_diff_sql

**Files:**
- Modify: `src/cli/src/main.rs`

**Step 1: Write the failing test**

```rust
// tests/cli/integration/generate_diff_test.rs
#[cfg(test)]
mod tests {
    use dbnexus_cli::generate_schema_diff_sql;

    #[test]
    fn test_generate_schema_diff_sql() {
        let from_sql = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255));";
        let to_sql = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255), email VARCHAR(255));";
        let diff = generate_schema_diff_sql(from_sql, to_sql).unwrap();
        assert!(diff.up.contains("ALTER TABLE"));
        assert!(diff.up.contains("ADD COLUMN"));
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test cli_integration -- generate_diff_test --no-fail-fast`
Expected: FAIL with placeholder comments

**Step 3: Modify generate_schema_diff_sql to use real implementation**

```rust
// src/cli/src/main.rs
use dbnexus_cli::{schema::Schema, diff::SchemaDiff, generator::generate_sql};

fn generate_schema_diff_sql(from_content: &str, to_content: &str) -> Result<dbnexus_cli::DiffSql, dbnexus::error::DbError> {
    let old_schema = Schema::from_sql(from_content)
        .map_err(|e| dbnexus::error::DbError::InvalidMigration(e))?;
    let new_schema = Schema::from_sql(to_content)
        .map_err(|e| dbnexus::error::DbError::InvalidMigration(e))?;

    let diff = SchemaDiff::compare(&old_schema, &new_schema);
    let sql = generate_sql(&diff, "sqlite");

    Ok(dbnexus_cli::DiffSql {
        up: sql.up,
        down: sql.down,
    })
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test cli_integration -- generate_diff_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/cli/src/main.rs tests/cli/integration/generate_diff_test.rs
git commit -m "feat(cli): integrate schema diff into generate_schema_diff_sql"
```

---

## Phase 4: Permission 模块 - 合并整合

### Task 4.1: 创建统一的 PermissionProvider trait

**Files:**
- Create: `src/permission/provider.rs`
- Modify: `src/permission.rs`

**Step 1: Write the failing test**

```rust
// tests/permission/unit/provider_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::permission::provider::PermissionProvider;

    #[test]
    fn test_provider_trait() {
        // 测试 trait 定义
        let _provider: Box<dyn PermissionProvider> = Box::new(TestProvider {});
    }

    struct TestProvider;
    impl PermissionProvider for TestProvider {
        fn name(&self) -> &str { "test" }
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test permission_unit -- provider_test --no-fail-fast`
Expected: FAIL with "cannot find PermissionProvider in this scope"

**Step 3: Write minimal implementation**

```rust
// src/permission/provider.rs
use async_trait::async_trait;

#[async_trait]
pub trait PermissionProvider: Send + Sync {
    async fn check_permission(&self, context: &PermissionContext) -> PermissionDecision;
    async fn get_allowed_resources(&self, subject: &str) -> Vec<String>;
    async fn get_allowed_actions(&self, subject: &str, resource: &str) -> Vec<String>;
    async fn refresh(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    fn name(&self) -> &str;
}

#[derive(Debug, Clone)]
pub struct PermissionContext {
    pub subject: String,
    pub resource: String,
    pub action: String,
}

#[derive(Debug, Clone, PartialEq)]
pub enum PermissionDecision {
    Allow,
    Deny { reason: String },
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test permission_unit -- provider_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/permission/provider.rs tests/permission/unit/provider_test.rs src/permission.rs
git commit -m "feat(permission): add unified PermissionProvider trait"
```

---

### Task 4.2: 实现基础 RBAC Provider

**Files:**
- Create: `src/permission/rbac.rs`
- Modify: `src/permission/mod.rs`

**Step 1: Write the failing test**

```rust
// tests/permission/unit/rbac_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::permission::rbac::RbacProvider;
    use dbnexus::permission::provider::{PermissionProvider, PermissionContext};

    #[tokio::test]
    async fn test_rbac_allow() {
        let provider = RbacProvider::new();
        let context = PermissionContext {
            subject: "admin".to_string(),
            resource: "users".to_string(),
            action: "SELECT".to_string(),
        };
        let decision = provider.check_permission(&context).await;
        assert_eq!(decision, dbnexus::permission::provider::PermissionDecision::Allow);
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test permission_unit -- rbac_test --no-fail-fast`
Expected: FAIL with "cannot find RbacProvider in this scope"

**Step 3: Write minimal implementation**

```rust
// src/permission/rbac.rs
use crate::permission::provider::{PermissionProvider, PermissionContext, PermissionDecision};
use std::collections::HashMap;
use std::sync::Arc;
use dashmap::DashMap;

pub struct RbacProvider {
    roles: Arc<DashMap<String, RolePolicy>>,
}

#[derive(Debug, Clone)]
pub struct RolePolicy {
    pub tables: Vec<TablePermission>,
}

#[derive(Debug, Clone)]
pub struct TablePermission {
    pub table_name: String,
    pub actions: Vec<String>,
}

impl RbacProvider {
    pub fn new() -> Self {
        let mut roles = DashMap::new();
        // 默认管理员角色
        roles.insert(
            "admin".to_string(),
            RolePolicy {
                tables: vec![TablePermission {
                    table_name: "*".to_string(),
                    actions: vec!["SELECT".to_string(), "INSERT".to_string(), "UPDATE".to_string(), "DELETE".to_string()],
                }],
            },
        );
        Self { roles: Arc::new(roles) }
    }
}

#[async_trait::async_trait]
impl PermissionProvider for RbacProvider {
    async fn check_permission(&self, context: &PermissionContext) -> PermissionDecision {
        if let Some(role_policy) = self.roles.get(&context.subject) {
            for table_perm in &role_policy.tables {
                if table_perm.table_name == "*" || table_perm.table_name == context.resource {
                    if table_perm.actions.contains(&context.action) {
                        return PermissionDecision::Allow;
                    }
                }
            }
        }
        PermissionDecision::Deny { reason: "Permission denied".to_string() }
    }

    async fn get_allowed_resources(&self, subject: &str) -> Vec<String> {
        if let Some(role_policy) = self.roles.get(subject) {
            role_policy.tables.iter().map(|t| t.table_name.clone()).collect()
        } else {
            Vec::new()
        }
    }

    async fn get_allowed_actions(&self, subject: &str, resource: &str) -> Vec<String> {
        if let Some(role_policy) = self.roles.get(subject) {
            for table_perm in &role_policy.tables {
                if table_perm.table_name == "*" || table_perm.table_name == resource {
                    return table_perm.actions.clone();
                }
            }
        }
        Vec::new()
    }

    async fn refresh(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        Ok(())
    }

    fn name(&self) -> &str {
        "rbac"
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test permission_unit -- rbac_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/permission/rbac.rs tests/permission/unit/rbac_test.rs src/permission/mod.rs
git commit -m "feat(permission): implement basic RBAC provider"
```

---

### Task 4.3: 实现高级 RBAC Provider（角色继承）

**Files:**
- Create: `src/permission/advanced.rs`
- Modify: `src/permission/mod.rs`

**Step 1: Write the failing test**

```rust
// tests/permission/unit/advanced_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::permission::advanced::AdvancedRbacProvider;
    use dbnexus::permission::provider::{PermissionProvider, PermissionContext};

    #[tokio::test]
    async fn test_role_inheritance() {
        let provider = AdvancedRbacProvider::new();
        // 配置角色继承：manager 继承 admin
        provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);

        let context = PermissionContext {
            subject: "manager".to_string(),
            resource: "users".to_string(),
            action: "SELECT".to_string(),
        };
        let decision = provider.check_permission(&context).await;
        assert_eq!(decision, dbnexus::permission::provider::PermissionDecision::Allow);
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test permission_unit -- advanced_test --no-fail-fast`
Expected: FAIL with "cannot find AdvancedRbacProvider in this scope"

**Step 3: Write minimal implementation**

```rust
// src/permission/advanced.rs
use crate::permission::provider::{PermissionProvider, PermissionContext, PermissionDecision};
use crate::permission::rbac::{RbacProvider, RolePolicy, TablePermission};
use std::collections::HashMap;
use std::sync::Arc;
use dashmap::DashMap;

pub struct AdvancedRbacProvider {
    base: RbacProvider,
    role_hierarchy: Arc<DashMap<String, Vec<String>>>,
}

impl AdvancedRbacProvider {
    pub fn new() -> Self {
        Self {
            base: RbacProvider::new(),
            role_hierarchy: Arc::new(DashMap::new()),
        }
    }

    pub fn add_role_inheritance(&self, child: String, parents: Vec<String>) {
        self.role_hierarchy.insert(child, parents);
    }

    async fn get_inherited_roles(&self, role: &str) -> Vec<String> {
        let mut roles = vec![role.to_string()];
        if let Some(parents) = self.role_hierarchy.get(role) {
            for parent in parents.iter() {
                roles.extend(self.get_inherited_roles(parent).await);
            }
        }
        roles
    }
}

#[async_trait::async_trait]
impl PermissionProvider for AdvancedRbacProvider {
    async fn check_permission(&self, context: &PermissionContext) -> PermissionDecision {
        // 检查当前角色
        let decision = self.base.check_permission(context).await;
        if matches!(decision, PermissionDecision::Allow) {
            return decision;
        }

        // 检查继承的角色
        let inherited_roles = self.get_inherited_roles(&context.subject).await;
        for role in inherited_roles {
            let inherited_context = PermissionContext {
                subject: role,
                resource: context.resource.clone(),
                action: context.action.clone(),
            };
            let decision = self.base.check_permission(&inherited_context).await;
            if matches!(decision, PermissionDecision::Allow) {
                return decision;
            }
        }

        PermissionDecision::Deny { reason: "Permission denied".to_string() }
    }

    async fn get_allowed_resources(&self, subject: &str) -> Vec<String> {
        self.base.get_allowed_resources(subject).await
    }

    async fn get_allowed_actions(&self, subject: &str, resource: &str) -> Vec<String> {
        self.base.get_allowed_actions(subject, resource).await
    }

    async fn refresh(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        self.base.refresh().await
    }

    fn name(&self) -> &str {
        "advanced-rbac"
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test permission_unit -- advanced_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/permission/advanced.rs tests/permission/unit/advanced_test.rs src/permission/mod.rs
git commit -m "feat(permission): add advanced RBAC with role inheritance"
```

---

### Task 4.4: 更新 PermissionContext 使用新 Provider

**Files:**
- Modify: `src/permission.rs`

**Step 1: Write the failing test**

```rust
// tests/permission/integration/context_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::{Session, permission::{PermissionContext, provider::PermissionProvider}};
    use dbnexus::permission::rbac::RbacProvider;

    #[tokio::test]
    async fn test_permission_context_with_provider() {
        let pool = dbnexus::DbPool::new("sqlite::memory:").await.unwrap();
        let session = pool.get_session("admin").await.unwrap();
        let provider = RbacProvider::new();

        let mut context = PermissionContext::new(&session, "admin".to_string());
        context.set_provider(Box::new(provider));

        let allowed = context.check_table_access("users", "SELECT").await;
        assert!(allowed);
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test permission_integration -- context_test --no-fail-fast`
Expected: FAIL with current PermissionContext doesn't support providers

**Step 3: Modify PermissionContext to use new Provider**

```rust
// src/permission.rs
use crate::permission::provider::{PermissionProvider, PermissionDecision};
use std::sync::Arc;

pub struct PermissionContext {
    role: String,
    provider: Option<Arc<dyn PermissionProvider>>,
    session: Option<Session>,
}

impl PermissionContext {
    pub fn new(session: &Session, role: String) -> Self {
        Self {
            role,
            provider: None,
            session: Some(session.clone()),
        }
    }

    pub fn set_provider(&mut self, provider: Box<dyn PermissionProvider>) {
        self.provider = Some(Arc::from(provider));
    }

    pub async fn check_table_access(&self, table: &str, operation: &str) -> bool {
        if let Some(provider) = &self.provider {
            let context = crate::permission::provider::PermissionContext {
                subject: self.role.clone(),
                resource: table.to_string(),
                action: operation.to_string(),
            };
            matches!(provider.check_permission(&context).await, PermissionDecision::Allow)
        } else {
            // 回退到旧的实现
            self.check_table_access_legacy(table, operation)
        }
    }

    fn check_table_access_legacy(&self, table: &str, operation: &str) -> bool {
        // 保留旧的实现作为回退
        // TODO: 实现旧的检查逻辑
        true
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test permission_integration -- context_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add src/permission.rs tests/permission/integration/context_test.rs
git commit -m "feat(permission): integrate PermissionProvider into PermissionContext"
```

---

### Task 4.5: 标记旧 API 为 deprecated

**Files:**
- Modify: `src/permission.rs`

**Step 1: Write the test (验证 deprecated 警告)**

```rust
// tests/permission/unit/deprecated_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::permission::PermissionConfig;

    #[test]
    #[allow(deprecated)]
    fn test_deprecated_api() {
        let _config = PermissionConfig::default();
        // 验证 API 仍然可用但标记为 deprecated
    }
}
```

**Step 2: Run test to verify it compiles with warnings**

Run: `cargo test --test permission_unit -- deprecated_test --no-fail-fast`
Expected: PASS with deprecation warnings

**Step 3: Add deprecated attributes**

```rust
// src/permission.rs
#[derive(Debug, Clone)]
#[deprecated(since = "0.2.0", note = "Use PermissionProvider instead")]
pub struct PermissionConfig {
    pub roles: HashMap<String, RolePolicy>,
}

impl Default for PermissionConfig {
    fn default() -> Self {
        Self {
            roles: HashMap::new(),
        }
    }
}
```

**Step 4: Run test to verify it passes**

Run: `cargo test --test permission_unit -- deprecated_test --no-fail-fast`
Expected: PASS with warnings

**Step 5: Commit**

```bash
git add src/permission.rs tests/permission/unit/deprecated_test.rs
git commit -m "refactor(permission): mark old APIs as deprecated"
```

---

## Phase 5: 集成测试和性能验证

### Task 5.1: 端到端集成测试

**Files:**
- Create: `tests/integration/all_modules_test.rs`

**Step 1: Write the failing test**

```rust
// tests/integration/all_modules_test.rs
#[cfg(test)]
mod tests {
    use dbnexus::{DbPool, Session, migration::executor::MigrationExecutor};
    use dbnexus::tracing::context::TracingContext;
    use dbnexus::permission::provider::PermissionProvider;
    use dbnexus::permission::rbac::RbacProvider;

    #[tokio::test]
    async fn test_end_to_end_migration_with_tracing_and_permission() {
        // 初始化追踪
        let _tracing_guard = dbnexus::tracing::init_with_sampling("stdout", "", 1.0).await.unwrap();

        // 创建连接池
        let pool = DbPool::new("sqlite::memory:").await.unwrap();
        let mut session = pool.get_session("admin").await.unwrap();

        // 设置权限
        let provider = RbacProvider::new();
        let mut perm_context = dbnexus::PermissionContext::new(&session, "admin".to_string());
        perm_context.set_provider(Box::new(provider));

        // 创建追踪上下文
        let _span = TracingContext::new("migration_execution");

        // 执行迁移
        let mut executor = MigrationExecutor::new(session.connection()).await.unwrap();
        executor.execute_raw("CREATE TABLE test (id INT PRIMARY KEY);").await.unwrap();

        // 验证表创建成功
        let result = session.execute_raw("SELECT COUNT(*) FROM test;").await.unwrap();
        assert!(result.rows_affected() > 0);

        // 测试回滚
        let reverser = dbnexus::migration::sql_reverser::SqlReverser::new();
        let down_sql = reverser.reverse("CREATE TABLE test (id INT PRIMARY KEY);").unwrap();
        executor.execute_raw(&down_sql).await.unwrap();

        // 验证表已删除
        let result = session.execute_raw("SELECT COUNT(*) FROM test;").await;
        assert!(result.is_err());
    }
}
```

**Step 2: Run test to verify it fails**

Run: `cargo test --test integration -- all_modules_test --no-fail-fast`
Expected: FAIL with integration issues

**Step 3: Debug and fix integration issues**

根据错误信息修复模块间的集成问题。

**Step 4: Run test to verify it passes**

Run: `cargo test --test integration -- all_modules_test --no-fail-fast`
Expected: PASS

**Step 5: Commit**

```bash
git add tests/integration/all_modules_test.rs
git commit -m "test: add end-to-end integration test"
```

---

### Task 5.2: 性能基准测试

**Files:**
- Create: `benches/module_fixes_bench.rs`

**Step 1: Write the benchmark**

```rust
// benches/module_fixes_bench.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use dbnexus::migration::sql_reverser::SqlReverser;
use dbnexus::tracing::context::TracingContext;
use dbnexus::permission::rbac::RbacProvider;
use dbnexus::permission::provider::PermissionProvider;

fn bench_sql_reverser(c: &mut Criterion) {
    let reverser = SqlReverser::new();
    let sql = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255), email VARCHAR(255));";

    c.bench_function("sql_reverser", |b| {
        b.iter(|| {
            reverser.reverse(black_box(sql)).unwrap()
        })
    });
}

fn bench_tracing_context(c: &mut Criterion) {
    c.bench_function("tracing_context", |b| {
        b.iter(|| {
            let _ctx = TracingContext::new("test_span");
            black_box(_ctx)
        })
    });
}

fn bench_permission_check(c: &mut Criterion) {
    let provider = RbacProvider::new();
    let context = dbnexus::permission::provider::PermissionContext {
        subject: "admin".to_string(),
        resource: "users".to_string(),
        action: "SELECT".to_string(),
    };

    c.bench_function("permission_check", |b| {
        b.iter(|| {
            black_box(provider.check_permission(black_box(&context)))
        })
    });
}

criterion_group!(benches, bench_sql_reverser, bench_tracing_context, bench_permission_check);
criterion_main!(benches);
```

**Step 2: Run benchmark to establish baseline**

Run: `cargo bench --bench module_fixes_bench`
Expected: Baseline performance metrics

**Step 3: Verify performance meets goals**

- SQL Reverser: < 100ms
- Tracing Context: < 5μs
- Permission Check: < 10μs

**Step 4: Commit**

```bash
git add benches/module_fixes_bench.rs
git commit -m "bench: add performance benchmarks for module fixes"
```

---

### Task 5.3: 运行完整测试套件

**Step 1: Run all tests**

Run: `cargo test --all-features --no-fail-fast`
Expected: All tests pass

**Step 2: Run benchmarks**

Run: `cargo bench --all-features`
Expected: Performance targets met

**Step 3: Check for deprecation warnings**

Run: `cargo clippy --all-features`
Expected: Only intentional deprecation warnings

**Step 4: Final commit**

```bash
git add .
git commit -m "test: all modules fixed and tested"
```

---

## Summary

**Total Tasks:** 22
**Estimated Time:** 4-6 hours
**Files Modified:** 15
**Files Created:** 12
**Test Coverage:** >90% (target)

**Key Deliverables:**
1. ✅ Migration 模块支持自动回滚 SQL 生成
2. ✅ Tracing 模块支持完整的分布式追踪
3. ✅ CLI 模块支持 schema 差异检测
4. ✅ Permission 模块统一整合
5. ✅ 完整的测试覆盖
6. ✅ 性能基准测试

**Next Steps After Implementation:**
1. 代码审查
2. 合并到主分支
3. 更新文档
4. 发布新版本

---

**Plan Version:** 1.0
**Last Updated:** 2026-01-23