# SM003: drop_table_unsafe

| Property       | Value             |
| -------------- | ----------------- |
| **Rule ID**    | SM003             |
| **Severity**   | WARNING           |
| **Name**       | drop_table_unsafe |
| **Applies to** | All databases     |

## What Triggers This Rule

This rule triggers when a migration contains `DeleteModel`:

```python
# Triggers SM003
migrations.DeleteModel(
    name='LegacyModel',
)
```

## Why It's Dangerous

Dropping a table has the same risks as dropping a column, but with even more severe consequences:

1. **All data is permanently lost** — No recovery without backups
2. **All queries fail** — Any code referencing the table crashes
3. **Foreign key violations** — Other tables may reference this table
4. **Cascading failures** — Dependent code and jobs all fail

### Real-World Failure Scenario

```
Timeline:
├─ 0:00  Migration runs → table deleted
├─ 0:00  All rows permanently gone (unless backed up)
├─ 0:01  Server 1 (old code): SELECT * FROM legacy_table
├─ 0:01  Database: ERROR - relation "legacy_table" does not exist
├─ 0:01  User sees 500 error
├─ 0:02  Background job tries to query table
├─ 0:02  Job fails, error logged
├─ 0:03  Related models with ForeignKey fail
└─ ...   Cascading failures continue
```

## When It's Safe to Ignore

This warning can be safely ignored when:

1. **The table is truly unused** — No code references, no foreign keys
2. **You've verified in production** — Checked for any remaining queries
3. **Data has been migrated** — If needed, data moved to new location
4. **Backups are confirmed** — In case recovery is needed
5. **Blue-green deployment** — Complete cutover, no rolling update

## How to Fix It

### Recommended: Multi-Phase Removal

**Phase 1: Stop Writing**

1. Remove code that writes to the table
2. Keep read access for now
3. Deploy and monitor

**Phase 2: Stop Reading**

1. Remove all code that reads from the table
2. Remove from admin, serializers, views
3. Deploy and wait for all instances to update

**Phase 3: Remove Foreign Keys**

If other tables reference this table:

```python
# Remove FK relationships first
migrations.RemoveField(
    model_name='order',
    name='legacy_model',
)
```

**Phase 4: Drop the Table**

After confirming no references remain:

```python
migrations.DeleteModel(
    name='LegacyModel',
)
```

### Pre-Deletion Checklist

Before dropping a table, verify:

- [ ] No model code references this table
- [ ] No raw SQL queries reference this table
- [ ] No foreign keys point to this table
- [ ] No admin configurations reference this model
- [ ] No serializers or views reference this model
- [ ] No background jobs query this table
- [ ] Data has been backed up or migrated
- [ ] All application instances have been updated

## How to Suppress

### In Django Settings

```python
SAFE_MIGRATIONS = {
    "DISABLED_RULES": ["SM003"],
}
```

### Suppress for Specific Apps

```python
SAFE_MIGRATIONS = {
    "RULE_CONFIG": {
        "SM003": {
            "ignore_apps": ["legacy_app"],
        },
    },
}
```

## See Also

- [SM002: drop_column_unsafe](SM002.md) — Similar rule for dropping columns
- [Safe Patterns: Removing Columns](../patterns.md#removing-columns)
