{"_id":"@ederzadravec/firestore-migrations","_rev":"3-9119762c6c6bd1b13fb84aadc3b2cbf5","name":"@ederzadravec/firestore-migrations","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.1":{"name":"@ederzadravec/firestore-migrations","version":"1.0.1","keywords":["firestore","migrations","firebase","database","schema","versioning","rollback","cli"],"author":{"name":"Eder Zadravec","email":"ederzadravec@gmail.com"},"license":"MIT","_id":"@ederzadravec/firestore-migrations@1.0.1","maintainers":[{"name":"ezadravec","email":"ederzadravec@gmail.com"}],"homepage":"https://github.com/ederzadravec/firestore-migrations#readme","bugs":{"url":"https://github.com/ederzadravec/firestore-migrations/issues"},"bin":{"firestore-migrations":"dist/cli/index.js"},"dist":{"shasum":"c015a50ed6fa35008ec972f5a19d5819b371d13d","tarball":"https://registry.npmjs.org/@ederzadravec/firestore-migrations/-/firestore-migrations-1.0.1.tgz","fileCount":23,"integrity":"sha512-Z3v0E75q5NvAaA+3Q/XpciVCU9kHcyXHpxcuVPjDwIlGTCMBjgHlL0on8fnri7VKhKDvIlGa2ggkKRiSm58VcA==","signatures":[{"sig":"MEYCIQDUMPnaE+2tpBFV1tkNLGsY6djK7x0DRsWmdQUboKwOxgIhAOzbpFT6m21bA0pFpG/Acbk7bb2TIbg+odcglpFklsoQ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101107},"main":"index.ts","types":"index.ts","engines":{"node":">=18.0.0"},"gitHead":"a238a20ac07fd8689e6ec9768d627c8566036aa8","scripts":{"dev":"ts-node cli/index.ts","test":"jest","build":"tsc","dev:up":"ts-node cli/index.ts up","prepare":"npm run build","dev:down":"ts-node cli/index.ts down","dev:init":"ts-node cli/index.ts init","test:unit":"jest --testMatch='**/unit/**/*.test.ts'","dev:create":"ts-node cli/index.ts create migration","dev:status":"ts-node cli/index.ts status","test:local":"cd test-project && npx ts-node ../cli/index.ts","test:watch":"jest --watch","test:coverage":"jest --coverage","test:integration":"jest --testMatch='**/integration/**/*.test.ts'"},"_npmUser":{"name":"ezadravec","email":"ederzadravec@gmail.com"},"repository":{"url":"git+https://github.com/ederzadravec/firestore-migrations.git","type":"git"},"_npmVersion":"11.6.2","description":"Sistema de migrations para Firestore - Framework agnostic e reutilizável","directories":{},"_nodeVersion":"22.17.1","dependencies":{"firebase-admin":"^13.6.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","ts-jest":"^29.4.5","ts-node":"^10.9.0","typescript":"^5.0.0","@types/jest":"^29.5.14","@types/node":"^20.19.25"},"peerDependencies":{"typescript":">=4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/firestore-migrations_1.0.1_1763749941888_0.7599933381508945","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@ederzadravec/firestore-migrations","version":"1.0.2","keywords":["firestore","migrations","firebase","database","schema","versioning","rollback","cli"],"author":{"name":"Eder Zadravec","email":"ederzadravec@gmail.com"},"license":"MIT","_id":"@ederzadravec/firestore-migrations@1.0.2","maintainers":[{"name":"ezadravec","email":"ederzadravec@gmail.com"}],"homepage":"https://github.com/ederzadravec/firestore-migrations#readme","bugs":{"url":"https://github.com/ederzadravec/firestore-migrations/issues"},"bin":{"firestore-migrations":"dist/cli/index.js"},"dist":{"shasum":"d83495e68b54fe67fe1fb9eb9e8d955e8b33186e","tarball":"https://registry.npmjs.org/@ederzadravec/firestore-migrations/-/firestore-migrations-1.0.2.tgz","fileCount":61,"integrity":"sha512-VliS16uSCK5bqwlPZVpmHnZScsyuMsilLOiXxWDhRAHrVZNqMXcMAveP0QjPoYv5mk/n+Ch3KGMjKyOjn57xSA==","signatures":[{"sig":"MEYCIQDoHJPEXBcTDPT70ZmN3lQReV7k6zryRavvOTkbiPjK0wIhAIOQdMgnWaIm32vNJt1W/p2n/r9vnfpIeXxZ5rL429Po","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":165128},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"dfb07a330e7ba9e5b405e28debba086f250c0080","scripts":{"dev":"ts-node cli/index.ts","test":"jest","build":"tsc","dev:up":"ts-node cli/index.ts up","prepare":"npm run build","dev:down":"ts-node cli/index.ts down","dev:init":"ts-node cli/index.ts init","test:unit":"jest --testMatch='**/unit/**/*.test.ts'","dev:create":"ts-node cli/index.ts create migration","dev:status":"ts-node cli/index.ts status","test:local":"cd test-project && npx ts-node ../cli/index.ts","test:watch":"jest --watch","test:coverage":"jest --coverage","test:integration":"jest --testMatch='**/integration/**/*.test.ts'"},"_npmUser":{"name":"ezadravec","email":"ederzadravec@gmail.com"},"repository":{"url":"git+https://github.com/ederzadravec/firestore-migrations.git","type":"git"},"_npmVersion":"11.6.2","description":"Sistema de migrations para Firestore - Framework agnostic e reutilizável","directories":{},"_nodeVersion":"22.17.1","dependencies":{"firebase-admin":"^13.6.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","ts-jest":"^29.4.5","ts-node":"^10.9.0","typescript":"^5.0.0","@types/jest":"^29.5.14","@types/node":"^20.19.25"},"peerDependencies":{"typescript":">=4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/firestore-migrations_1.0.2_1763750233063_0.546818982421972","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@ederzadravec/firestore-migrations","version":"1.1.0","description":"Sistema de migrations para Firestore - Framework agnostic e reutilizável","main":"dist/index.js","types":"dist/index.d.ts","bin":{"firestore-migrations":"dist/cli/index.js"},"scripts":{"build":"tsc","dev":"ts-node cli/index.ts","dev:init":"ts-node cli/index.ts init","dev:create":"ts-node cli/index.ts create migration","dev:up":"ts-node cli/index.ts up","dev:down":"ts-node cli/index.ts down","dev:status":"ts-node cli/index.ts status","test:local":"cd test-project && npx ts-node ../cli/index.ts","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","test:integration":"jest --testMatch='**/integration/**/*.test.ts'","test:unit":"jest --testMatch='**/unit/**/*.test.ts'","prepare":"npm run build"},"keywords":["firestore","migrations","firebase","database","schema","versioning","rollback","cli"],"author":{"name":"Eder Zadravec","email":"ederzadravec@gmail.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/ederzadravec/firestore-migrations.git"},"engines":{"node":">=18.0.0"},"devDependencies":{"@types/jest":"^29.5.14","@types/node":"^20.19.25","jest":"^29.7.0","ts-jest":"^29.4.5","ts-node":"^10.9.0","typescript":"^5.0.0"},"peerDependencies":{"typescript":">=4.0.0"},"dependencies":{"firebase-admin":"^13.6.0"},"licenseText":"MIT License\n\nCopyright (c) 2025 Eder Zadravec\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","_id":"@ederzadravec/firestore-migrations@1.1.0","dist":{"shasum":"95915717675b66a52b0d6ef67604eb5ab81647a7","integrity":"sha512-WW2fR5YEBXCpS2NfUT4Iiib8ATZijemkXSElU1TPTyz9PF8FAeKLJokZZbdfZwojqGg/bTHfMzg+O2B/FLSXMw==","tarball":"https://registry.npmjs.org/@ederzadravec/firestore-migrations/-/firestore-migrations-1.1.0.tgz","fileCount":82,"unpackedSize":201769,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC9alLLMEuha08I376BPiJRqITnUKWewLC3U32J8y4yWwIhAMLHidRqObt0dRhjM8Yip1SUGUGYremsJSdJJcfSXilF"}]},"_npmUser":{"name":"ezadravec","email":"ederzadravec@gmail.com"},"directories":{},"maintainers":[{"name":"ezadravec","email":"ederzadravec@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/firestore-migrations_1.1.0_1768913194959_0.5707577909588826"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-21T18:32:21.780Z","modified":"2026-01-20T12:46:35.232Z","1.0.1":"2025-11-21T18:32:22.109Z","1.0.2":"2025-11-21T18:37:13.258Z","1.1.0":"2026-01-20T12:46:35.106Z"},"author":{"name":"Eder Zadravec","email":"ederzadravec@gmail.com"},"license":"MIT","keywords":["firestore","migrations","firebase","database","schema","versioning","rollback","cli"],"repository":{"type":"git","url":"git+https://github.com/ederzadravec/firestore-migrations.git"},"description":"Sistema de migrations para Firestore - Framework agnostic e reutilizável","maintainers":[{"name":"ezadravec","email":"ederzadravec@gmail.com"}],"readme":"# 🔥 Firestore Migrations\n\n> Sistema de migrations e seeds para Firestore com **zero configuração** - Funciona como Prisma, TypeORM, Sequelize\n\n[![npm version](https://badge.fury.io/js/@ederzadravec%2Ffirestore-migrations.svg)](https://www.npmjs.com/package/@ederzadravec/firestore-migrations)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## ✨ Por que usar?\n\n- ✅ **Zero Config** - Funciona sem nenhum arquivo de configuração\n- ✅ **Auto-Discovery** - Descobre Firebase e migrations automaticamente\n- ✅ **CLI Simples** - Comandos diretos como `npx firestore-migrations up`\n- ✅ **TypeScript First** - Suporte completo e types incluídos\n- ✅ **Rollback** - Reverta migrations com segurança\n- ✅ **Seeds** - Popule dados iniciais facilmente\n- ✅ **Checksum Validation** - Detecta mudanças em migrations já executadas\n\n## ⚠️ Erro \"Unexpected token '{'?\"\n\nSe você receber este erro ao executar `npx firestore-migrations up`:\n\n```bash\nErro: Unexpected token '{'\nerror Command failed with exit code 1.\n```\n\n**Solução rápida:**\n\n```bash\n# Opção 1: Instalar ts-node (desenvolvimento)\nnpm install --save-dev ts-node\nnpx firestore-migrations up\n\n# Opção 2: Compilar migrations (produção)\nnpx tsc migrations/**/*.ts --outDir migrations --module commonjs\nnpx firestore-migrations up\n```\n\n📖 **[Ver Guia Completo de Solução](./docs/TYPESCRIPT-MIGRATIONS.md)**\n\n## 🚀 Quick Start (3 minutos)\n\n### 1️⃣ Instalar\n\n```bash\nnpm install @ederzadravec/firestore-migrations firebase-admin\n# ou\nyarn add @ederzadravec/firestore-migrations firebase-admin\n```\n\n### 2️⃣ Configurar Firebase (escolha UMA opção)\n\n**Opção A: Variável de ambiente** (mais fácil)\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"./serviceAccountKey.json\"\n```\n\n**Opção B: Arquivo de config** (mais controle)\n\nCrie `firestore-migrations.config.js`:\n\n```javascript\nmodule.exports = {\n  firebase: {\n    serviceAccountPath: './serviceAccountKey.json'\n  }\n}\n```\n\n**Opção C: Application Default Credentials**\n\n```bash\ngcloud auth application-default login\n```\n\n### 3️⃣ Inicializar estrutura\n\n```bash\nnpx firestore-migrations init\n```\n\nIsso cria:\n```\nseu-projeto/\n├── migrations/     ← suas migrations aqui\n└── seeds/         ← seus seeds aqui\n```\n\n### 4️⃣ Criar e executar migration\n\n```bash\n# Criar\nnpx firestore-migrations create migration add-user-email\n\n# Editar migrations/TIMESTAMP_add-user-email.ts\n# Implementar up() e down()\n\n# Executar\nnpx firestore-migrations up\n```\n\n## 🎯 Uso Completo\n\n### Comandos Disponíveis\n\n```bash\n# CRIAR\nnpx firestore-migrations create migration <name>   # Nova migration\nnpx firestore-migrations create seed <name>        # Novo seed\n\n# EXECUTAR\nnpx firestore-migrations up                        # Rodar migrations pendentes\nnpx firestore-migrations down                      # Reverter última migration\nnpx firestore-migrations seed                      # Popular dados (seeds)\n\n# INFORMAÇÃO\nnpx firestore-migrations status                    # Ver status\nnpx firestore-migrations list                      # Listar todas migrations\n```\n\n### ⚡ TypeScript vs JavaScript\n\nAs migrations são criadas em **TypeScript** por padrão. Para executá-las em produção, você tem **3 opções**:\n\n**Opção 1: Usar ts-node (desenvolvimento)** ✅ Recomendado para dev\n\n```bash\nnpm install --save-dev ts-node\nnpx firestore-migrations up\n```\n\n**Opção 2: Compilar migrations (produção)** ✅ Recomendado para produção\n\n```bash\n# Compile suas migrations\nnpx tsc migrations/**/*.ts --outDir migrations --module commonjs\n\n# Execute normalmente\nnpx firestore-migrations up\n```\n\n**Opção 3: Scripts do package.json**\n\n```json\n{\n  \"scripts\": {\n    \"migrate:build\": \"tsc migrations/**/*.ts --outDir migrations --module commonjs\",\n    \"migrate:up\": \"npm run migrate:build && firestore-migrations up\",\n    \"migrate:up:dev\": \"ts-node -r tsconfig-paths/register ./node_modules/.bin/firestore-migrations up\"\n  }\n}\n```\n\n> 💡 O CLI detecta automaticamente se você tem arquivos `.js` ou `.ts` e usa a versão apropriada.  \n> 📖 **Erro \"Unexpected token '{'?\"** Veja o [Guia Completo TypeScript/JavaScript](./docs/TYPESCRIPT-MIGRATIONS.md)\n\n### Scripts no package.json (recomendado)\n\nAdicione ao seu `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"migrate:create\": \"firestore-migrations create migration\",\n    \"migrate:up\": \"firestore-migrations up\",\n    \"migrate:down\": \"firestore-migrations down\",\n    \"migrate:status\": \"firestore-migrations status\",\n    \"seed:create\": \"firestore-migrations create seed\",\n    \"seed:run\": \"firestore-migrations seed\"\n  }\n}\n```\n\nAgora use:\n\n```bash\nyarn migrate:create add-user-role\nyarn migrate:up\nyarn migrate:status\n```\n\n## 📝 Exemplo de Migration\n\nArquivo gerado automaticamente em `migrations/20231121120000_add_user_email.ts`:\n\n```typescript\nimport type { IFirestoreAdapter } from '@ederzadravec/firestore-migrations'\n\nexport const migration = {\n  id: '20231121120000_add_user_email',\n  name: 'add user email',\n  description: 'Adiciona campo email em todos users',\n\n  async up(adapter: IFirestoreAdapter) {\n    console.log('▶️  Adicionando campo email...')\n    \n    const users = await adapter.getItems('users')\n    \n    for (const user of users) {\n      await adapter.updateItemById('users', user.id, {\n        email: user.email || `${user.username}@example.com`,\n        emailVerified: false\n      })\n    }\n    \n    console.log(`✅ ${users.length} usuários atualizados`)\n  },\n\n  async down(adapter: IFirestoreAdapter) {\n    console.log('◀️  Removendo campo email...')\n    \n    const users = await adapter.getItems('users')\n    \n    for (const user of users) {\n      await adapter.deleteItemProperty('users', user.id, 'email')\n      await adapter.deleteItemProperty('users', user.id, 'emailVerified')\n    }\n    \n    console.log('✅ Rollback completo')\n  }\n}\n\nexport default migration\n```\n\n## 🌱 Exemplo de Seed\n\nArquivo gerado automaticamente em `seeds/20231121120000_initial_users.ts`:\n\n```typescript\nimport type { IFirestoreAdapter } from '@ederzadravec/firestore-migrations'\n\nexport const seed = {\n  id: '20231121120000_initial_users',\n  name: 'initial users',\n  description: 'Cria usuários iniciais do sistema',\n  environments: ['all'], // 'all' para todos ambientes, ou ['development', 'production']\n\n  async run(adapter: IFirestoreAdapter) {\n    console.log('🌱 Criando usuários iniciais...')\n    \n    await adapter.createItemWithId('users', 'admin', {\n      name: 'Admin User',\n      email: 'admin@example.com',\n      role: 'admin',\n      createdAt: new Date()\n    })\n    \n    await adapter.createItemWithId('users', 'guest', {\n      name: 'Guest User',\n      email: 'guest@example.com',\n      role: 'guest',\n      createdAt: new Date()\n    })\n    \n    console.log('✅ 2 usuários criados')\n  },\n\n  async validate() {\n    // Opcional: validações antes de executar\n    return true\n  }\n}\n\nexport default seed\n```\n\n> 💡 **Campo `environments`**: Use `['all']` para executar em todos ambientes, ou especifique ambientes como `['development']`, `['production']`, ou `['development', 'staging']`.\n\n## ⚙️ Configuração (Opcional)\n\nA biblioteca funciona **sem configuração**, mas você pode customizar criando `firestore-migrations.config.js`:\n\n```javascript\nmodule.exports = {\n  // Pasta de migrations (padrão: './migrations')\n  migrationsPath: './database/migrations',\n  \n  // Pasta de seeds (padrão: './seeds')\n  seedsPath: './database/seeds',\n  \n  // Collection de controle (padrão: '_migrations')\n  migrationsCollection: '_migrations',\n  \n  // Firebase config (opcional - auto-discovery se não fornecido)\n  firebase: {\n    // Opção 1: Path para service account\n    serviceAccountPath: './config/firebase-adminsdk.json',\n    \n    // Opção 2: Service account object\n    // serviceAccount: require('./serviceAccountKey.json'),\n  }\n}\n```\n\n## 🔐 Credenciais Firebase\n\nA biblioteca **descobre automaticamente** suas credenciais Firebase nesta ordem:\n\n1. ✅ Se Firebase já está inicializado → usa instância existente\n2. ✅ Se tem `firebase.serviceAccountPath` no config → carrega e usa\n3. ✅ Se tem `GOOGLE_APPLICATION_CREDENTIALS` env var → usa\n4. ✅ Application Default Credentials (gcloud auth)\n\n**Você não precisa fazer nada!** Apenas garanta que uma dessas opções está configurada.\n\n### Exemplo: Service Account\n\n1. Baixe service account do Firebase Console\n2. Salve como `serviceAccountKey.json` na raiz do projeto\n3. Configure env var:\n\n```bash\n# .env\nGOOGLE_APPLICATION_CREDENTIALS=./serviceAccountKey.json\n```\n\n4. Adicione ao `.gitignore`:\n\n```\nserviceAccountKey.json\n.env\n```\n\nPronto! A lib vai descobrir e usar automaticamente.\n\n## 📚 API do Adapter\n\nTodas migrations e seeds recebem um `adapter` com estes métodos:\n\n```typescript\n// Tipos de filtros suportados\ntype FirestoreFilterOperator =\n  | '==' | '!=' | '<' | '<=' | '>' | '>='\n  | 'array-contains' | 'array-contains-any' | 'in' | 'not-in'\n\ninterface IFirestoreFilter {\n  field: string\n  operator: FirestoreFilterOperator\n  value: any\n}\n\ninterface IQueryOptions {\n  filters?: IFirestoreFilter[]\n  limit?: number\n  orderBy?: { field: string; direction?: 'asc' | 'desc' }\n}\n\ninterface IFirestoreAdapter {\n  // Buscar\n  getItems<T>(collection: string, options?: IQueryOptions): Promise<T[]>\n  getItemById<T>(collection: string, id: string): Promise<T>\n\n  // Criar\n  createItemWithId(collection: string, id: string, data: any): Promise<string>\n\n  // Atualizar\n  updateItemById(collection: string, id: string, data: any): Promise<void>\n  updateItems(collection: string, data: any, options: IQueryOptions): Promise<number>\n\n  // Deletar\n  deleteItemById(collection: string, id: string): Promise<any>\n  deleteItems(collection: string, options: IQueryOptions): Promise<number>\n}\n```\n\n### Exemplos de uso com filtros\n\n```typescript\n// Buscar usuários ativos maiores de 18 anos\nconst users = await adapter.getItems('users', {\n  filters: [\n    { field: 'status', operator: '==', value: 'active' },\n    { field: 'age', operator: '>=', value: 18 }\n  ],\n  orderBy: { field: 'createdAt', direction: 'desc' },\n  limit: 100\n})\n\n// Atualizar múltiplos documentos de uma vez\nconst updatedCount = await adapter.updateItems(\n  'users',\n  { notifiedAt: new Date() },\n  { filters: [{ field: 'status', operator: '==', value: 'active' }] }\n)\nconsole.log(`${updatedCount} usuários atualizados`)\n\n// Deletar documentos expirados\nconst deletedCount = await adapter.deleteItems('sessions', {\n  filters: [{ field: 'expiresAt', operator: '<', value: new Date() }]\n})\nconsole.log(`${deletedCount} sessões removidas`)\n```\n\n## 🎓 Casos de Uso\n\n### Adicionar campo em documentos existentes (bulk)\n\n```typescript\nasync up(adapter) {\n  // Usando updateItems para atualizar em lote (mais eficiente)\n  const count = await adapter.updateItems(\n    'users',\n    { status: 'active', updatedAt: new Date() },\n    { filters: [] } // filtros vazios = todos os documentos\n  )\n  console.log(`${count} usuários atualizados`)\n}\n```\n\n### Adicionar campo apenas em documentos específicos\n\n```typescript\nasync up(adapter) {\n  // Atualiza apenas usuários pendentes\n  const count = await adapter.updateItems(\n    'users',\n    { status: 'active', updatedAt: new Date() },\n    { filters: [{ field: 'status', operator: '==', value: 'pending' }] }\n  )\n  console.log(`${count} usuários pendentes atualizados`)\n}\n```\n\n### Migrar dados entre collections\n\n```typescript\nasync up(adapter) {\n  const oldUsers = await adapter.getItems('users_old')\n\n  for (const user of oldUsers) {\n    await adapter.createItemWithId('users', user.id, {\n      name: user.full_name,  // rename\n      email: user.email,\n      active: user.status === 'enabled'  // transform\n    })\n  }\n}\n```\n\n### Criar estrutura inicial\n\n```typescript\nasync up(adapter) {\n  await adapter.createItemWithId('settings', 'app', {\n    version: '1.0.0',\n    maintenanceMode: false,\n    features: {\n      auth: true,\n      payments: false\n    }\n  })\n}\n```\n\n### Limpar dados antigos\n\n```typescript\nasync up(adapter) {\n  // Remove todas as sessões expiradas\n  const deleted = await adapter.deleteItems('sessions', {\n    filters: [{ field: 'expiresAt', operator: '<', value: new Date() }]\n  })\n  console.log(`${deleted} sessões expiradas removidas`)\n}\n```\n\n### Buscar e processar com filtros complexos\n\n```typescript\nasync up(adapter) {\n  // Busca usuários premium inativos há mais de 30 dias\n  const thirtyDaysAgo = new Date()\n  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)\n\n  const inactiveUsers = await adapter.getItems('users', {\n    filters: [\n      { field: 'plan', operator: '==', value: 'premium' },\n      { field: 'lastLogin', operator: '<', value: thirtyDaysAgo }\n    ],\n    orderBy: { field: 'lastLogin', direction: 'asc' }\n  })\n\n  // Processa cada usuário\n  for (const user of inactiveUsers) {\n    await adapter.updateItemById('users', user.id, {\n      status: 'inactive',\n      inactiveSince: new Date()\n    })\n  }\n}\n```\n\n## 🛡️ Segurança\n\n- ✅ **Checksum Validation** - Detecta alterações em migrations já executadas\n- ✅ **Transaction Support** - Opera\\u00e7\\u00f5es atômicas quando possível\n- ✅ **Rollback** - Sempre implemente `down()` para reverter\n- ✅ **Dry-run** - Teste com `validate()` antes de executar\n\n## 🤝 Contribuindo\n\nContribuições são bem-vindas! Veja [CONTRIBUTING.md](./CONTRIBUTING.md)\n\n### Testando Localmente\n\n```bash\n# Setup rápido\n./dev-setup.sh\n\n# Testar comandos\ncd test-project\nnpx ts-node ../cli/index.ts init\nnpx ts-node ../cli/index.ts create migration test\nnpx ts-node ../cli/index.ts list\n```\n\nVer [DEVELOPMENT.md](./DEVELOPMENT.md) para mais opções de teste.\n\n## 🧪 Testes\n\nA biblioteca possui uma suíte completa de testes automatizados com Jest:\n\n```bash\n# Rodar todos os testes\nnpm test\n\n# Testes com cobertura\nnpm run test:coverage\n\n# Rodar testes específicos\nnpm test -- tests/unit/MigrationService.test.ts\n\n# Watch mode para desenvolvimento\nnpm run test:watch\n```\n\n### Cobertura de Testes\n\n- ✅ **22 testes** passando\n- ✅ **57% de cobertura** geral\n- ✅ Testes unitários para `MigrationService` (70% cobertura)\n- ✅ Testes unitários para `MockFirestoreAdapter` (100% cobertura)\n- ✅ Testes de integração para `ConfigLoader`\n- ✅ Mock completo do Firestore para testes rápidos\n\nVer [TESTING.md](./TESTING.md) para guia completo de testes.\n\n## 📄 Licença\n\nMIT © [Eder Zadravec](https://github.com/ederzadravec)\n\n## 🔗 Links\n\n- [GitHub](https://github.com/ederzadravec/firestore-migrations)\n- [npm](https://www.npmjs.com/package/@ederzadravec/firestore-migrations)\n- [Issues](https://github.com/ederzadravec/firestore-migrations/issues)\n\n","readmeFilename":"README.md"}