[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7AMMVWNFSX51M35WA2DNPE1":3,"skill-same:01M7AMMVWNFSX51M35WA2DNPE1":48},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":14,"repositoryHtmlUrl":30,"repositoryHomepageUrl":6,"ownerHtmlUrl":31,"ownerBlogUrl":6,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M7AMMVWNFSX51M35WA2DNPE1","database-migration",null,"Master database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.","GongYuanCaiJi\u002Fdsh-claude-code-templates","GongYuanCaiJi","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F129952120?v=4","01M7AK39Q4W3VPF7C1K8M58BFX","劉昱廷 Yu-Ting Liu","01M7AK39QPS2RAJKRQY0EPQJPZ",0,"MIT","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fdatabase\u002Fdatabase-migration\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: database-migration\ndescription: \"Master database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# Database Migration\n\nMaster database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.\n\n## Do not use this skill when\n\n- The task is unrelated to database migration\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Migrating between different ORMs\n- Performing schema transformations\n- Moving data between databases\n- Implementing rollback procedures\n- Zero-downtime deployments\n- Database version upgrades\n- Data model refactoring\n\n## ORM Migrations\n\n### Sequelize Migrations\n```javascript\n\u002F\u002F migrations\u002F20231201-create-users.js\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.createTable('users', {\n      id: {\n        type: Sequelize.INTEGER,\n        primaryKey: true,\n        autoIncrement: true\n      },\n      email: {\n        type: Sequelize.STRING,\n        unique: true,\n        allowNull: false\n      },\n      createdAt: Sequelize.DATE,\n      updatedAt: Sequelize.DATE\n    });\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.dropTable('users');\n  }\n};\n\n\u002F\u002F Run: npx sequelize-cli db:migrate\n\u002F\u002F Rollback: npx sequelize-cli db:migrate:undo\n```\n\n### TypeORM Migrations\n```typescript\n\u002F\u002F migrations\u002F1701234567-CreateUsers.ts\nimport { MigrationInterface, QueryRunner, Table } from 'typeorm';\n\nexport class CreateUsers1701234567 implements MigrationInterface {\n  public async up(queryRunner: QueryRunner): Promise\u003Cvoid> {\n    await queryRunner.createTable(\n      new Table({\n        name: 'users',\n        columns: [\n          {\n            name: 'id',\n            type: 'int',\n            isPrimary: true,\n            isGenerated: true,\n            generationStrategy: 'increment'\n          },\n          {\n            name: 'email',\n            type: 'varchar',\n            isUnique: true\n          },\n          {\n            name: 'created_at',\n            type: 'timestamp',\n            default: 'CURRENT_TIMESTAMP'\n          }\n        ]\n      })\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise\u003Cvoid> {\n    await queryRunner.dropTable('users');\n  }\n}\n\n\u002F\u002F Run: npm run typeorm migration:run\n\u002F\u002F Rollback: npm run typeorm migration:revert\n```\n\n### Prisma Migrations\n```prisma\n\u002F\u002F schema.prisma\nmodel User {\n  id        Int      @id @default(autoincrement())\n  email     String   @unique\n  createdAt DateTime @default(now())\n}\n\n\u002F\u002F Generate migration: npx prisma migrate dev --name create_users\n\u002F\u002F Apply: npx prisma migrate deploy\n```\n\n## Schema Transformations\n\n### Adding Columns with Defaults\n```javascript\n\u002F\u002F Safe migration: add column with default\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'status', {\n      type: Sequelize.STRING,\n      defaultValue: 'active',\n      allowNull: false\n    });\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'status');\n  }\n};\n```\n\n### Renaming Columns (Zero Downtime)\n```javascript\n\u002F\u002F Step 1: Add new column\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'full_name', {\n      type: Sequelize.STRING\n    });\n\n    \u002F\u002F Copy data from old column\n    await queryInterface.sequelize.query(\n      'UPDATE users SET full_name = name'\n    );\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'full_name');\n  }\n};\n\n\u002F\u002F Step 2: Update application to use new column\n\n\u002F\u002F Step 3: Remove old column\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'name');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'name', {\n      type: Sequelize.STRING\n    });\n  }\n};\n```\n\n### Changing Column Types\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F For large tables, use multi-step approach\n\n    \u002F\u002F 1. Add new column\n    await queryInterface.addColumn('users', 'age_new', {\n      type: Sequelize.INTEGER\n    });\n\n    \u002F\u002F 2. Copy and transform data\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET age_new = CAST(age AS INTEGER)\n      WHERE age IS NOT NULL\n    `);\n\n    \u002F\u002F 3. Drop old column\n    await queryInterface.removeColumn('users', 'age');\n\n    \u002F\u002F 4. Rename new column\n    await queryInterface.renameColumn('users', 'age_new', 'age');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.changeColumn('users', 'age', {\n      type: Sequelize.STRING\n    });\n  }\n};\n```\n\n## Data Transformations\n\n### Complex Data Migration\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F Get all records\n    const [users] = await queryInterface.sequelize.query(\n      'SELECT id, address_string FROM users'\n    );\n\n    \u002F\u002F Transform each record\n    for (const user of users) {\n      const addressParts = user.address_string.split(',');\n\n      await queryInterface.sequelize.query(\n        `UPDATE users\n         SET street = :street,\n             city = :city,\n             state = :state\n         WHERE id = :id`,\n        {\n          replacements: {\n            id: user.id,\n            street: addressParts[0]?.trim(),\n            city: addressParts[1]?.trim(),\n            state: addressParts[2]?.trim()\n          }\n        }\n      );\n    }\n\n    \u002F\u002F Drop old column\n    await queryInterface.removeColumn('users', 'address_string');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    \u002F\u002F Reconstruct original column\n    await queryInterface.addColumn('users', 'address_string', {\n      type: Sequelize.STRING\n    });\n\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET address_string = CONCAT(street, ', ', city, ', ', state)\n    `);\n\n    await queryInterface.removeColumn('users', 'street');\n    await queryInterface.removeColumn('users', 'city');\n    await queryInterface.removeColumn('users', 'state');\n  }\n};\n```\n\n## Rollback Strategies\n\n### Transaction-Based Migrations\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    const transaction = await queryInterface.sequelize.transaction();\n\n    try {\n      await queryInterface.addColumn(\n        'users',\n        'verified',\n        { type: Sequelize.BOOLEAN, defaultValue: false },\n        { transaction }\n      );\n\n      await queryInterface.sequelize.query(\n        'UPDATE users SET verified = true WHERE email_verified_at IS NOT NULL',\n        { transaction }\n      );\n\n      await transaction.commit();\n    } catch (error) {\n      await transaction.rollback();\n      throw error;\n    }\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'verified');\n  }\n};\n```\n\n### Checkpoint-Based Rollback\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F Create backup table\n    await queryInterface.sequelize.query(\n      'CREATE TABLE users_backup AS SELECT * FROM users'\n    );\n\n    try {\n      \u002F\u002F Perform migration\n      await queryInterface.addColumn('users', 'new_field', {\n        type: Sequelize.STRING\n      });\n\n      \u002F\u002F Verify migration\n      const [result] = await queryInterface.sequelize.query(\n        \"SELECT COUNT(*) as count FROM users WHERE new_field IS NULL\"\n      );\n\n      if (result[0].count > 0) {\n        throw new Error('Migration verification failed');\n      }\n\n      \u002F\u002F Drop backup\n      await queryInterface.dropTable('users_backup');\n    } catch (error) {\n      \u002F\u002F Restore from backup\n      await queryInterface.sequelize.query('DROP TABLE users');\n      await queryInterface.sequelize.query(\n        'CREATE TABLE users AS SELECT * FROM users_backup'\n      );\n      await queryInterface.dropTable('users_backup');\n      throw error;\n    }\n  }\n};\n```\n\n## Zero-Downtime Migrations\n\n### Blue-Green Deployment Strategy\n```javascript\n\u002F\u002F Phase 1: Make changes backward compatible\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F Add new column (both old and new code can work)\n    await queryInterface.addColumn('users', 'email_new', {\n      type: Sequelize.STRING\n    });\n  }\n};\n\n\u002F\u002F Phase 2: Deploy code that writes to both columns\n\n\u002F\u002F Phase 3: Backfill data\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET email_new = email\n      WHERE email_new IS NULL\n    `);\n  }\n};\n\n\u002F\u002F Phase 4: Deploy code that reads from new column\n\n\u002F\u002F Phase 5: Remove old column\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'email');\n  }\n};\n```\n\n## Cross-Database Migrations\n\n### PostgreSQL to MySQL\n```javascript\n\u002F\u002F Handle differences\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    const dialectName = queryInterface.sequelize.getDialect();\n\n    if (dialectName === 'mysql') {\n      await queryInterface.createTable('users', {\n        id: {\n          type: Sequelize.INTEGER,\n          primaryKey: true,\n          autoIncrement: true\n        },\n        data: {\n          type: Sequelize.JSON  \u002F\u002F MySQL JSON type\n        }\n      });\n    } else if (dialectName === 'postgres') {\n      await queryInterface.createTable('users', {\n        id: {\n          type: Sequelize.INTEGER,\n          primaryKey: true,\n          autoIncrement: true\n        },\n        data: {\n          type: Sequelize.JSONB  \u002F\u002F PostgreSQL JSONB type\n        }\n      });\n    }\n  }\n};\n```\n\n## Resources\n\n- **references\u002Form-switching.md**: ORM migration guides\n- **references\u002Fschema-migration.md**: Schema transformation patterns\n- **references\u002Fdata-transformation.md**: Data migration scripts\n- **references\u002Frollback-strategies.md**: Rollback procedures\n- **assets\u002Fschema-migration-template.sql**: SQL migration templates\n- **assets\u002Fdata-migration-script.py**: Data migration utilities\n- **scripts\u002Ftest-migration.sh**: Migration testing script\n\n## Best Practices\n\n1. **Always Provide Rollback**: Every up() needs a down()\n2. **Test Migrations**: Test on staging first\n3. **Use Transactions**: Atomic migrations when possible\n4. **Backup First**: Always backup before migration\n5. **Small Changes**: Break into small, incremental steps\n6. **Monitor**: Watch for errors during deployment\n7. **Document**: Explain why and how\n8. **Idempotent**: Migrations should be rerunnable\n\n## Common Pitfalls\n\n- Not testing rollback procedures\n- Making breaking changes without downtime strategy\n- Forgetting to handle NULL values\n- Not considering index performance\n- Ignoring foreign key constraints\n- Migrating too much data at once\n","# Database Migration\n\nMaster database schema and data migrations across ORMs (Sequelize, TypeORM, Prisma), including rollback strategies and zero-downtime deployments.\n\n## Do not use this skill when\n\n- The task is unrelated to database migration\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Migrating between different ORMs\n- Performing schema transformations\n- Moving data between databases\n- Implementing rollback procedures\n- Zero-downtime deployments\n- Database version upgrades\n- Data model refactoring\n\n## ORM Migrations\n\n### Sequelize Migrations\n```javascript\n\u002F\u002F migrations\u002F20231201-create-users.js\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.createTable('users', {\n      id: {\n        type: Sequelize.INTEGER,\n        primaryKey: true,\n        autoIncrement: true\n      },\n      email: {\n        type: Sequelize.STRING,\n        unique: true,\n        allowNull: false\n      },\n      createdAt: Sequelize.DATE,\n      updatedAt: Sequelize.DATE\n    });\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.dropTable('users');\n  }\n};\n\n\u002F\u002F Run: npx sequelize-cli db:migrate\n\u002F\u002F Rollback: npx sequelize-cli db:migrate:undo\n```\n\n### TypeORM Migrations\n```typescript\n\u002F\u002F migrations\u002F1701234567-CreateUsers.ts\nimport { MigrationInterface, QueryRunner, Table } from 'typeorm';\n\nexport class CreateUsers1701234567 implements MigrationInterface {\n  public async up(queryRunner: QueryRunner): Promise\u003Cvoid> {\n    await queryRunner.createTable(\n      new Table({\n        name: 'users',\n        columns: [\n          {\n            name: 'id',\n            type: 'int',\n            isPrimary: true,\n            isGenerated: true,\n            generationStrategy: 'increment'\n          },\n          {\n            name: 'email',\n            type: 'varchar',\n            isUnique: true\n          },\n          {\n            name: 'created_at',\n            type: 'timestamp',\n            default: 'CURRENT_TIMESTAMP'\n          }\n        ]\n      })\n    );\n  }\n\n  public async down(queryRunner: QueryRunner): Promise\u003Cvoid> {\n    await queryRunner.dropTable('users');\n  }\n}\n\n\u002F\u002F Run: npm run typeorm migration:run\n\u002F\u002F Rollback: npm run typeorm migration:revert\n```\n\n### Prisma Migrations\n```prisma\n\u002F\u002F schema.prisma\nmodel User {\n  id        Int      @id @default(autoincrement())\n  email     String   @unique\n  createdAt DateTime @default(now())\n}\n\n\u002F\u002F Generate migration: npx prisma migrate dev --name create_users\n\u002F\u002F Apply: npx prisma migrate deploy\n```\n\n## Schema Transformations\n\n### Adding Columns with Defaults\n```javascript\n\u002F\u002F Safe migration: add column with default\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'status', {\n      type: Sequelize.STRING,\n      defaultValue: 'active',\n      allowNull: false\n    });\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'status');\n  }\n};\n```\n\n### Renaming Columns (Zero Downtime)\n```javascript\n\u002F\u002F Step 1: Add new column\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'full_name', {\n      type: Sequelize.STRING\n    });\n\n    \u002F\u002F Copy data from old column\n    await queryInterface.sequelize.query(\n      'UPDATE users SET full_name = name'\n    );\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'full_name');\n  }\n};\n\n\u002F\u002F Step 2: Update application to use new column\n\n\u002F\u002F Step 3: Remove old column\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'name');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.addColumn('users', 'name', {\n      type: Sequelize.STRING\n    });\n  }\n};\n```\n\n### Changing Column Types\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F For large tables, use multi-step approach\n\n    \u002F\u002F 1. Add new column\n    await queryInterface.addColumn('users', 'age_new', {\n      type: Sequelize.INTEGER\n    });\n\n    \u002F\u002F 2. Copy and transform data\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET age_new = CAST(age AS INTEGER)\n      WHERE age IS NOT NULL\n    `);\n\n    \u002F\u002F 3. Drop old column\n    await queryInterface.removeColumn('users', 'age');\n\n    \u002F\u002F 4. Rename new column\n    await queryInterface.renameColumn('users', 'age_new', 'age');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    await queryInterface.changeColumn('users', 'age', {\n      type: Sequelize.STRING\n    });\n  }\n};\n```\n\n## Data Transformations\n\n### Complex Data Migration\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F Get all records\n    const [users] = await queryInterface.sequelize.query(\n      'SELECT id, address_string FROM users'\n    );\n\n    \u002F\u002F Transform each record\n    for (const user of users) {\n      const addressParts = user.address_string.split(',');\n\n      await queryInterface.sequelize.query(\n        `UPDATE users\n         SET street = :street,\n             city = :city,\n             state = :state\n         WHERE id = :id`,\n        {\n          replacements: {\n            id: user.id,\n            street: addressParts[0]?.trim(),\n            city: addressParts[1]?.trim(),\n            state: addressParts[2]?.trim()\n          }\n        }\n      );\n    }\n\n    \u002F\u002F Drop old column\n    await queryInterface.removeColumn('users', 'address_string');\n  },\n\n  down: async (queryInterface, Sequelize) => {\n    \u002F\u002F Reconstruct original column\n    await queryInterface.addColumn('users', 'address_string', {\n      type: Sequelize.STRING\n    });\n\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET address_string = CONCAT(street, ', ', city, ', ', state)\n    `);\n\n    await queryInterface.removeColumn('users', 'street');\n    await queryInterface.removeColumn('users', 'city');\n    await queryInterface.removeColumn('users', 'state');\n  }\n};\n```\n\n## Rollback Strategies\n\n### Transaction-Based Migrations\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    const transaction = await queryInterface.sequelize.transaction();\n\n    try {\n      await queryInterface.addColumn(\n        'users',\n        'verified',\n        { type: Sequelize.BOOLEAN, defaultValue: false },\n        { transaction }\n      );\n\n      await queryInterface.sequelize.query(\n        'UPDATE users SET verified = true WHERE email_verified_at IS NOT NULL',\n        { transaction }\n      );\n\n      await transaction.commit();\n    } catch (error) {\n      await transaction.rollback();\n      throw error;\n    }\n  },\n\n  down: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'verified');\n  }\n};\n```\n\n### Checkpoint-Based Rollback\n```javascript\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F Create backup table\n    await queryInterface.sequelize.query(\n      'CREATE TABLE users_backup AS SELECT * FROM users'\n    );\n\n    try {\n      \u002F\u002F Perform migration\n      await queryInterface.addColumn('users', 'new_field', {\n        type: Sequelize.STRING\n      });\n\n      \u002F\u002F Verify migration\n      const [result] = await queryInterface.sequelize.query(\n        \"SELECT COUNT(*) as count FROM users WHERE new_field IS NULL\"\n      );\n\n      if (result[0].count > 0) {\n        throw new Error('Migration verification failed');\n      }\n\n      \u002F\u002F Drop backup\n      await queryInterface.dropTable('users_backup');\n    } catch (error) {\n      \u002F\u002F Restore from backup\n      await queryInterface.sequelize.query('DROP TABLE users');\n      await queryInterface.sequelize.query(\n        'CREATE TABLE users AS SELECT * FROM users_backup'\n      );\n      await queryInterface.dropTable('users_backup');\n      throw error;\n    }\n  }\n};\n```\n\n## Zero-Downtime Migrations\n\n### Blue-Green Deployment Strategy\n```javascript\n\u002F\u002F Phase 1: Make changes backward compatible\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    \u002F\u002F Add new column (both old and new code can work)\n    await queryInterface.addColumn('users', 'email_new', {\n      type: Sequelize.STRING\n    });\n  }\n};\n\n\u002F\u002F Phase 2: Deploy code that writes to both columns\n\n\u002F\u002F Phase 3: Backfill data\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.sequelize.query(`\n      UPDATE users\n      SET email_new = email\n      WHERE email_new IS NULL\n    `);\n  }\n};\n\n\u002F\u002F Phase 4: Deploy code that reads from new column\n\n\u002F\u002F Phase 5: Remove old column\nmodule.exports = {\n  up: async (queryInterface) => {\n    await queryInterface.removeColumn('users', 'email');\n  }\n};\n```\n\n## Cross-Database Migrations\n\n### PostgreSQL to MySQL\n```javascript\n\u002F\u002F Handle differences\nmodule.exports = {\n  up: async (queryInterface, Sequelize) => {\n    const dialectName = queryInterface.sequelize.getDialect();\n\n    if (dialectName === 'mysql') {\n      await queryInterface.createTable('users', {\n        id: {\n          type: Sequelize.INTEGER,\n          primaryKey: true,\n          autoIncrement: true\n        },\n        data: {\n          type: Sequelize.JSON  \u002F\u002F MySQL JSON type\n        }\n      });\n    } else if (dialectName === 'postgres') {\n      await queryInterface.createTable('users', {\n        id: {\n          type: Sequelize.INTEGER,\n          primaryKey: true,\n          autoIncrement: true\n        },\n        data: {\n          type: Sequelize.JSONB  \u002F\u002F PostgreSQL JSONB type\n        }\n      });\n    }\n  }\n};\n```\n\n## Resources\n\n- **references\u002Form-switching.md**: ORM migration guides\n- **references\u002Fschema-migration.md**: Schema transformation patterns\n- **references\u002Fdata-transformation.md**: Data migration scripts\n- **references\u002Frollback-strategies.md**: Rollback procedures\n- **assets\u002Fschema-migration-template.sql**: SQL migration templates\n- **assets\u002Fdata-migration-script.py**: Data migration utilities\n- **scripts\u002Ftest-migration.sh**: Migration testing script\n\n## Best Practices\n\n1. **Always Provide Rollback**: Every up() needs a down()\n2. **Test Migrations**: Test on staging first\n3. **Use Transactions**: Atomic migrations when possible\n4. **Backup First**: Always backup before migration\n5. **Small Changes**: Break into small, incremental steps\n6. **Monitor**: Watch for errors during deployment\n7. **Document**: Explain why and how\n8. **Idempotent**: Migrations should be rerunnable\n\n## Common Pitfalls\n\n- Not testing rollback procedures\n- Making breaking changes without downtime strategy\n- Forgetting to handle NULL values\n- Not considering index performance\n- Ignoring foreign key constraints\n- Migrating too much data at once\n",{"name":5,"risk":24,"source":25,"date_added":26,"description":7},"unknown","community","2026-02-27","main","51493f354fd03e3f941d4df7fd64c0b8c7a2632d","skills\u002Fdatabase\u002Fdatabase-migration","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi","漏洞研究、根因分析、黑箱測試｜做 AI agent 工具｜Vulnerability research, root-cause analysis, AI agent tooling","2026-08-16 02:24:07",{"source":8,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add GongYuanCaiJi\u002Fdsh-claude-code-templates --skill database-migration",{"tool":40,"command":41},"bunx","bunx skills add GongYuanCaiJi\u002Fdsh-claude-code-templates --skill database-migration",{"tool":43,"command":44},"pnpm","pnpm dlx skills add GongYuanCaiJi\u002Fdsh-claude-code-templates --skill database-migration","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fdatabase\u002Fdatabase-migration\u002FSKILL.md",true,[],[49,56,65,72,79,86],{"skillNo":50,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":53,"categories":54,"keywords":55,"publishedAt":19},"01M7ARMYTZ5D4B7N5SKFXV345V","zapier-make-patterns","No-code automation democratizes workflow building. Zapier and Make (formerly Integromat) let non-developers automate business processes without writing code. But no-code doesn't mean no-complexity - these platforms have their own patterns, pitfalls, and breaking points.  This skill covers when to use which platform, how to build reliable automations, and when to graduate to code-based solutions. Key insight: Zapier optimizes for simplicity and integrations (7000+ apps), Make optimizes for power","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Fzapier-make-patterns\u002FSKILL.md",[],[],{"skillNo":57,"name":58,"nameZh":6,"description":59,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":60,"licenseFileUrl":61,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M7ARMX1BVNEAR98SBANMDF2V","yeet","Use only when the user explicitly asks to stage, commit, push, and open a GitHub pull request in one flow using the GitHub CLI (`gh`).","Apache-2.0","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Fyeet\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Fyeet\u002FSKILL.md",[],[],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":71,"publishedAt":19},"01M7ARMPR4RQ417MG1HMPGNQHH","workflow-automation","Workflow automation is the infrastructure that makes AI agents reliable. Without durable execution, a network hiccup during a 10-step payment flow means lost money and angry customers. With it, workflows resume exactly where they left off.  This skill covers the platforms (n8n, Temporal, Inngest) and patterns (sequential, parallel, orchestrator-worker) that turn brittle scripts into production-grade automation.  Key insight: The platforms make different tradeoffs. n8n optimizes for accessibility","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Fworkflow-automation\u002FSKILL.md",[],[],{"skillNo":73,"name":74,"nameZh":6,"description":75,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":19},"01M7ARMHBERDMKGDMV7K6MQ6YP","trigger-dev","Trigger.dev expert for background jobs, AI workflows, and reliable async execution with excellent developer experience and TypeScript-first design. Use when: trigger.dev, trigger dev, background task, ai background job, long running task.","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Ftrigger-dev\u002FSKILL.md",[],[],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":19},"01M7ARME0A7KFT330Q2H25HE2B","slack-automation","Automate Slack workspace operations including messaging, search, channel management, and reaction workflows through Composio's Slack toolkit.","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Fslack-automation\u002FSKILL.md",[],[],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":19},"01M7ARM8D87V18WDG0GEZS11ZT","planning-with-files","Transforms workflow to use Manus-style persistent markdown files for planning, progress tracking, and knowledge storage. Use when starting complex tasks, multi-step projects, research tasks, or when the user mentions planning, organizing work, tracking progress, or wants structured output.","https:\u002F\u002Fgithub.com\u002FGongYuanCaiJi\u002Fdsh-claude-code-templates\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-automation\u002Fplanning-with-files\u002FSKILL.md",[],[]]