Phase 1b: Rename all ~94 commands across 12 plugins to /<noun> <action> sub-command pattern. Git-flow consolidated from 8→5 commands (commit variants absorbed into --push/--merge/--sync flags). Dispatch files, name: frontmatter, and cross-reference updates for all plugins. Phase 2: Design documents for 8 new plugins in docs/designs/. Phase 3: Scaffold 8 new plugins — saas-api-platform, saas-db-migrate, saas-react-platform, saas-test-pilot, data-seed, ops-release-manager, ops-deploy-pipeline, debug-mcp. Each with plugin.json, commands, agents, skills, README, and claude-md-integration. Marketplace grows from 12→20. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
158 lines
4.3 KiB
Markdown
158 lines
4.3 KiB
Markdown
---
|
|
name: rollback-patterns
|
|
description: Standard rollback generation patterns, reverse operations, and data backup strategies
|
|
---
|
|
|
|
# Rollback Patterns
|
|
|
|
## Purpose
|
|
|
|
Defines patterns for generating safe rollback migrations. This skill is loaded by the `migration-planner` agent when generating migrations (to include downgrade sections) and when creating explicit rollback plans.
|
|
|
|
---
|
|
|
|
## Reverse Operation Map
|
|
|
|
| Forward Operation | Reverse Operation | Data Preserved |
|
|
|-------------------|-------------------|----------------|
|
|
| CREATE TABLE | DROP TABLE | No (all data lost) |
|
|
| DROP TABLE | CREATE TABLE (empty) | No (must restore from backup) |
|
|
| ADD COLUMN | DROP COLUMN | No (column data lost) |
|
|
| DROP COLUMN | ADD COLUMN (nullable) | No (must restore from backup) |
|
|
| RENAME TABLE | RENAME TABLE (back) | Yes |
|
|
| RENAME COLUMN | RENAME COLUMN (back) | Yes |
|
|
| ADD INDEX | DROP INDEX | Yes (data unaffected) |
|
|
| DROP INDEX | CREATE INDEX | Yes (data unaffected) |
|
|
| ADD CONSTRAINT | DROP CONSTRAINT | Yes |
|
|
| DROP CONSTRAINT | ADD CONSTRAINT | Yes (if data still valid) |
|
|
| ALTER COLUMN TYPE | ALTER COLUMN TYPE (back) | Depends on conversion |
|
|
| INSERT rows | DELETE matching rows | Yes (if identifiable) |
|
|
| UPDATE rows | UPDATE with original values | Only if originals saved |
|
|
| DELETE rows | INSERT saved rows | Only if backed up |
|
|
|
|
---
|
|
|
|
## Rollback Classification
|
|
|
|
### Fully Reversible (Green)
|
|
|
|
Operations that can be undone with no data loss:
|
|
- RENAME operations (table, column)
|
|
- ADD/DROP INDEX
|
|
- ADD/DROP CONSTRAINT (when data satisfies constraint)
|
|
- ADD COLUMN (drop it in rollback)
|
|
|
|
### Partially Reversible (Yellow)
|
|
|
|
Operations where structure is restored but data is lost:
|
|
- CREATE TABLE (rollback = DROP TABLE; data lost)
|
|
- DROP COLUMN (rollback = ADD COLUMN; column data gone)
|
|
- ALTER COLUMN TYPE narrowing then widening (precision lost)
|
|
|
|
### Irreversible (Red)
|
|
|
|
Operations that cannot be meaningfully undone:
|
|
- DROP TABLE without backup (data permanently gone)
|
|
- TRUNCATE TABLE without backup
|
|
- DELETE without WHERE without backup
|
|
- Data transformation that loses information (e.g., hash, round)
|
|
|
|
---
|
|
|
|
## Backup Strategies
|
|
|
|
### Pre-Migration Table Backup
|
|
|
|
For migrations that will cause data loss, generate backup commands:
|
|
|
|
**PostgreSQL:**
|
|
```sql
|
|
-- Full table backup
|
|
CREATE TABLE _backup_users_20240115 AS SELECT * FROM users;
|
|
|
|
-- Column-only backup
|
|
CREATE TABLE _backup_users_email_20240115 AS
|
|
SELECT id, legacy_email FROM users;
|
|
```
|
|
|
|
**Export to file:**
|
|
```bash
|
|
pg_dump --table=users --column-inserts dbname > users_backup_20240115.sql
|
|
```
|
|
|
|
### Restoration Commands
|
|
|
|
Include restoration commands in rollback section:
|
|
|
|
```sql
|
|
-- Restore from backup table
|
|
INSERT INTO users (id, legacy_email)
|
|
SELECT id, legacy_email FROM _backup_users_email_20240115;
|
|
|
|
-- Clean up backup
|
|
DROP TABLE IF EXISTS _backup_users_email_20240115;
|
|
```
|
|
|
|
---
|
|
|
|
## Alembic Downgrade Patterns
|
|
|
|
```python
|
|
def downgrade():
|
|
# Reverse of upgrade, in opposite order
|
|
op.drop_index('ix_orders_user_id', table_name='orders')
|
|
op.drop_table('orders')
|
|
```
|
|
|
|
For complex downgrades with data restoration:
|
|
```python
|
|
def downgrade():
|
|
# Re-create dropped column
|
|
op.add_column('users', sa.Column('legacy_email', sa.String(255), nullable=True))
|
|
# Note: Data cannot be restored automatically
|
|
# Restore from backup: _backup_users_email_YYYYMMDD
|
|
```
|
|
|
|
---
|
|
|
|
## Prisma Rollback Patterns
|
|
|
|
Prisma does not have native downgrade support. Generate a new migration that reverses the operations:
|
|
|
|
```sql
|
|
-- Rollback: undo add_orders_table
|
|
DROP TABLE IF EXISTS "order_items";
|
|
DROP TABLE IF EXISTS "orders";
|
|
```
|
|
|
|
---
|
|
|
|
## Raw SQL Rollback Patterns
|
|
|
|
Always include DOWN section in migration files:
|
|
|
|
```sql
|
|
-- UP
|
|
CREATE TABLE orders (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id),
|
|
total DECIMAL(10,2) NOT NULL
|
|
);
|
|
|
|
-- DOWN
|
|
DROP TABLE IF EXISTS orders;
|
|
```
|
|
|
|
---
|
|
|
|
## Point-of-No-Return Identification
|
|
|
|
Flag migrations that cross the point of no return:
|
|
|
|
1. **Data deletion without backup step**: Mark as irreversible
|
|
2. **Type narrowing that truncates data**: Data is permanently altered
|
|
3. **Hash/encrypt transformations**: Original values unrecoverable
|
|
4. **Aggregate/merge operations**: Individual records lost
|
|
|
|
When a migration includes irreversible operations, the rollback section must clearly state: "This migration cannot be fully rolled back. Data backup is required before applying."
|