@luanpdd/kit-mcp 1.29.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +168 -168
- package/gates/agent-no-recursive-dispatch.md +82 -82
- package/kit/COMANDOS.md +138 -138
- package/kit/README.md +76 -76
- package/kit/agents/advisor-researcher.md +106 -106
- package/kit/agents/assumptions-analyzer.md +107 -107
- package/kit/agents/audit-log-implementer.md +313 -313
- package/kit/agents/auditor-consistencia-isolamento.md +413 -413
- package/kit/agents/b2b-saas-architect.md +156 -156
- package/kit/agents/cascading-failures-auditor.md +298 -298
- package/kit/agents/codebase-mapper.md +768 -768
- package/kit/agents/crm-pipeline-implementer.md +256 -256
- package/kit/agents/debugger.md +813 -813
- package/kit/agents/detector-tenant-quente.md +337 -337
- package/kit/agents/evolution-go-integrator.md +200 -200
- package/kit/agents/example-reviewer.md +21 -21
- package/kit/agents/executor.md +564 -564
- package/kit/agents/integration-checker.md +200 -200
- package/kit/agents/invite-flow-implementer.md +189 -189
- package/kit/agents/legacy-characterizer.md +368 -368
- package/kit/agents/lgpd-compliance-auditor.md +295 -295
- package/kit/agents/multi-tenant-isolation-auditor.md +253 -253
- package/kit/agents/multi-tenant-rls-writer.md +340 -340
- package/kit/agents/nyquist-auditor.md +178 -178
- package/kit/agents/observability-coverage-auditor.md +315 -315
- package/kit/agents/org-onboarding-implementer.md +223 -223
- package/kit/agents/payload-capture-instrumenter.md +273 -273
- package/kit/agents/phase-researcher.md +696 -696
- package/kit/agents/plan-checker.md +272 -272
- package/kit/agents/planner.md +922 -922
- package/kit/agents/project-researcher.md +652 -652
- package/kit/agents/refactor-safety-auditor.md +404 -404
- package/kit/agents/research-synthesizer.md +245 -245
- package/kit/agents/roadmapper.md +677 -677
- package/kit/agents/seam-finder.md +359 -359
- package/kit/agents/shotgun-surgery-detector.md +349 -349
- package/kit/agents/supabase-branching-architect.md +562 -562
- package/kit/agents/supabase-cicd-pipeline-implementer.md +777 -777
- package/kit/agents/supabase-column-privileges-writer.md +399 -399
- package/kit/agents/supabase-edge-fn-tester.md +287 -0
- package/kit/agents/supabase-edge-fn-writer.md +239 -210
- package/kit/agents/supabase-migration-writer.md +385 -385
- package/kit/agents/supabase-rbac-implementer.md +392 -392
- package/kit/agents/supabase-realtime-implementer.md +363 -267
- package/kit/agents/supabase-rls-hardener.md +521 -521
- package/kit/agents/supabase-rls-writer.md +323 -323
- package/kit/agents/supabase-roles-implementer.md +355 -355
- package/kit/agents/super-admin-implementer.md +281 -281
- package/kit/agents/ui-auditor.md +437 -437
- package/kit/agents/ui-checker.md +302 -302
- package/kit/agents/ui-researcher.md +355 -355
- package/kit/agents/user-profiler.md +175 -175
- package/kit/agents/validador-evolucao-schema.md +335 -335
- package/kit/agents/verifier.md +728 -728
- package/kit/commands/adicionar-backlog.md +75 -75
- package/kit/commands/adicionar-fase.md +42 -42
- package/kit/commands/adicionar-tarefa.md +45 -45
- package/kit/commands/adicionar-testes.md +41 -41
- package/kit/commands/ajuda.md +21 -21
- package/kit/commands/atualizar.md +37 -37
- package/kit/commands/auditar-cascading.md +111 -111
- package/kit/commands/auditar-marco.md +179 -179
- package/kit/commands/auditar-observabilidade-cobertura.md +183 -183
- package/kit/commands/auditar-refactor.md +219 -219
- package/kit/commands/auditar-release.md +109 -109
- package/kit/commands/auditar-uat.md +23 -23
- package/kit/commands/autonomo.md +40 -40
- package/kit/commands/branch-pr.md +24 -24
- package/kit/commands/burn-rate-status.md +408 -408
- package/kit/commands/capturar-payloads.md +193 -193
- package/kit/commands/caracterizar.md +212 -212
- package/kit/commands/concluir-marco.md +247 -247
- package/kit/commands/configuracoes.md +36 -36
- package/kit/commands/dados-distribuidos.md +188 -188
- package/kit/commands/definir-perfil.md +10 -10
- package/kit/commands/depurar.md +190 -190
- package/kit/commands/detectar-duplicacao.md +197 -197
- package/kit/commands/discutir-fase.md +131 -131
- package/kit/commands/encontrar-seams.md +136 -136
- package/kit/commands/entrar-discord.md +17 -17
- package/kit/commands/estatisticas.md +18 -18
- package/kit/commands/example-greeting.md +33 -33
- package/kit/commands/executar-fase.md +58 -58
- package/kit/commands/expresso.md +56 -56
- package/kit/commands/fase-ui.md +34 -34
- package/kit/commands/fazer.md +57 -57
- package/kit/commands/fio.md +125 -125
- package/kit/commands/fluxos-trabalho.md +64 -64
- package/kit/commands/forense.md +176 -176
- package/kit/commands/gerenciador.md +38 -38
- package/kit/commands/inserir-fase.md +31 -31
- package/kit/commands/legacy.md +263 -263
- package/kit/commands/limpeza.md +17 -17
- package/kit/commands/listar-hipoteses-fase.md +45 -45
- package/kit/commands/listar-workspaces.md +18 -18
- package/kit/commands/load-shedding.md +117 -117
- package/kit/commands/mapear-codebase.md +70 -70
- package/kit/commands/multi-tenant.md +163 -163
- package/kit/commands/nota.md +33 -33
- package/kit/commands/novo-marco.md +43 -43
- package/kit/commands/novo-projeto.md +41 -41
- package/kit/commands/novo-workspace.md +43 -43
- package/kit/commands/pausar-trabalho.md +37 -37
- package/kit/commands/perfil-usuario.md +45 -45
- package/kit/commands/pesquisar-fase.md +195 -195
- package/kit/commands/planejar-fase.md +67 -67
- package/kit/commands/planejar-lacunas.md +33 -33
- package/kit/commands/plantar-ideia.md +25 -25
- package/kit/commands/progresso.md +24 -24
- package/kit/commands/proximo.md +30 -30
- package/kit/commands/publicar.md +490 -490
- package/kit/commands/rapido.md +35 -35
- package/kit/commands/reaplicar-patches.md +124 -124
- package/kit/commands/refactor-seguro.md +321 -321
- package/kit/commands/relatorio-sessao.md +19 -19
- package/kit/commands/remover-fase.md +31 -31
- package/kit/commands/remover-workspace.md +26 -26
- package/kit/commands/resumo-marco.md +50 -50
- package/kit/commands/retomar-trabalho.md +40 -40
- package/kit/commands/revisar-backlog.md +60 -60
- package/kit/commands/revisar-ui.md +32 -32
- package/kit/commands/revisar.md +37 -37
- package/kit/commands/saude.md +21 -21
- package/kit/commands/setup-notion.md +93 -93
- package/kit/commands/storytelling.md +179 -179
- package/kit/commands/supabase.md +30 -7
- package/kit/commands/sync-main.md +68 -68
- package/kit/commands/validar-fase.md +35 -35
- package/kit/commands/verificar-tarefas.md +44 -44
- package/kit/commands/verificar-trabalho.md +64 -64
- package/kit/file-manifest.json +14 -8
- package/kit/framework/bin/lib/commands.cjs +959 -959
- package/kit/framework/bin/lib/config.cjs +442 -442
- package/kit/framework/bin/lib/core.cjs +1230 -1230
- package/kit/framework/bin/lib/frontmatter.cjs +336 -336
- package/kit/framework/bin/lib/init.cjs +1442 -1442
- package/kit/framework/bin/lib/milestone.cjs +252 -252
- package/kit/framework/bin/lib/model-profiles.cjs +68 -68
- package/kit/framework/bin/lib/phase.cjs +888 -888
- package/kit/framework/bin/lib/profile-output.cjs +952 -952
- package/kit/framework/bin/lib/profile-pipeline.cjs +539 -539
- package/kit/framework/bin/lib/roadmap.cjs +329 -329
- package/kit/framework/bin/lib/security.cjs +382 -382
- package/kit/framework/bin/lib/state.cjs +1031 -1031
- package/kit/framework/bin/lib/template.cjs +222 -222
- package/kit/framework/bin/lib/uat.cjs +282 -282
- package/kit/framework/bin/lib/verify.cjs +888 -888
- package/kit/framework/bin/lib/workstream.cjs +491 -491
- package/kit/framework/bin/tools.cjs +918 -918
- package/kit/framework/commands/workstreams.md +63 -63
- package/kit/framework/references/checkpoints.md +778 -778
- package/kit/framework/references/continuation-format.md +249 -249
- package/kit/framework/references/decimal-phase-calculation.md +64 -64
- package/kit/framework/references/git-integration.md +295 -295
- package/kit/framework/references/git-planning-commit.md +38 -38
- package/kit/framework/references/model-profile-resolution.md +36 -36
- package/kit/framework/references/model-profiles.md +139 -139
- package/kit/framework/references/phase-argument-parsing.md +61 -61
- package/kit/framework/references/planning-config.md +202 -202
- package/kit/framework/references/questioning.md +162 -162
- package/kit/framework/references/tdd.md +263 -263
- package/kit/framework/references/ui-brand.md +160 -160
- package/kit/framework/references/user-profiling.md +657 -657
- package/kit/framework/references/verification-patterns.md +612 -612
- package/kit/framework/references/workstream-flag.md +58 -58
- package/kit/framework/templates/DEBUG.md +164 -164
- package/kit/framework/templates/UAT.md +265 -265
- package/kit/framework/templates/UI-SPEC.md +100 -100
- package/kit/framework/templates/VALIDATION.md +76 -76
- package/kit/framework/templates/claude-md.md +122 -122
- package/kit/framework/templates/codebase/architecture.md +185 -185
- package/kit/framework/templates/codebase/concerns.md +205 -205
- package/kit/framework/templates/codebase/conventions.md +204 -204
- package/kit/framework/templates/codebase/integrations.md +192 -192
- package/kit/framework/templates/codebase/stack.md +158 -158
- package/kit/framework/templates/codebase/structure.md +199 -199
- package/kit/framework/templates/codebase/testing.md +301 -301
- package/kit/framework/templates/config.json +44 -44
- package/kit/framework/templates/context.md +352 -352
- package/kit/framework/templates/continue-here.md +78 -78
- package/kit/framework/templates/copilot-instructions.md +7 -7
- package/kit/framework/templates/debug-subagent-prompt.md +91 -91
- package/kit/framework/templates/dev-preferences.md +20 -20
- package/kit/framework/templates/discovery.md +146 -146
- package/kit/framework/templates/discussion-log.md +63 -63
- package/kit/framework/templates/milestone-archive.md +123 -123
- package/kit/framework/templates/milestone.md +115 -115
- package/kit/framework/templates/phase-prompt.md +610 -610
- package/kit/framework/templates/planner-subagent-prompt.md +117 -117
- package/kit/framework/templates/project.md +186 -186
- package/kit/framework/templates/requirements.md +231 -231
- package/kit/framework/templates/research-project/ARCHITECTURE.md +204 -204
- package/kit/framework/templates/research-project/FEATURES.md +147 -147
- package/kit/framework/templates/research-project/PITFALLS.md +200 -200
- package/kit/framework/templates/research-project/STACK.md +120 -120
- package/kit/framework/templates/research-project/SUMMARY.md +170 -170
- package/kit/framework/templates/research.md +419 -419
- package/kit/framework/templates/retrospective.md +54 -54
- package/kit/framework/templates/roadmap.md +202 -202
- package/kit/framework/templates/state.md +176 -176
- package/kit/framework/templates/summary-complex.md +59 -59
- package/kit/framework/templates/summary-minimal.md +41 -41
- package/kit/framework/templates/summary-standard.md +48 -48
- package/kit/framework/templates/summary.md +209 -209
- package/kit/framework/templates/user-profile.md +146 -146
- package/kit/framework/templates/user-setup.md +256 -256
- package/kit/framework/templates/verification-report.md +258 -258
- package/kit/framework/workflows/add-phase.md +112 -112
- package/kit/framework/workflows/add-tests.md +351 -351
- package/kit/framework/workflows/add-todo.md +158 -158
- package/kit/framework/workflows/audit-milestone.md +340 -340
- package/kit/framework/workflows/audit-uat.md +109 -109
- package/kit/framework/workflows/autonomous.md +891 -891
- package/kit/framework/workflows/check-todos.md +177 -177
- package/kit/framework/workflows/cleanup.md +152 -152
- package/kit/framework/workflows/complete-milestone.md +696 -696
- package/kit/framework/workflows/diagnose-issues.md +231 -231
- package/kit/framework/workflows/discovery-phase.md +289 -289
- package/kit/framework/workflows/discuss-phase-assumptions.md +653 -653
- package/kit/framework/workflows/discuss-phase.md +784 -784
- package/kit/framework/workflows/do.md +104 -104
- package/kit/framework/workflows/execute-phase.md +838 -838
- package/kit/framework/workflows/execute-plan.md +510 -510
- package/kit/framework/workflows/fast.md +102 -102
- package/kit/framework/workflows/forensics.md +265 -265
- package/kit/framework/workflows/health.md +181 -181
- package/kit/framework/workflows/help.md +619 -619
- package/kit/framework/workflows/insert-phase.md +130 -130
- package/kit/framework/workflows/list-phase-assumptions.md +178 -178
- package/kit/framework/workflows/list-workspaces.md +56 -56
- package/kit/framework/workflows/manager.md +362 -362
- package/kit/framework/workflows/map-codebase.md +377 -377
- package/kit/framework/workflows/milestone-summary.md +223 -223
- package/kit/framework/workflows/new-milestone.md +486 -486
- package/kit/framework/workflows/new-project.md +1159 -1159
- package/kit/framework/workflows/new-workspace.md +237 -237
- package/kit/framework/workflows/next.md +97 -97
- package/kit/framework/workflows/node-repair.md +92 -92
- package/kit/framework/workflows/note.md +156 -156
- package/kit/framework/workflows/pause-work.md +176 -176
- package/kit/framework/workflows/plan-milestone-gaps.md +273 -273
- package/kit/framework/workflows/plan-phase.md +765 -765
- package/kit/framework/workflows/plant-seed.md +169 -169
- package/kit/framework/workflows/pr-branch.md +129 -129
- package/kit/framework/workflows/profile-user.md +450 -450
- package/kit/framework/workflows/progress.md +507 -507
- package/kit/framework/workflows/quick.md +757 -757
- package/kit/framework/workflows/remove-phase.md +155 -155
- package/kit/framework/workflows/remove-workspace.md +90 -90
- package/kit/framework/workflows/research-phase.md +82 -82
- package/kit/framework/workflows/resume-project.md +326 -326
- package/kit/framework/workflows/review.md +228 -228
- package/kit/framework/workflows/session-report.md +146 -146
- package/kit/framework/workflows/settings.md +283 -283
- package/kit/framework/workflows/ship.md +228 -228
- package/kit/framework/workflows/stats.md +60 -60
- package/kit/framework/workflows/transition.md +671 -671
- package/kit/framework/workflows/ui-phase.md +302 -302
- package/kit/framework/workflows/ui-review.md +165 -165
- package/kit/framework/workflows/update.md +323 -323
- package/kit/framework/workflows/validate-phase.md +174 -174
- package/kit/framework/workflows/verify-phase.md +252 -252
- package/kit/framework/workflows/verify-work.md +637 -637
- package/kit/hooks/check-update.js +118 -118
- package/kit/hooks/context-monitor.js +163 -163
- package/kit/hooks/prompt-guard.js +103 -103
- package/kit/hooks/statusline.js +125 -125
- package/kit/hooks/workflow-guard.js +101 -101
- package/kit/settings.json +45 -45
- package/kit/skills/_shared-supabase/glossary.md +17 -0
- package/kit/skills/ai-prompt-characterization/SKILL.md +335 -335
- package/kit/skills/armadilhas-sistemas-distribuidos/SKILL.md +447 -447
- package/kit/skills/audit-log-multi-tenant/SKILL.md +340 -340
- package/kit/skills/b2b-saas-architecture/SKILL.md +300 -300
- package/kit/skills/consistencia-leitura-replica/SKILL.md +385 -385
- package/kit/skills/crm-lead-pipeline-patterns/SKILL.md +343 -343
- package/kit/skills/escolha-modelo-consistencia/SKILL.md +494 -494
- package/kit/skills/evolucao-schema-compativel/SKILL.md +448 -448
- package/kit/skills/evolution-go-whatsapp-integration/SKILL.md +322 -322
- package/kit/skills/example-skill/SKILL.md +42 -42
- package/kit/skills/legacy-api-only-applications/SKILL.md +358 -358
- package/kit/skills/legacy-characterization-tests/SKILL.md +330 -330
- package/kit/skills/legacy-effect-analysis/SKILL.md +331 -331
- package/kit/skills/legacy-extract-class/SKILL.md +203 -203
- package/kit/skills/legacy-programming-by-difference/SKILL.md +252 -252
- package/kit/skills/legacy-seams-and-test-harness/SKILL.md +460 -460
- package/kit/skills/legacy-shotgun-surgery/SKILL.md +286 -286
- package/kit/skills/legacy-sprout-wrap-techniques/SKILL.md +434 -434
- package/kit/skills/legacy-storytelling-naked-crc/SKILL.md +270 -270
- package/kit/skills/lgpd-multi-tenant-compliance/SKILL.md +340 -340
- package/kit/skills/member-invite-flow/SKILL.md +305 -305
- package/kit/skills/member-management-react-shadcn/SKILL.md +328 -328
- package/kit/skills/multi-tenant-performance-scaling/SKILL.md +316 -316
- package/kit/skills/multi-tenant-rls-hierarchy/SKILL.md +342 -342
- package/kit/skills/org-onboarding-flow/SKILL.md +257 -257
- package/kit/skills/org-switcher-react-pattern/SKILL.md +349 -349
- package/kit/skills/permission-gate-react-pattern/SKILL.md +271 -271
- package/kit/skills/postgres-isolamento-concorrencia/SKILL.md +552 -552
- package/kit/skills/pre-refactor-characterization/SKILL.md +421 -421
- package/kit/skills/rbac-permissions-matrix-supabase/SKILL.md +338 -338
- package/kit/skills/streams-eventos-cdc/SKILL.md +711 -711
- package/kit/skills/supabase-branching-workflow/SKILL.md +544 -544
- package/kit/skills/supabase-ci-cd-github-actions/SKILL.md +880 -880
- package/kit/skills/supabase-column-level-security/SKILL.md +426 -426
- package/kit/skills/supabase-config-toml-remotes/SKILL.md +807 -807
- package/kit/skills/supabase-custom-claims-rbac/SKILL.md +472 -472
- package/kit/skills/supabase-edge-functions/SKILL.md +229 -141
- package/kit/skills/supabase-edge-functions-auth/SKILL.md +309 -0
- package/kit/skills/supabase-edge-functions-limits/SKILL.md +302 -0
- package/kit/skills/supabase-edge-functions-mcp-server/SKILL.md +279 -0
- package/kit/skills/supabase-edge-functions-testing/SKILL.md +277 -0
- package/kit/skills/supabase-edge-runtime-builtins/SKILL.md +357 -0
- package/kit/skills/supabase-migration-repair/SKILL.md +823 -823
- package/kit/skills/supabase-migrations/SKILL.md +297 -297
- package/kit/skills/supabase-pgtap-testing/SKILL.md +1053 -1053
- package/kit/skills/supabase-postgres-roles/SKILL.md +392 -392
- package/kit/skills/supabase-realtime/SKILL.md +460 -236
- package/kit/skills/supabase-rls-defense-in-depth/SKILL.md +418 -418
- package/kit/skills/supabase-rls-policies/SKILL.md +635 -635
- package/kit/skills/super-admin-platform-pattern/SKILL.md +326 -326
- package/kit/skills/tenant-quente-mitigacao/SKILL.md +605 -605
- package/kit/skills/whatsapp-conversation-state-machine/SKILL.md +287 -287
- package/package.json +1 -1
- package/src/core/kit.js +216 -216
- package/src/core/reflect.js +247 -247
- package/src/core/reverse-sync.js +372 -372
- package/src/core/sync.js +418 -418
- package/src/core/watch.js +121 -121
- package/src/mcp-server/index.js +693 -693
|
@@ -1,823 +1,823 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: supabase-migration-repair
|
|
3
|
-
description: Use ao diagnosticar e reparar sync errors entre local supabase/migrations/ e remote supabase_migrations.schema_migrations tracking table…
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Supabase — Migration Repair
|
|
7
|
-
|
|
8
|
-
## Quando usar
|
|
9
|
-
|
|
10
|
-
Use esta skill ao enfrentar **sync errors** ou **estado inconsistente** entre o folder local `supabase/migrations/` e a tracking table remota `supabase_migrations.schema_migrations`, ou ao precisar de rollback de preview branch após migration falha.
|
|
11
|
-
|
|
12
|
-
Trigger phrases:
|
|
13
|
-
|
|
14
|
-
- "migration repair", "supabase migration repair"
|
|
15
|
-
- "sync error Supabase", "migration history mismatch"
|
|
16
|
-
- "supabase migration list mostra mismatch"
|
|
17
|
-
- "schema drift Supabase", "git rebase migration timestamps"
|
|
18
|
-
- "permission denied migration", "permission denied for table _type"
|
|
19
|
-
- "permission denied 42501 Supabase", "custom_role to postgres"
|
|
20
|
-
- "rollback preview branch Supabase"
|
|
21
|
-
- "db push falhando re-aplicar migration"
|
|
22
|
-
- "db pull pg_dump error graphql"
|
|
23
|
-
|
|
24
|
-
**Use esta skill APENAS para:**
|
|
25
|
-
|
|
26
|
-
- Diagnosticar mismatch entre folder local e tracking table remoto
|
|
27
|
-
- Corrigir history record em `supabase_migrations.schema_migrations` quando schema state real está OK
|
|
28
|
-
- Rollback de preview branch ephemeral via PR close+reopen (cross-ref skill `supabase-branching-workflow` Phase 149)
|
|
29
|
-
- Resolver drift de timestamps após git rebase em equipe
|
|
30
|
-
- Resolver erros `42501 permission denied` e `pg_dump error permission denied for table _type`
|
|
31
|
-
|
|
32
|
-
**NÃO use esta skill para:**
|
|
33
|
-
|
|
34
|
-
- Reverter mudanças de schema reais — `migration repair` NÃO reverte SQL (cross-ref CAVEAT CRÍTICO abaixo)
|
|
35
|
-
- Substituir testes de migration — preview branch + DAG step 5 (cross-ref skill `supabase-branching-workflow` Phase 149) é o gate canônico
|
|
36
|
-
- Bypassar migration files aplicando schema changes via Dashboard SQL editor — isso CRIA o problema que esta skill diagnostica
|
|
37
|
-
- Recovery de production database com data loss — backup + point-in-time recovery do Supabase (fora do escopo desta skill)
|
|
38
|
-
|
|
39
|
-
## Princípio canônico
|
|
40
|
-
|
|
41
|
-
Três princípios canônicos sustentam toda a skill:
|
|
42
|
-
|
|
43
|
-
### Princípio 1 — Tracking table state ≠ schema state real
|
|
44
|
-
|
|
45
|
-
A tracking table `supabase_migrations.schema_migrations` é um **registro de histórico** de quais migrations foram aplicadas. O **schema state real** é o estado físico do DB (tabelas, colunas, indices, funções, policies).
|
|
46
|
-
|
|
47
|
-
Os dois podem divergir:
|
|
48
|
-
|
|
49
|
-
| Schema real | Tracking table | Causa | Sintoma |
|
|
50
|
-
|---|---|---|---|
|
|
51
|
-
| Tabela `foo` existe | Sem registro 20240102 | Migration aplicada manualmente via Dashboard SQL editor | `db push` tenta re-aplicar 20240102 e falha com "relation foo already exists" |
|
|
52
|
-
| Tabela `foo` NÃO existe | Com registro 20240102 | Tracking table corrupto / migration teve rollback parcial | `db push` skip 20240102 mas tabela ausente |
|
|
53
|
-
| Tabela `foo` existe | Com registro 20240102 | Estado normal — sincronizado | Nenhum |
|
|
54
|
-
| Tabela `foo` NÃO existe | Sem registro 20240102 | Nada aplicado ainda — pendente | `db push` aplica 20240102 normalmente |
|
|
55
|
-
|
|
56
|
-
### Princípio 2 — Diagnose ANTES de repair
|
|
57
|
-
|
|
58
|
-
NUNCA execute `supabase migration repair` sem primeiro rodar `supabase migration list` para entender QUAL migration está em qual estado de mismatch. Repair cego pode mascarar bug + tornar recovery mais difícil.
|
|
59
|
-
|
|
60
|
-
### Princípio 3 — Rollback preview preferível a manual revert
|
|
61
|
-
|
|
62
|
-
Para preview branches Supabase Branching (Phase 149), **delete+reopen do PR** é canônico e seguro. Tentar criar "reverter migration" manualmente para desfazer schema changes em preview branch é anti-pattern — preview branches são ephemeral by design (cross-ref skill `supabase-branching-workflow` Phase 149).
|
|
63
|
-
|
|
64
|
-
## CAVEAT CRÍTICO — Tracking table apenas
|
|
65
|
-
|
|
66
|
-
> **`supabase migration repair` atualiza APENAS a tracking table `supabase_migrations.schema_migrations`. NÃO aplica SQL nem reverte SQL.**
|
|
67
|
-
>
|
|
68
|
-
> Este caveat é repetido **DUAS VEZES** nesta skill (Pattern 2 + abaixo) porque é a fonte #1 de bugs em recovery de migrations Supabase. LLMs e humanos frequentemente assumem que `repair --status reverted` "desfaz" a migration — **NÃO DESFAZ**.
|
|
69
|
-
>
|
|
70
|
-
> Se a migration realmente alterou schema (criou tabela, alterou coluna, etc.), `repair --status reverted` APENAS remove o registro do histórico. As mudanças físicas no DB **permanecem**. Para reverter mudanças de schema reais:
|
|
71
|
-
>
|
|
72
|
-
> 1. Criar **nova migration** que desfaz as mudanças (`drop table ...`, `alter table ... drop column ...`)
|
|
73
|
-
> 2. Aplicar via `supabase db push`
|
|
74
|
-
> 3. NÃO usar `repair --status reverted` esperando reverter SQL
|
|
75
|
-
|
|
76
|
-
## Pattern 1: Diagnóstico via `supabase migration list` (REPAIR-01)
|
|
77
|
-
|
|
78
|
-
Primeira ação canônica em qualquer cenário de migration error — **sempre** começar por aqui.
|
|
79
|
-
|
|
80
|
-
### Comando
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
supabase migration list
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Output canônico
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
LOCAL │ REMOTE │ TIME (UTC)
|
|
90
|
-
─────────────────────┼────────────────┼─────────────────────
|
|
91
|
-
20240101120000 │ 20240101120000 │ 2024-01-01 12:00:00
|
|
92
|
-
20240102140000 │ - │ 2024-01-02 14:00:00
|
|
93
|
-
- │ 20240103160000 │ 2024-01-03 16:00:00
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Interpretação canônica das 3 colunas
|
|
97
|
-
|
|
98
|
-
| Coluna | Significado |
|
|
99
|
-
|---|---|
|
|
100
|
-
| **LOCAL** | Timestamp encontrado em `supabase/migrations/*.sql` (folder local do repo git) |
|
|
101
|
-
| **REMOTE** | Timestamp registrado em `supabase_migrations.schema_migrations` (tracking table no DB remoto) |
|
|
102
|
-
| **TIME (UTC)** | Quando foi aplicada (presente apenas quando coluna REMOTE tem valor) |
|
|
103
|
-
|
|
104
|
-
### 3 estados canônicos por linha
|
|
105
|
-
|
|
106
|
-
**Estado 1: sincronizado**
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
20240101120000 │ 20240101120000 │ 2024-01-01 12:00:00
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Migration presente em ambos — estado **normal**, nenhuma ação necessária.
|
|
113
|
-
|
|
114
|
-
**Estado 2: local-only (pending push)**
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
20240102140000 │ - │ 2024-01-02 14:00:00
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Migration existe no folder local mas NÃO foi aplicada no remote. Ação canônica:
|
|
121
|
-
|
|
122
|
-
```bash
|
|
123
|
-
supabase db push
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Aplica migrations pendentes em ordem cronológica.
|
|
127
|
-
|
|
128
|
-
**Estado 3: remote-only (drift)**
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
- │ 20240103160000 │ 2024-01-03 16:00:00
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Migration foi aplicada no remote (registrada na tracking table) MAS o arquivo `.sql` correspondente NÃO existe no folder local. Causas possíveis:
|
|
135
|
-
|
|
136
|
-
- Migration aplicada manualmente via Dashboard SQL editor sem commit no git
|
|
137
|
-
- Outro dev aplicou migration e ainda não pushou para git remoto
|
|
138
|
-
- Arquivo local foi deletado por engano
|
|
139
|
-
|
|
140
|
-
Ação canônica:
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
supabase db pull
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Gera arquivo `.sql` local correspondente à migration registrada no remote. Sincroniza folder local com tracking table.
|
|
147
|
-
|
|
148
|
-
### Comportamento canônico de `supabase db push`
|
|
149
|
-
|
|
150
|
-
`supabase db push` compara local folder vs remote tracking table:
|
|
151
|
-
|
|
152
|
-
1. Lista migrations em `supabase/migrations/*.sql` (folder local)
|
|
153
|
-
2. Lista migrations em `supabase_migrations.schema_migrations` (tracking table)
|
|
154
|
-
3. Calcula diff: migrations no folder MAS não na tracking table
|
|
155
|
-
4. Aplica em ordem cronológica (por timestamp) — registra cada uma na tracking table após sucesso
|
|
156
|
-
|
|
157
|
-
**Caveat — tracking table é fonte de verdade para "o que foi aplicado":**
|
|
158
|
-
|
|
159
|
-
Se você deleta o folder local, `db push` NÃO re-aplica migrations já registradas na tracking table. Para forçar re-aplicação, precisa:
|
|
160
|
-
|
|
161
|
-
1. `db pull` para regenerar folder local a partir do remote, OU
|
|
162
|
-
2. `migration repair --status reverted <timestamp>` para remover o registro da tracking table (CAVEAT CRÍTICO repetido — isso só remove o registro, NÃO reverte schema)
|
|
163
|
-
|
|
164
|
-
### Estrutura interna da tracking table
|
|
165
|
-
|
|
166
|
-
```sql
|
|
167
|
-
-- estrutura canônica da tracking table (não modificar manualmente)
|
|
168
|
-
\d supabase_migrations.schema_migrations
|
|
169
|
-
|
|
170
|
-
Column │ Type
|
|
171
|
-
──────────────────┼─────────────────────────
|
|
172
|
-
version │ text NOT NULL PRIMARY KEY
|
|
173
|
-
name │ text
|
|
174
|
-
statements │ text[]
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
- `version` — timestamp da migration (PK)
|
|
178
|
-
- `name` — descrição da migration
|
|
179
|
-
- `statements` — array com SQL aplicado (audit trail)
|
|
180
|
-
|
|
181
|
-
**NUNCA modifique esta tabela diretamente.** Use `migration repair` (Pattern 2) para mutação segura via CLI.
|
|
182
|
-
|
|
183
|
-
## Pattern 2: `migration repair --status applied|reverted` (REPAIR-02)
|
|
184
|
-
|
|
185
|
-
> **CAVEAT CRÍTICO REPETIDO — tracking table apenas:**
|
|
186
|
-
>
|
|
187
|
-
> `supabase migration repair` atualiza APENAS a tracking table `supabase_migrations.schema_migrations`. **NÃO aplica SQL nem reverte SQL.**
|
|
188
|
-
>
|
|
189
|
-
> Se a migration realmente alterou schema, `repair --status reverted` remove o registro do histórico MAS as mudanças físicas no DB **permanecem**. Para reverter schema changes reais, crie nova migration via `supabase migration new`.
|
|
190
|
-
|
|
191
|
-
### Sintaxe canônica
|
|
192
|
-
|
|
193
|
-
```bash
|
|
194
|
-
supabase migration repair --status <applied|reverted> <migration-timestamp>
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
Dois subcomandos canônicos:
|
|
198
|
-
|
|
199
|
-
- `--status applied <timestamp>` — adiciona registro à tracking table (marca como aplicada)
|
|
200
|
-
- `--status reverted <timestamp>` — remove registro da tracking table (marca como reverted)
|
|
201
|
-
|
|
202
|
-
### Caso 1 — Migration aplicada manualmente (precisa marcar como applied)
|
|
203
|
-
|
|
204
|
-
**Cenário:**
|
|
205
|
-
|
|
206
|
-
- Dev abriu Dashboard → SQL editor → executou `CREATE TABLE foo (...)` direto no DB remoto
|
|
207
|
-
- Schema state OK (tabela existe), mas tracking table NÃO tem registro
|
|
208
|
-
- Posteriormente, dev criou migration `20240102_create_foo.sql` no folder local com o mesmo SQL
|
|
209
|
-
- `supabase db push` lista migration como pending → tenta aplicar → falha com `relation "foo" already exists`
|
|
210
|
-
|
|
211
|
-
**Diagnóstico:**
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
supabase migration list
|
|
215
|
-
# Output:
|
|
216
|
-
# 20240102140000 │ - │ 2024-01-02 14:00:00
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
Confirma migration está local-only — porém schema state real tem a tabela. Repair canônico:
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
supabase migration repair --status applied 20240102140000
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**O que acontece:**
|
|
226
|
-
|
|
227
|
-
- Tracking table recebe novo registro: `INSERT INTO supabase_migrations.schema_migrations (version, name) VALUES ('20240102140000', 'create_foo')`
|
|
228
|
-
- Schema state físico NÃO é alterado (tabela `foo` continua existindo, sem nenhuma operação SQL extra)
|
|
229
|
-
- Próximo `supabase migration list` mostra migration sincronizada
|
|
230
|
-
|
|
231
|
-
**Quando usar este caso:**
|
|
232
|
-
|
|
233
|
-
- Hotfix aplicado emergencialmente via Dashboard SQL editor sem migration file
|
|
234
|
-
- Migration aplicada manualmente em ambiente novo (ex: replicar schema de produção)
|
|
235
|
-
- Schema gerado por ferramenta externa (Drizzle, Prisma) onde tracking table está fora de sync
|
|
236
|
-
|
|
237
|
-
### Caso 2 — Migration registrada mas nunca aplicada (precisa marcar como reverted)
|
|
238
|
-
|
|
239
|
-
**Cenário:**
|
|
240
|
-
|
|
241
|
-
- Tracking table tem registro `20240102140000` MAS schema state real NÃO tem a tabela criada por essa migration
|
|
242
|
-
- Causas possíveis: tracking table corrupto, migration teve rollback parcial, restore parcial de backup
|
|
243
|
-
|
|
244
|
-
**Diagnóstico:**
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
supabase migration list
|
|
248
|
-
# Output:
|
|
249
|
-
# 20240102140000 │ 20240102140000 │ 2024-01-02 14:00:00
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
Aparenta sincronizado, mas tabela não existe. Confirmar via:
|
|
253
|
-
|
|
254
|
-
```sql
|
|
255
|
-
-- conectar via psql ou Dashboard SQL editor
|
|
256
|
-
select table_name from information_schema.tables where table_schema = 'public' and table_name = 'foo';
|
|
257
|
-
-- 0 rows
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Repair canônico:
|
|
261
|
-
|
|
262
|
-
```bash
|
|
263
|
-
supabase migration repair --status reverted 20240102140000
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**O que acontece:**
|
|
267
|
-
|
|
268
|
-
- Tracking table tem registro DELETADO: `DELETE FROM supabase_migrations.schema_migrations WHERE version = '20240102140000'`
|
|
269
|
-
- Schema state físico NÃO é alterado (tabela `foo` continua não existindo — `repair` não cria nada)
|
|
270
|
-
- `supabase db push` agora considera migration como pending → aplica normalmente
|
|
271
|
-
|
|
272
|
-
**Quando usar este caso:**
|
|
273
|
-
|
|
274
|
-
- Tracking table está fora de sync por motivo desconhecido
|
|
275
|
-
- Migration tem registro mas schema state real não reflete (tabela ausente, coluna ausente, etc.)
|
|
276
|
-
- Precisa "forçar" re-aplicação de migration via `db push` após confirmar que schema real não tem as mudanças
|
|
277
|
-
|
|
278
|
-
### Anti-uso CRÍTICO — não usar para reverter schema
|
|
279
|
-
|
|
280
|
-
```bash
|
|
281
|
-
# ERRADO — esperar que isso reverta a tabela criada pela migration
|
|
282
|
-
supabase migration repair --status reverted 20240102140000
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
**Por quê:** apenas remove o registro. A tabela `foo` continua existindo. Próximo `supabase db push` vai tentar aplicar a migration novamente, falhar com `relation already exists`, e você fica em loop infinito.
|
|
286
|
-
|
|
287
|
-
**Certo — para reverter schema changes reais:**
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
# 1. Criar nova migration que desfaz as mudanças
|
|
291
|
-
supabase migration new drop_foo
|
|
292
|
-
|
|
293
|
-
# 2. Editar arquivo gerado supabase/migrations/<novo-timestamp>_drop_foo.sql:
|
|
294
|
-
# drop table if exists public.foo;
|
|
295
|
-
|
|
296
|
-
# 3. Aplicar
|
|
297
|
-
supabase db push
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Fluxograma canônico de decisão
|
|
301
|
-
|
|
302
|
-
```
|
|
303
|
-
Sync error em supabase migration list?
|
|
304
|
-
│
|
|
305
|
-
├─ Local-only (LOCAL=X, REMOTE=-)
|
|
306
|
-
│ │
|
|
307
|
-
│ ├─ Schema real TEM as mudanças?
|
|
308
|
-
│ │ ├─ SIM → repair --status applied <X>
|
|
309
|
-
│ │ └─ NÃO → supabase db push (aplicação normal)
|
|
310
|
-
│ │
|
|
311
|
-
│
|
|
312
|
-
├─ Remote-only (LOCAL=-, REMOTE=Y)
|
|
313
|
-
│ │
|
|
314
|
-
│ ├─ Schema real TEM as mudanças?
|
|
315
|
-
│ │ ├─ SIM → supabase db pull (regenera arquivo local)
|
|
316
|
-
│ │ └─ NÃO → repair --status reverted <Y> (limpa registro órfão)
|
|
317
|
-
│
|
|
318
|
-
└─ Aparenta sincronizado mas erros persistem
|
|
319
|
-
│
|
|
320
|
-
├─ Conectar via psql + verificar schema state real
|
|
321
|
-
└─ Decidir entre repair vs nova migration baseado em estado
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
## Pattern 3: Rollback preview branch via delete + reopen (REPAIR-03)
|
|
325
|
-
|
|
326
|
-
Quando uma migration ruim foi pushada para preview branch Supabase Branching e DAG falhou no step 5 (migrate), o **canônico** é NÃO criar reverter migration — use rollback via PR close+reopen.
|
|
327
|
-
|
|
328
|
-
### Workflow canônico (5 passos)
|
|
329
|
-
|
|
330
|
-
```
|
|
331
|
-
1. Dev pusha migration ruim em PR
|
|
332
|
-
↓
|
|
333
|
-
2. Supabase webhook → DAG step 5 (migrate) FALHA
|
|
334
|
-
↓ status no PR: "Supabase Preview ✗"
|
|
335
|
-
↓
|
|
336
|
-
3. Dev fecha PR (GitHub UI: "Close pull request")
|
|
337
|
-
↓
|
|
338
|
-
4. Supabase Branching detecta PR closed → DELETA preview branch
|
|
339
|
-
↓ (cleanup completo: DB, Edge Functions, Storage config)
|
|
340
|
-
↓
|
|
341
|
-
5. Dev fixa migration + reopen PR (GitHub UI: "Reopen pull request")
|
|
342
|
-
↓
|
|
343
|
-
6. Supabase Branching detecta PR reopened → CRIA novo preview branch
|
|
344
|
-
↓ DAG roda steps 1-7 do zero com migration corrigida
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
### Equivalência canônica
|
|
348
|
-
|
|
349
|
-
**Delete preview branch + reopen** = **`supabase db reset` local**.
|
|
350
|
-
|
|
351
|
-
Ambos:
|
|
352
|
-
|
|
353
|
-
- Limpam DB state completamente
|
|
354
|
-
- Re-executam todas migrations em ordem cronológica
|
|
355
|
-
- Re-aplicam `supabase/seed.sql`
|
|
356
|
-
- Resetam Edge Functions para versão atual do branch git
|
|
357
|
-
|
|
358
|
-
### Caveats canônicos
|
|
359
|
-
|
|
360
|
-
**Caveat 1 — Data changes adicionais SÃO PERDIDOS**
|
|
361
|
-
|
|
362
|
-
`seed.sql` é re-aplicado como dataless setup. Quaisquer rows inseridas/atualizadas manualmente durante uso do preview branch:
|
|
363
|
-
|
|
364
|
-
- Via Dashboard Table editor
|
|
365
|
-
- Via testes manuais (insert, update direto)
|
|
366
|
-
- Via Edge Function execution (que escreveu em tabelas)
|
|
367
|
-
|
|
368
|
-
**são perdidas** no reset. Aceito como trade-off canônico para reset limpo — preview branches são ephemeral by design (cross-ref skill `supabase-branching-workflow` Phase 149).
|
|
369
|
-
|
|
370
|
-
**Caveat 2 — Auto-pause em inatividade NÃO substitui reset**
|
|
371
|
-
|
|
372
|
-
Preview branches auto-pausam após inatividade (~24h sem requests), mas isso preserva o state. NÃO é equivalente a reset. Para limpeza real, sempre use close+reopen.
|
|
373
|
-
|
|
374
|
-
**Caveat 3 — Branching Compute Hours acumulam novamente**
|
|
375
|
-
|
|
376
|
-
Reopen recria preview branch do zero → nova hora de Branching Compute Hours é cobrada (cross-ref skill `supabase-branching-workflow` Phase 149 — Pattern 5 custo). Se rollback acontece 5× para o mesmo PR, são 5 horas extras cobradas. Considere disciplina: testar migration localmente antes de push.
|
|
377
|
-
|
|
378
|
-
### Quando usar este pattern
|
|
379
|
-
|
|
380
|
-
- Migration ruim foi pushada para preview branch
|
|
381
|
-
- DAG step 5 (migrate) falhou — sem possibilidade de recovery via re-push (porque o branch já está em estado "failed")
|
|
382
|
-
- Você quer voltar ao estado limpo sem aplicar reverter migration manualmente
|
|
383
|
-
- Aceita perda de data changes adicionais que não estavam em seed.sql
|
|
384
|
-
|
|
385
|
-
### Quando NÃO usar este pattern
|
|
386
|
-
|
|
387
|
-
- Persistent branches (staging/QA) — NÃO use delete+reopen; persistent branches são long-lived (cross-ref skill `supabase-branching-workflow` Phase 149 — Pattern 1)
|
|
388
|
-
- Production project — production NUNCA tem rollback via "close PR" — use migration de reversão + `db push` + cuidados extras (backup + monitoramento)
|
|
389
|
-
- Quando você precisa preservar data changes — não há recovery dos dados após delete
|
|
390
|
-
|
|
391
|
-
### Workflow alternativo: push corrected migration
|
|
392
|
-
|
|
393
|
-
Se o branch ainda está em estado "failed" mas branch ainda existe (PR não foi fechado):
|
|
394
|
-
|
|
395
|
-
```
|
|
396
|
-
1. Identificar root cause via Dashboard → branch deployment logs (step 5 stderr)
|
|
397
|
-
2. Corrigir migration localmente
|
|
398
|
-
3. git commit + git push (mesmo PR)
|
|
399
|
-
4. Supabase webhook detecta push → re-run DAG do step 1
|
|
400
|
-
5. Se passa step 5 → step 6 (seed) e step 7 (deploy) executam
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
Este workflow é **preferível** se o erro foi simples (typo, syntax error) — evita Branching Compute Hours extras do reset.
|
|
404
|
-
|
|
405
|
-
## Pattern 4: Schema drift após git rebase (REPAIR-04)
|
|
406
|
-
|
|
407
|
-
Cenário canônico em equipes que mergem migrations em paralelo via PRs em main.
|
|
408
|
-
|
|
409
|
-
### Problema canônico
|
|
410
|
-
|
|
411
|
-
```
|
|
412
|
-
Timeline:
|
|
413
|
-
T = Dev A cria PR-A com migration 20240106120000_dev_A.sql
|
|
414
|
-
T+1 = Dev B cria PR-B com migration 20240106130000_dev_B.sql
|
|
415
|
-
T+2 = PR-B é merged primeiro (dev_B agora está em main)
|
|
416
|
-
T+3 = Dev A faz git pull origin main → traz dev_B
|
|
417
|
-
T+4 = Dev A faz git rebase main em sua branch
|
|
418
|
-
T+5 = Estado: branch de Dev A tem dev_B (timestamp 13:00) + dev_A (timestamp 12:00)
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
**Problema:** após rebase, Dev A tem migrations em ordem:
|
|
422
|
-
|
|
423
|
-
```
|
|
424
|
-
supabase/migrations/
|
|
425
|
-
├── 20240106120000_dev_A.sql (mais antiga)
|
|
426
|
-
├── 20240106130000_dev_B.sql (mais nova)
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
Local `supabase db reset` aplica em ordem cronológica:
|
|
430
|
-
|
|
431
|
-
1. Aplica `20240106120000_dev_A.sql` PRIMEIRO
|
|
432
|
-
2. Aplica `20240106130000_dev_B.sql` DEPOIS
|
|
433
|
-
|
|
434
|
-
Se `dev_A` depende de schema state que só existe APÓS `dev_B` (ex: dev_A adiciona FK para tabela que dev_B criou), `supabase db reset` falha.
|
|
435
|
-
|
|
436
|
-
**Pior:** quando `db push` para production, ordem cronológica força dev_A primeiro → falha em produção.
|
|
437
|
-
|
|
438
|
-
### Solução canônica (4 passos)
|
|
439
|
-
|
|
440
|
-
```bash
|
|
441
|
-
# Passo 1: Pull main (traz migrations recentes da equipe)
|
|
442
|
-
git pull origin main
|
|
443
|
-
|
|
444
|
-
# Passo 2: Criar nova migration com timestamp atualizado (placeholder)
|
|
445
|
-
supabase migration new dev_A
|
|
446
|
-
# Cria: supabase/migrations/20240106140000_dev_A.sql (timestamp ATUAL, mais novo)
|
|
447
|
-
|
|
448
|
-
# Passo 3: Renomear migration antiga para o novo timestamp
|
|
449
|
-
mv supabase/migrations/20240106120000_dev_A.sql supabase/migrations/20240106140000_dev_A.sql
|
|
450
|
-
|
|
451
|
-
# (Passo 2 criou arquivo vazio; passo 3 sobrescreve com conteúdo correto)
|
|
452
|
-
|
|
453
|
-
# Passo 4: Reset local para reaplicar tudo em ordem cronológica correta
|
|
454
|
-
supabase db reset
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
### Resultado final
|
|
458
|
-
|
|
459
|
-
```
|
|
460
|
-
supabase/migrations/
|
|
461
|
-
├── 20240106130000_dev_B.sql (do teammate, vem primeiro)
|
|
462
|
-
├── 20240106140000_dev_A.sql (renomeada com timestamp posterior, vem depois)
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
`supabase db reset` aplica em ordem correta:
|
|
466
|
-
|
|
467
|
-
1. Aplica `20240106130000_dev_B.sql` (tabela criada por dev_B)
|
|
468
|
-
2. Aplica `20240106140000_dev_A.sql` (FK funciona porque tabela já existe)
|
|
469
|
-
|
|
470
|
-
### Princípio canônico
|
|
471
|
-
|
|
472
|
-
> **Changes que dependem de earlier changes DEVEM ter later timestamps.**
|
|
473
|
-
>
|
|
474
|
-
> Append-only migration history não tolera reordering retroativo. Se você precisa ordenar migration A antes de B mas A tem timestamp mais antigo, **renomeie** A para timestamp posterior a B.
|
|
475
|
-
|
|
476
|
-
### Cuidado canônico — git history
|
|
477
|
-
|
|
478
|
-
Após `mv supabase/migrations/<old>.sql supabase/migrations/<new>.sql`:
|
|
479
|
-
|
|
480
|
-
```bash
|
|
481
|
-
# git detecta como rename (boa preservação de history)
|
|
482
|
-
git status
|
|
483
|
-
# renamed: supabase/migrations/20240106120000_dev_A.sql -> supabase/migrations/20240106140000_dev_A.sql
|
|
484
|
-
|
|
485
|
-
git add supabase/migrations/
|
|
486
|
-
git commit -m "fix: rebase migration dev_A após merge de dev_B em main"
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
### Caveat — se a migration JÁ FOI PUSHADA para preview/staging
|
|
490
|
-
|
|
491
|
-
Se sua migration `dev_A` já foi pushada para preview branch e DAG executou (mesmo se falhou), a tracking table do preview tem registro `20240106120000`. Renomear o arquivo local cria mismatch:
|
|
492
|
-
|
|
493
|
-
- Local folder: `20240106140000_dev_A.sql` (renomeado)
|
|
494
|
-
- Tracking table preview: `20240106120000` (registro antigo)
|
|
495
|
-
|
|
496
|
-
Solução canônica nesse caso:
|
|
497
|
-
|
|
498
|
-
1. Renomear arquivo localmente (passos 1-4 acima)
|
|
499
|
-
2. Close+reopen PR (Pattern 3 — rollback preview) → recria preview branch do zero
|
|
500
|
-
3. Push do branch corrigido → DAG roda com timestamp correto
|
|
501
|
-
|
|
502
|
-
### Quando este pattern NÃO se aplica
|
|
503
|
-
|
|
504
|
-
- Migrations independentes (não há dependência de ordem) — pode ignorar drift, ordem cronológica resolve corretamente
|
|
505
|
-
- Migrations já aplicadas em produção — NÃO renomeie migrations em produção; cria mismatch entre tracking table e folder local. Use forward-only migration de correção.
|
|
506
|
-
|
|
507
|
-
## Pattern 5: Permission denied troubleshooting (REPAIR-05)
|
|
508
|
-
|
|
509
|
-
Dois casos canônicos documentados na doc oficial Supabase — ambos exigem aplicação manual de GRANT via Dashboard SQL Editor.
|
|
510
|
-
|
|
511
|
-
### Caso 1 — db pull erro "permission denied for table _type"
|
|
512
|
-
|
|
513
|
-
#### Erro completo
|
|
514
|
-
|
|
515
|
-
```
|
|
516
|
-
$ supabase db pull
|
|
517
|
-
Error: Error running pg_dump on remote database:
|
|
518
|
-
pg_dump: error: query failed: ERROR: permission denied for table _type
|
|
519
|
-
pg_dump: error: query was: LOCK TABLE "graphql"."_type" IN ACCESS SHARE MODE
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
#### Causa canônica
|
|
523
|
-
|
|
524
|
-
Projetos Supabase **antigos** (criados antes da introdução do GraphQL schema com grants padrão) NÃO têm GRANTs corretos em `graphql._type`. `pg_dump` requer LOCK ACCESS SHARE em todas as tabelas do schema para snapshot consistente — falha sem GRANT.
|
|
525
|
-
|
|
526
|
-
#### Solução canônica
|
|
527
|
-
|
|
528
|
-
Executar no **Dashboard → SQL Editor** (não em migration file porque é one-time fix para schema graphql gerenciado pelo Supabase):
|
|
529
|
-
|
|
530
|
-
```sql
|
|
531
|
-
grant all on all tables in schema graphql to postgres, anon, authenticated, service_role;
|
|
532
|
-
grant all on all functions in schema graphql to postgres, anon, authenticated, service_role;
|
|
533
|
-
grant all on all sequences in schema graphql to postgres, anon, authenticated, service_role;
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
#### Verificação após fix
|
|
537
|
-
|
|
538
|
-
```bash
|
|
539
|
-
supabase db pull
|
|
540
|
-
# Output esperado: "Schema pulled successfully" sem erro de permission denied
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
#### Caveat canônico — projetos novos
|
|
544
|
-
|
|
545
|
-
Projetos criados após 2024 vêm com esses GRANTs configurados automaticamente. Se você está em projeto criado recentemente e ainda recebe esse erro, verifique se há roles customizadas que precisam de GRANT também:
|
|
546
|
-
|
|
547
|
-
```sql
|
|
548
|
-
-- exemplo: se você criou role "data_team_reader" e quer permitir db pull com ela
|
|
549
|
-
grant all on all tables in schema graphql to data_team_reader;
|
|
550
|
-
grant all on all functions in schema graphql to data_team_reader;
|
|
551
|
-
grant all on all sequences in schema graphql to data_team_reader;
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
### Caso 2 — db push erro 42501 com custom role
|
|
555
|
-
|
|
556
|
-
#### Erro completo
|
|
557
|
-
|
|
558
|
-
```
|
|
559
|
-
$ supabase db push
|
|
560
|
-
Applying migration 20240107120000_alter_orders.sql...
|
|
561
|
-
ERROR: permission denied for table orders (SQLSTATE 42501)
|
|
562
|
-
Error: failed to apply migration
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
#### Causa canônica
|
|
566
|
-
|
|
567
|
-
Tabela `orders` foi criada com **custom role** (ex: `app_admin` ou similar) em migration anterior. Quando `supabase db push` executa a próxima migration, o conexão é feita como role `postgres` (default do CLI), e `postgres` NÃO tem permission para modificar a tabela porque o owner é `app_admin`.
|
|
568
|
-
|
|
569
|
-
SQLSTATE `42501` é o código canônico Postgres para "insufficient_privilege". Cross-ref skill `supabase-postgres-roles` (v1.26) para entendimento completo de custom roles.
|
|
570
|
-
|
|
571
|
-
#### Solução canônica
|
|
572
|
-
|
|
573
|
-
Conceder membership do custom role para `postgres`:
|
|
574
|
-
|
|
575
|
-
```sql
|
|
576
|
-
grant "custom_role" to "postgres";
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
Substituindo `custom_role` pelo nome real (ex: `app_admin`, `lead_manager`, etc.):
|
|
580
|
-
|
|
581
|
-
```sql
|
|
582
|
-
-- exemplo concreto
|
|
583
|
-
grant "app_admin" to "postgres";
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
#### Como funciona
|
|
587
|
-
|
|
588
|
-
- `grant "app_admin" to "postgres"` torna `postgres` **membro** do role `app_admin`
|
|
589
|
-
- Por default, roles em Postgres usam INHERIT — `postgres` herda permissions de `app_admin`
|
|
590
|
-
- Agora `postgres` consegue modificar tabelas que têm owner = `app_admin`
|
|
591
|
-
|
|
592
|
-
#### Caveat canônico — INHERIT vs SET ROLE
|
|
593
|
-
|
|
594
|
-
Se `app_admin` foi criado com NOINHERIT (cross-ref skill `supabase-postgres-roles` v1.26 — Pattern 3), simples GRANT membership NÃO é suficiente. `postgres` precisa `SET ROLE app_admin` explicitamente antes de cada operação:
|
|
595
|
-
|
|
596
|
-
```sql
|
|
597
|
-
-- na migration (não recomendado, mas funciona)
|
|
598
|
-
set role app_admin;
|
|
599
|
-
alter table public.orders add column foo text;
|
|
600
|
-
reset role;
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
Solução **preferível** se você está em projeto novo: criar custom roles com INHERIT default (cross-ref skill `supabase-postgres-roles` v1.26 — Pattern 3).
|
|
604
|
-
|
|
605
|
-
#### Quando aplicar este GRANT
|
|
606
|
-
|
|
607
|
-
Aplique **uma única vez** após criar a custom role:
|
|
608
|
-
|
|
609
|
-
```sql
|
|
610
|
-
-- na primeira migration que cria a custom role (cross-ref skill supabase-postgres-roles)
|
|
611
|
-
create role "app_admin" noinherit;
|
|
612
|
-
alter role "app_admin" with bypassrls;
|
|
613
|
-
grant "app_admin" to "postgres"; -- ⚡ esta linha resolve o erro 42501
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
Comments explicativos canônicos na migration:
|
|
617
|
-
|
|
618
|
-
```sql
|
|
619
|
-
-- GRANT membership de app_admin para postgres
|
|
620
|
-
-- Permite que supabase db push (conectado como postgres) modifique tabelas
|
|
621
|
-
-- com owner app_admin sem precisar SET ROLE explícito.
|
|
622
|
-
-- Sem isso: erro SQLSTATE 42501 ao alterar tabela.
|
|
623
|
-
grant "app_admin" to "postgres";
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
### Tabela canônica — erros + soluções
|
|
627
|
-
|
|
628
|
-
| Erro | SQLSTATE | Comando que dispara | Solução canônica |
|
|
629
|
-
|---|---|---|---|
|
|
630
|
-
| `permission denied for table _type` | (sem código) pg_dump error | `supabase db pull` | `grant all on all tables in schema graphql to postgres, anon, authenticated, service_role` |
|
|
631
|
-
| `permission denied for table X` | 42501 | `supabase db push` | `grant "custom_role" to "postgres"` |
|
|
632
|
-
| `relation X already exists` | 42P07 | `supabase db push` | `migration repair --status applied <timestamp>` (Pattern 2) |
|
|
633
|
-
| `relation X does not exist` | 42P01 | `supabase db push` | Verificar ordem de migrations (Pattern 4) ou pull do remote (Pattern 1) |
|
|
634
|
-
|
|
635
|
-
## Anti-patterns
|
|
636
|
-
|
|
637
|
-
### Anti-pattern 1: Usar `migration repair --status reverted` esperando reverter SQL
|
|
638
|
-
|
|
639
|
-
**Errado:**
|
|
640
|
-
|
|
641
|
-
```bash
|
|
642
|
-
# Dev quer "desfazer" CREATE TABLE foo que migration 20240102 criou
|
|
643
|
-
supabase migration repair --status reverted 20240102140000
|
|
644
|
-
# Espera: tabela foo deletada
|
|
645
|
-
# Realidade: apenas registro de tracking table removido — tabela foo continua existindo
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
**Por quê:** `repair` é tracking-table-only. CAVEAT CRÍTICO repetido nesta skill (Pattern 2 + introdução). LLMs e humanos frequentemente assumem semantics de "rollback completo" — incorreto.
|
|
649
|
-
|
|
650
|
-
**Sintoma do bug:** próximo `supabase db push` tenta re-aplicar a migration → falha com `relation "foo" already exists` (SQLSTATE 42P07) → loop infinito de tentativas de repair.
|
|
651
|
-
|
|
652
|
-
**Certo:**
|
|
653
|
-
|
|
654
|
-
```bash
|
|
655
|
-
# Para reverter schema changes reais, crie nova migration
|
|
656
|
-
supabase migration new drop_foo
|
|
657
|
-
# Editar arquivo gerado:
|
|
658
|
-
# drop table if exists public.foo;
|
|
659
|
-
supabase db push
|
|
660
|
-
```
|
|
661
|
-
|
|
662
|
-
### Anti-pattern 2: Schema changes direto no remote bypassing migration files
|
|
663
|
-
|
|
664
|
-
**Errado:**
|
|
665
|
-
|
|
666
|
-
```sql
|
|
667
|
-
-- Dev abre Dashboard → SQL Editor → executa direto no DB remoto:
|
|
668
|
-
create table public.audit_log (
|
|
669
|
-
id uuid primary key default gen_random_uuid(),
|
|
670
|
-
event text not null,
|
|
671
|
-
created_at timestamptz not null default now()
|
|
672
|
-
);
|
|
673
|
-
|
|
674
|
-
-- Sem commit no git, sem migration file, sem registro na tracking table
|
|
675
|
-
```
|
|
676
|
-
|
|
677
|
-
**Por quê:** cria divergência canônica entre schema real (tabela existe) e tracking table (sem registro). Cross-ref Princípio 1. Próximo dev que clonar repo + rodar `supabase db reset` local NÃO terá a tabela.
|
|
678
|
-
|
|
679
|
-
**Sintomas:**
|
|
680
|
-
|
|
681
|
-
- Outros devs reportam "minha app não funciona, tabela audit_log não existe"
|
|
682
|
-
- CI/CD pipeline falha em ambientes novos (preview branches, persistent staging)
|
|
683
|
-
- `supabase db pull` mostra surpresas (tabela "remote-only")
|
|
684
|
-
|
|
685
|
-
**Certo:**
|
|
686
|
-
|
|
687
|
-
```bash
|
|
688
|
-
# 1. Criar migration file via CLI
|
|
689
|
-
supabase migration new create_audit_log
|
|
690
|
-
|
|
691
|
-
# 2. Editar arquivo gerado com SQL (incluindo GRANTs + RLS — cross-ref skill supabase-migrations)
|
|
692
|
-
# supabase/migrations/<timestamp>_create_audit_log.sql
|
|
693
|
-
|
|
694
|
-
# 3. Testar localmente
|
|
695
|
-
supabase db reset
|
|
696
|
-
|
|
697
|
-
# 4. Commit + push + PR (cross-ref skill supabase-branching-workflow Phase 149)
|
|
698
|
-
git add supabase/migrations/
|
|
699
|
-
git commit -m "feat: add audit_log table"
|
|
700
|
-
git push
|
|
701
|
-
# Abre PR → preview branch criado → DAG step 5 valida migration
|
|
702
|
-
```
|
|
703
|
-
|
|
704
|
-
### Anti-pattern 3: Não rebase local antes de db push em equipe
|
|
705
|
-
|
|
706
|
-
**Errado:**
|
|
707
|
-
|
|
708
|
-
```
|
|
709
|
-
Dev A workflow:
|
|
710
|
-
1. Cria branch feature-A com migration 20240106120000_dev_A.sql
|
|
711
|
-
2. NÃO pulla main por 1 semana (dev_B foi merged enquanto isso)
|
|
712
|
-
3. Direto: supabase db push para staging
|
|
713
|
-
4. Resultado: ordem cronológica força dev_A antes de dev_B → falha
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
**Por quê:** ordem cronológica de migrations é determinada por timestamp. Sem rebase, sua migration pode estar "presa" no passado relativo a migrations da equipe.
|
|
717
|
-
|
|
718
|
-
**Sintomas:**
|
|
719
|
-
|
|
720
|
-
- `db push` falha com "relation X does not exist" (FK para tabela que dev_B criou)
|
|
721
|
-
- Staging branch entra em estado "failed" do DAG
|
|
722
|
-
- Production fica em risco de mesma falha se dev fizer merge sem revisão
|
|
723
|
-
|
|
724
|
-
**Certo:**
|
|
725
|
-
|
|
726
|
-
```bash
|
|
727
|
-
# Antes de QUALQUER db push
|
|
728
|
-
git pull origin main
|
|
729
|
-
git rebase main
|
|
730
|
-
|
|
731
|
-
# Se houver conflito de timestamps → aplicar Pattern 4 (rename migration files)
|
|
732
|
-
supabase migration list # diagnose primeiro
|
|
733
|
-
# se mismatch detectado, renomear migration antiga para timestamp atualizado
|
|
734
|
-
|
|
735
|
-
supabase db reset # validar localmente em ordem cronológica correta
|
|
736
|
-
supabase db push # só depois disso
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
### Anti-pattern 4: Concurrent db push from different machines
|
|
740
|
-
|
|
741
|
-
**Errado:**
|
|
742
|
-
|
|
743
|
-
```
|
|
744
|
-
Dev A (machine 1):
|
|
745
|
-
19:00 — supabase db push (target: staging)
|
|
746
|
-
|
|
747
|
-
Dev B (machine 2):
|
|
748
|
-
19:01 — supabase db push (target: staging)
|
|
749
|
-
↓ race condition
|
|
750
|
-
```
|
|
751
|
-
|
|
752
|
-
**Por quê:** dois processos `db push` simultâneos podem ambos detectar a mesma migration como pending → ambos tentam aplicar → race condition na tracking table → pode resultar em registro duplicado OU registro ausente após retry.
|
|
753
|
-
|
|
754
|
-
**Sintomas:**
|
|
755
|
-
|
|
756
|
-
- Tracking table corrompido (duplicate version OU missing version)
|
|
757
|
-
- Migration aplicada parcialmente (algumas statements rodaram, outras não)
|
|
758
|
-
- `supabase migration list` mostra estado inconsistente que não bate com nenhum cenário canônico
|
|
759
|
-
|
|
760
|
-
**Certo:**
|
|
761
|
-
|
|
762
|
-
- **Centralizar `db push` em CI/CD** — apenas pipelines (GitHub Actions, GitLab CI) executam `db push` em ambientes compartilhados (staging, production). Cross-ref skill `supabase-ci-cd-github-actions` (Phase 151).
|
|
763
|
-
- **Lock manual em produção** — se você precisa fazer manual push em production, comunique no canal #release-coordination ANTES (humano lock)
|
|
764
|
-
- **Dev workflow** — devs NUNCA fazem `db push` para staging direto da máquina local; sempre via PR + merge + CI/CD pipeline
|
|
765
|
-
|
|
766
|
-
### Anti-pattern 5: Renomear migrations em produção
|
|
767
|
-
|
|
768
|
-
**Errado:**
|
|
769
|
-
|
|
770
|
-
```bash
|
|
771
|
-
# Production tracking table tem registro 20240106120000
|
|
772
|
-
# Dev renomeia o arquivo local para 20240106140000 (sem entender o impacto)
|
|
773
|
-
mv supabase/migrations/20240106120000_old.sql supabase/migrations/20240106140000_old.sql
|
|
774
|
-
|
|
775
|
-
# Push para production
|
|
776
|
-
supabase db push --target=production
|
|
777
|
-
# ↓ falha: 20240106120000 (registrado) ≠ 20240106140000 (folder)
|
|
778
|
-
```
|
|
779
|
-
|
|
780
|
-
**Por quê:** tracking table em produção é **append-only history**. Renomear arquivos locais cria mismatch irreversível. Diferente de Pattern 4 (rename ANTES de qualquer push), em produção a migration JÁ foi registrada — renomear local é destrutivo.
|
|
781
|
-
|
|
782
|
-
**Sintomas:**
|
|
783
|
-
|
|
784
|
-
- `db push` para production falha permanentemente
|
|
785
|
-
- `migration repair` é necessário para corrigir, mas pode levar a mais bugs se aplicado errado
|
|
786
|
-
- Worst case: rollback de production via point-in-time recovery (custo + downtime)
|
|
787
|
-
|
|
788
|
-
**Certo:**
|
|
789
|
-
|
|
790
|
-
- **Renames de migration são VÁLIDOS apenas se nunca foram aplicados** (preview branch deletado + recriado, ou apenas em folder local sem nenhum push)
|
|
791
|
-
- **Em produção, sempre forward-only**: criar nova migration que desfaz/corrige, nunca renomear histórico
|
|
792
|
-
- **Treinamento de equipe**: documentar este anti-pattern no onboarding; novo dev pode descobrir Pattern 4 e aplicar inadvertidamente em produção
|
|
793
|
-
|
|
794
|
-
## Cross-suite integration (v1.27)
|
|
795
|
-
|
|
796
|
-
Esta skill é o **complemento operacional** das skills v1.27 introduzidas em Phases 149-152:
|
|
797
|
-
|
|
798
|
-
- **`supabase-branching-workflow`** (Phase 149) — quando DAG step 5 (migrate) falha em preview branch, use Pattern 3 (rollback via delete+reopen). Forward-ref de Phase 149 fechado nesta skill.
|
|
799
|
-
- **`supabase-config-toml-remotes`** (Phase 150) — secrets per-branch podem mascarar permission errors se a migration espera env var diferente. Diagnosticar via Pattern 5 quando aplicável.
|
|
800
|
-
- **`supabase-ci-cd-github-actions`** (Phase 151) — pipelines que executam `supabase db push` podem falhar com erros documentados em Pattern 5. Fix one-time via Dashboard SQL editor, depois pipeline funciona.
|
|
801
|
-
- **`supabase-pgtap-testing`** (Phase 152) — tests falhando em CI por schema desatualizado podem indicar tracking table mismatch — diagnose via Pattern 1 antes de assumir bug no test.
|
|
802
|
-
|
|
803
|
-
Esta skill é **standalone** — não cria agent novo. É consumida por:
|
|
804
|
-
|
|
805
|
-
- `supabase-migration-writer` — referencia para ações pós-falha de migration
|
|
806
|
-
- `supabase-rls-writer` (v1.23) — quando RLS depende de schema state que pode estar drifted
|
|
807
|
-
- Agents futuros Phase 154 (`supabase-branching-architect`, `supabase-cicd-pipeline-implementer`) — incorporam diagnóstico Pattern 1 em workflows recomendados
|
|
808
|
-
|
|
809
|
-
Pattern de handoff cooperativo herdado v1.23-v1.26: **architect** projeta workflow → **pipeline-implementer** materializa pipeline → quando falha, **migration-repair** skill é o "kit de emergência" canônico para recovery.
|
|
810
|
-
|
|
811
|
-
## Ver também
|
|
812
|
-
|
|
813
|
-
- [supabase-migrations](../supabase-migrations/SKILL.md) (v1.23) — pattern canônico de migration files (5 blocos obrigatórios + naming)
|
|
814
|
-
- [supabase-branching-workflow](../supabase-branching-workflow/SKILL.md) (v1.27, Phase 149) — preview branch lifecycle + DAG 7 steps + delete+reopen rollback
|
|
815
|
-
- [supabase-config-toml-remotes](../supabase-config-toml-remotes/SKILL.md) (v1.27, Phase 150) — `[remotes]` block + secrets per-branch
|
|
816
|
-
- [supabase-ci-cd-github-actions](../supabase-ci-cd-github-actions/SKILL.md) (v1.27, Phase 151) — 8 workflows canônicos GitHub Actions
|
|
817
|
-
- [supabase-pgtap-testing](../supabase-pgtap-testing/SKILL.md) (v1.27, Phase 152) — testes pgTAP integrados no DAG
|
|
818
|
-
- [supabase-postgres-roles](../supabase-postgres-roles/SKILL.md) (v1.26) — INHERIT/NOINHERIT, GRANT membership, predefined Supabase roles
|
|
819
|
-
- [evolucao-schema-compativel](../evolucao-schema-compativel/SKILL.md) (v1.22) — 3-step migration safe rolling upgrade (expand → migrate data → contract)
|
|
820
|
-
- [supabase-declarative-schema](../supabase-declarative-schema/SKILL.md) — workflow alternativo (declarative-first → diff → migrate)
|
|
821
|
-
- [supabase-rls-policies](../supabase-rls-policies/SKILL.md) (v1.23) — RLS deve ser parte de cada migration nova
|
|
822
|
-
- [glossário compartilhado](../_shared-supabase/glossary.md) — termos canônicos migration repair, tracking table, schema drift, sync error
|
|
823
|
-
- Doc oficial Supabase: [Migration Repair](https://supabase.com/docs/reference/cli/supabase-migration-repair), [Local Development](https://supabase.com/docs/guides/local-development/cli/getting-started), [Branching](https://supabase.com/docs/guides/deployment/branching)
|
|
1
|
+
---
|
|
2
|
+
name: supabase-migration-repair
|
|
3
|
+
description: Use ao diagnosticar e reparar sync errors entre local supabase/migrations/ e remote supabase_migrations.schema_migrations tracking table…
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Supabase — Migration Repair
|
|
7
|
+
|
|
8
|
+
## Quando usar
|
|
9
|
+
|
|
10
|
+
Use esta skill ao enfrentar **sync errors** ou **estado inconsistente** entre o folder local `supabase/migrations/` e a tracking table remota `supabase_migrations.schema_migrations`, ou ao precisar de rollback de preview branch após migration falha.
|
|
11
|
+
|
|
12
|
+
Trigger phrases:
|
|
13
|
+
|
|
14
|
+
- "migration repair", "supabase migration repair"
|
|
15
|
+
- "sync error Supabase", "migration history mismatch"
|
|
16
|
+
- "supabase migration list mostra mismatch"
|
|
17
|
+
- "schema drift Supabase", "git rebase migration timestamps"
|
|
18
|
+
- "permission denied migration", "permission denied for table _type"
|
|
19
|
+
- "permission denied 42501 Supabase", "custom_role to postgres"
|
|
20
|
+
- "rollback preview branch Supabase"
|
|
21
|
+
- "db push falhando re-aplicar migration"
|
|
22
|
+
- "db pull pg_dump error graphql"
|
|
23
|
+
|
|
24
|
+
**Use esta skill APENAS para:**
|
|
25
|
+
|
|
26
|
+
- Diagnosticar mismatch entre folder local e tracking table remoto
|
|
27
|
+
- Corrigir history record em `supabase_migrations.schema_migrations` quando schema state real está OK
|
|
28
|
+
- Rollback de preview branch ephemeral via PR close+reopen (cross-ref skill `supabase-branching-workflow` Phase 149)
|
|
29
|
+
- Resolver drift de timestamps após git rebase em equipe
|
|
30
|
+
- Resolver erros `42501 permission denied` e `pg_dump error permission denied for table _type`
|
|
31
|
+
|
|
32
|
+
**NÃO use esta skill para:**
|
|
33
|
+
|
|
34
|
+
- Reverter mudanças de schema reais — `migration repair` NÃO reverte SQL (cross-ref CAVEAT CRÍTICO abaixo)
|
|
35
|
+
- Substituir testes de migration — preview branch + DAG step 5 (cross-ref skill `supabase-branching-workflow` Phase 149) é o gate canônico
|
|
36
|
+
- Bypassar migration files aplicando schema changes via Dashboard SQL editor — isso CRIA o problema que esta skill diagnostica
|
|
37
|
+
- Recovery de production database com data loss — backup + point-in-time recovery do Supabase (fora do escopo desta skill)
|
|
38
|
+
|
|
39
|
+
## Princípio canônico
|
|
40
|
+
|
|
41
|
+
Três princípios canônicos sustentam toda a skill:
|
|
42
|
+
|
|
43
|
+
### Princípio 1 — Tracking table state ≠ schema state real
|
|
44
|
+
|
|
45
|
+
A tracking table `supabase_migrations.schema_migrations` é um **registro de histórico** de quais migrations foram aplicadas. O **schema state real** é o estado físico do DB (tabelas, colunas, indices, funções, policies).
|
|
46
|
+
|
|
47
|
+
Os dois podem divergir:
|
|
48
|
+
|
|
49
|
+
| Schema real | Tracking table | Causa | Sintoma |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| Tabela `foo` existe | Sem registro 20240102 | Migration aplicada manualmente via Dashboard SQL editor | `db push` tenta re-aplicar 20240102 e falha com "relation foo already exists" |
|
|
52
|
+
| Tabela `foo` NÃO existe | Com registro 20240102 | Tracking table corrupto / migration teve rollback parcial | `db push` skip 20240102 mas tabela ausente |
|
|
53
|
+
| Tabela `foo` existe | Com registro 20240102 | Estado normal — sincronizado | Nenhum |
|
|
54
|
+
| Tabela `foo` NÃO existe | Sem registro 20240102 | Nada aplicado ainda — pendente | `db push` aplica 20240102 normalmente |
|
|
55
|
+
|
|
56
|
+
### Princípio 2 — Diagnose ANTES de repair
|
|
57
|
+
|
|
58
|
+
NUNCA execute `supabase migration repair` sem primeiro rodar `supabase migration list` para entender QUAL migration está em qual estado de mismatch. Repair cego pode mascarar bug + tornar recovery mais difícil.
|
|
59
|
+
|
|
60
|
+
### Princípio 3 — Rollback preview preferível a manual revert
|
|
61
|
+
|
|
62
|
+
Para preview branches Supabase Branching (Phase 149), **delete+reopen do PR** é canônico e seguro. Tentar criar "reverter migration" manualmente para desfazer schema changes em preview branch é anti-pattern — preview branches são ephemeral by design (cross-ref skill `supabase-branching-workflow` Phase 149).
|
|
63
|
+
|
|
64
|
+
## CAVEAT CRÍTICO — Tracking table apenas
|
|
65
|
+
|
|
66
|
+
> **`supabase migration repair` atualiza APENAS a tracking table `supabase_migrations.schema_migrations`. NÃO aplica SQL nem reverte SQL.**
|
|
67
|
+
>
|
|
68
|
+
> Este caveat é repetido **DUAS VEZES** nesta skill (Pattern 2 + abaixo) porque é a fonte #1 de bugs em recovery de migrations Supabase. LLMs e humanos frequentemente assumem que `repair --status reverted` "desfaz" a migration — **NÃO DESFAZ**.
|
|
69
|
+
>
|
|
70
|
+
> Se a migration realmente alterou schema (criou tabela, alterou coluna, etc.), `repair --status reverted` APENAS remove o registro do histórico. As mudanças físicas no DB **permanecem**. Para reverter mudanças de schema reais:
|
|
71
|
+
>
|
|
72
|
+
> 1. Criar **nova migration** que desfaz as mudanças (`drop table ...`, `alter table ... drop column ...`)
|
|
73
|
+
> 2. Aplicar via `supabase db push`
|
|
74
|
+
> 3. NÃO usar `repair --status reverted` esperando reverter SQL
|
|
75
|
+
|
|
76
|
+
## Pattern 1: Diagnóstico via `supabase migration list` (REPAIR-01)
|
|
77
|
+
|
|
78
|
+
Primeira ação canônica em qualquer cenário de migration error — **sempre** começar por aqui.
|
|
79
|
+
|
|
80
|
+
### Comando
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
supabase migration list
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Output canônico
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
LOCAL │ REMOTE │ TIME (UTC)
|
|
90
|
+
─────────────────────┼────────────────┼─────────────────────
|
|
91
|
+
20240101120000 │ 20240101120000 │ 2024-01-01 12:00:00
|
|
92
|
+
20240102140000 │ - │ 2024-01-02 14:00:00
|
|
93
|
+
- │ 20240103160000 │ 2024-01-03 16:00:00
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Interpretação canônica das 3 colunas
|
|
97
|
+
|
|
98
|
+
| Coluna | Significado |
|
|
99
|
+
|---|---|
|
|
100
|
+
| **LOCAL** | Timestamp encontrado em `supabase/migrations/*.sql` (folder local do repo git) |
|
|
101
|
+
| **REMOTE** | Timestamp registrado em `supabase_migrations.schema_migrations` (tracking table no DB remoto) |
|
|
102
|
+
| **TIME (UTC)** | Quando foi aplicada (presente apenas quando coluna REMOTE tem valor) |
|
|
103
|
+
|
|
104
|
+
### 3 estados canônicos por linha
|
|
105
|
+
|
|
106
|
+
**Estado 1: sincronizado**
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
20240101120000 │ 20240101120000 │ 2024-01-01 12:00:00
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Migration presente em ambos — estado **normal**, nenhuma ação necessária.
|
|
113
|
+
|
|
114
|
+
**Estado 2: local-only (pending push)**
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
20240102140000 │ - │ 2024-01-02 14:00:00
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Migration existe no folder local mas NÃO foi aplicada no remote. Ação canônica:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
supabase db push
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Aplica migrations pendentes em ordem cronológica.
|
|
127
|
+
|
|
128
|
+
**Estado 3: remote-only (drift)**
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
- │ 20240103160000 │ 2024-01-03 16:00:00
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Migration foi aplicada no remote (registrada na tracking table) MAS o arquivo `.sql` correspondente NÃO existe no folder local. Causas possíveis:
|
|
135
|
+
|
|
136
|
+
- Migration aplicada manualmente via Dashboard SQL editor sem commit no git
|
|
137
|
+
- Outro dev aplicou migration e ainda não pushou para git remoto
|
|
138
|
+
- Arquivo local foi deletado por engano
|
|
139
|
+
|
|
140
|
+
Ação canônica:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
supabase db pull
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Gera arquivo `.sql` local correspondente à migration registrada no remote. Sincroniza folder local com tracking table.
|
|
147
|
+
|
|
148
|
+
### Comportamento canônico de `supabase db push`
|
|
149
|
+
|
|
150
|
+
`supabase db push` compara local folder vs remote tracking table:
|
|
151
|
+
|
|
152
|
+
1. Lista migrations em `supabase/migrations/*.sql` (folder local)
|
|
153
|
+
2. Lista migrations em `supabase_migrations.schema_migrations` (tracking table)
|
|
154
|
+
3. Calcula diff: migrations no folder MAS não na tracking table
|
|
155
|
+
4. Aplica em ordem cronológica (por timestamp) — registra cada uma na tracking table após sucesso
|
|
156
|
+
|
|
157
|
+
**Caveat — tracking table é fonte de verdade para "o que foi aplicado":**
|
|
158
|
+
|
|
159
|
+
Se você deleta o folder local, `db push` NÃO re-aplica migrations já registradas na tracking table. Para forçar re-aplicação, precisa:
|
|
160
|
+
|
|
161
|
+
1. `db pull` para regenerar folder local a partir do remote, OU
|
|
162
|
+
2. `migration repair --status reverted <timestamp>` para remover o registro da tracking table (CAVEAT CRÍTICO repetido — isso só remove o registro, NÃO reverte schema)
|
|
163
|
+
|
|
164
|
+
### Estrutura interna da tracking table
|
|
165
|
+
|
|
166
|
+
```sql
|
|
167
|
+
-- estrutura canônica da tracking table (não modificar manualmente)
|
|
168
|
+
\d supabase_migrations.schema_migrations
|
|
169
|
+
|
|
170
|
+
Column │ Type
|
|
171
|
+
──────────────────┼─────────────────────────
|
|
172
|
+
version │ text NOT NULL PRIMARY KEY
|
|
173
|
+
name │ text
|
|
174
|
+
statements │ text[]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
- `version` — timestamp da migration (PK)
|
|
178
|
+
- `name` — descrição da migration
|
|
179
|
+
- `statements` — array com SQL aplicado (audit trail)
|
|
180
|
+
|
|
181
|
+
**NUNCA modifique esta tabela diretamente.** Use `migration repair` (Pattern 2) para mutação segura via CLI.
|
|
182
|
+
|
|
183
|
+
## Pattern 2: `migration repair --status applied|reverted` (REPAIR-02)
|
|
184
|
+
|
|
185
|
+
> **CAVEAT CRÍTICO REPETIDO — tracking table apenas:**
|
|
186
|
+
>
|
|
187
|
+
> `supabase migration repair` atualiza APENAS a tracking table `supabase_migrations.schema_migrations`. **NÃO aplica SQL nem reverte SQL.**
|
|
188
|
+
>
|
|
189
|
+
> Se a migration realmente alterou schema, `repair --status reverted` remove o registro do histórico MAS as mudanças físicas no DB **permanecem**. Para reverter schema changes reais, crie nova migration via `supabase migration new`.
|
|
190
|
+
|
|
191
|
+
### Sintaxe canônica
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
supabase migration repair --status <applied|reverted> <migration-timestamp>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Dois subcomandos canônicos:
|
|
198
|
+
|
|
199
|
+
- `--status applied <timestamp>` — adiciona registro à tracking table (marca como aplicada)
|
|
200
|
+
- `--status reverted <timestamp>` — remove registro da tracking table (marca como reverted)
|
|
201
|
+
|
|
202
|
+
### Caso 1 — Migration aplicada manualmente (precisa marcar como applied)
|
|
203
|
+
|
|
204
|
+
**Cenário:**
|
|
205
|
+
|
|
206
|
+
- Dev abriu Dashboard → SQL editor → executou `CREATE TABLE foo (...)` direto no DB remoto
|
|
207
|
+
- Schema state OK (tabela existe), mas tracking table NÃO tem registro
|
|
208
|
+
- Posteriormente, dev criou migration `20240102_create_foo.sql` no folder local com o mesmo SQL
|
|
209
|
+
- `supabase db push` lista migration como pending → tenta aplicar → falha com `relation "foo" already exists`
|
|
210
|
+
|
|
211
|
+
**Diagnóstico:**
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
supabase migration list
|
|
215
|
+
# Output:
|
|
216
|
+
# 20240102140000 │ - │ 2024-01-02 14:00:00
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Confirma migration está local-only — porém schema state real tem a tabela. Repair canônico:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
supabase migration repair --status applied 20240102140000
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**O que acontece:**
|
|
226
|
+
|
|
227
|
+
- Tracking table recebe novo registro: `INSERT INTO supabase_migrations.schema_migrations (version, name) VALUES ('20240102140000', 'create_foo')`
|
|
228
|
+
- Schema state físico NÃO é alterado (tabela `foo` continua existindo, sem nenhuma operação SQL extra)
|
|
229
|
+
- Próximo `supabase migration list` mostra migration sincronizada
|
|
230
|
+
|
|
231
|
+
**Quando usar este caso:**
|
|
232
|
+
|
|
233
|
+
- Hotfix aplicado emergencialmente via Dashboard SQL editor sem migration file
|
|
234
|
+
- Migration aplicada manualmente em ambiente novo (ex: replicar schema de produção)
|
|
235
|
+
- Schema gerado por ferramenta externa (Drizzle, Prisma) onde tracking table está fora de sync
|
|
236
|
+
|
|
237
|
+
### Caso 2 — Migration registrada mas nunca aplicada (precisa marcar como reverted)
|
|
238
|
+
|
|
239
|
+
**Cenário:**
|
|
240
|
+
|
|
241
|
+
- Tracking table tem registro `20240102140000` MAS schema state real NÃO tem a tabela criada por essa migration
|
|
242
|
+
- Causas possíveis: tracking table corrupto, migration teve rollback parcial, restore parcial de backup
|
|
243
|
+
|
|
244
|
+
**Diagnóstico:**
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
supabase migration list
|
|
248
|
+
# Output:
|
|
249
|
+
# 20240102140000 │ 20240102140000 │ 2024-01-02 14:00:00
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Aparenta sincronizado, mas tabela não existe. Confirmar via:
|
|
253
|
+
|
|
254
|
+
```sql
|
|
255
|
+
-- conectar via psql ou Dashboard SQL editor
|
|
256
|
+
select table_name from information_schema.tables where table_schema = 'public' and table_name = 'foo';
|
|
257
|
+
-- 0 rows
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Repair canônico:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
supabase migration repair --status reverted 20240102140000
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**O que acontece:**
|
|
267
|
+
|
|
268
|
+
- Tracking table tem registro DELETADO: `DELETE FROM supabase_migrations.schema_migrations WHERE version = '20240102140000'`
|
|
269
|
+
- Schema state físico NÃO é alterado (tabela `foo` continua não existindo — `repair` não cria nada)
|
|
270
|
+
- `supabase db push` agora considera migration como pending → aplica normalmente
|
|
271
|
+
|
|
272
|
+
**Quando usar este caso:**
|
|
273
|
+
|
|
274
|
+
- Tracking table está fora de sync por motivo desconhecido
|
|
275
|
+
- Migration tem registro mas schema state real não reflete (tabela ausente, coluna ausente, etc.)
|
|
276
|
+
- Precisa "forçar" re-aplicação de migration via `db push` após confirmar que schema real não tem as mudanças
|
|
277
|
+
|
|
278
|
+
### Anti-uso CRÍTICO — não usar para reverter schema
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# ERRADO — esperar que isso reverta a tabela criada pela migration
|
|
282
|
+
supabase migration repair --status reverted 20240102140000
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Por quê:** apenas remove o registro. A tabela `foo` continua existindo. Próximo `supabase db push` vai tentar aplicar a migration novamente, falhar com `relation already exists`, e você fica em loop infinito.
|
|
286
|
+
|
|
287
|
+
**Certo — para reverter schema changes reais:**
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# 1. Criar nova migration que desfaz as mudanças
|
|
291
|
+
supabase migration new drop_foo
|
|
292
|
+
|
|
293
|
+
# 2. Editar arquivo gerado supabase/migrations/<novo-timestamp>_drop_foo.sql:
|
|
294
|
+
# drop table if exists public.foo;
|
|
295
|
+
|
|
296
|
+
# 3. Aplicar
|
|
297
|
+
supabase db push
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Fluxograma canônico de decisão
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
Sync error em supabase migration list?
|
|
304
|
+
│
|
|
305
|
+
├─ Local-only (LOCAL=X, REMOTE=-)
|
|
306
|
+
│ │
|
|
307
|
+
│ ├─ Schema real TEM as mudanças?
|
|
308
|
+
│ │ ├─ SIM → repair --status applied <X>
|
|
309
|
+
│ │ └─ NÃO → supabase db push (aplicação normal)
|
|
310
|
+
│ │
|
|
311
|
+
│
|
|
312
|
+
├─ Remote-only (LOCAL=-, REMOTE=Y)
|
|
313
|
+
│ │
|
|
314
|
+
│ ├─ Schema real TEM as mudanças?
|
|
315
|
+
│ │ ├─ SIM → supabase db pull (regenera arquivo local)
|
|
316
|
+
│ │ └─ NÃO → repair --status reverted <Y> (limpa registro órfão)
|
|
317
|
+
│
|
|
318
|
+
└─ Aparenta sincronizado mas erros persistem
|
|
319
|
+
│
|
|
320
|
+
├─ Conectar via psql + verificar schema state real
|
|
321
|
+
└─ Decidir entre repair vs nova migration baseado em estado
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Pattern 3: Rollback preview branch via delete + reopen (REPAIR-03)
|
|
325
|
+
|
|
326
|
+
Quando uma migration ruim foi pushada para preview branch Supabase Branching e DAG falhou no step 5 (migrate), o **canônico** é NÃO criar reverter migration — use rollback via PR close+reopen.
|
|
327
|
+
|
|
328
|
+
### Workflow canônico (5 passos)
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
1. Dev pusha migration ruim em PR
|
|
332
|
+
↓
|
|
333
|
+
2. Supabase webhook → DAG step 5 (migrate) FALHA
|
|
334
|
+
↓ status no PR: "Supabase Preview ✗"
|
|
335
|
+
↓
|
|
336
|
+
3. Dev fecha PR (GitHub UI: "Close pull request")
|
|
337
|
+
↓
|
|
338
|
+
4. Supabase Branching detecta PR closed → DELETA preview branch
|
|
339
|
+
↓ (cleanup completo: DB, Edge Functions, Storage config)
|
|
340
|
+
↓
|
|
341
|
+
5. Dev fixa migration + reopen PR (GitHub UI: "Reopen pull request")
|
|
342
|
+
↓
|
|
343
|
+
6. Supabase Branching detecta PR reopened → CRIA novo preview branch
|
|
344
|
+
↓ DAG roda steps 1-7 do zero com migration corrigida
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Equivalência canônica
|
|
348
|
+
|
|
349
|
+
**Delete preview branch + reopen** = **`supabase db reset` local**.
|
|
350
|
+
|
|
351
|
+
Ambos:
|
|
352
|
+
|
|
353
|
+
- Limpam DB state completamente
|
|
354
|
+
- Re-executam todas migrations em ordem cronológica
|
|
355
|
+
- Re-aplicam `supabase/seed.sql`
|
|
356
|
+
- Resetam Edge Functions para versão atual do branch git
|
|
357
|
+
|
|
358
|
+
### Caveats canônicos
|
|
359
|
+
|
|
360
|
+
**Caveat 1 — Data changes adicionais SÃO PERDIDOS**
|
|
361
|
+
|
|
362
|
+
`seed.sql` é re-aplicado como dataless setup. Quaisquer rows inseridas/atualizadas manualmente durante uso do preview branch:
|
|
363
|
+
|
|
364
|
+
- Via Dashboard Table editor
|
|
365
|
+
- Via testes manuais (insert, update direto)
|
|
366
|
+
- Via Edge Function execution (que escreveu em tabelas)
|
|
367
|
+
|
|
368
|
+
**são perdidas** no reset. Aceito como trade-off canônico para reset limpo — preview branches são ephemeral by design (cross-ref skill `supabase-branching-workflow` Phase 149).
|
|
369
|
+
|
|
370
|
+
**Caveat 2 — Auto-pause em inatividade NÃO substitui reset**
|
|
371
|
+
|
|
372
|
+
Preview branches auto-pausam após inatividade (~24h sem requests), mas isso preserva o state. NÃO é equivalente a reset. Para limpeza real, sempre use close+reopen.
|
|
373
|
+
|
|
374
|
+
**Caveat 3 — Branching Compute Hours acumulam novamente**
|
|
375
|
+
|
|
376
|
+
Reopen recria preview branch do zero → nova hora de Branching Compute Hours é cobrada (cross-ref skill `supabase-branching-workflow` Phase 149 — Pattern 5 custo). Se rollback acontece 5× para o mesmo PR, são 5 horas extras cobradas. Considere disciplina: testar migration localmente antes de push.
|
|
377
|
+
|
|
378
|
+
### Quando usar este pattern
|
|
379
|
+
|
|
380
|
+
- Migration ruim foi pushada para preview branch
|
|
381
|
+
- DAG step 5 (migrate) falhou — sem possibilidade de recovery via re-push (porque o branch já está em estado "failed")
|
|
382
|
+
- Você quer voltar ao estado limpo sem aplicar reverter migration manualmente
|
|
383
|
+
- Aceita perda de data changes adicionais que não estavam em seed.sql
|
|
384
|
+
|
|
385
|
+
### Quando NÃO usar este pattern
|
|
386
|
+
|
|
387
|
+
- Persistent branches (staging/QA) — NÃO use delete+reopen; persistent branches são long-lived (cross-ref skill `supabase-branching-workflow` Phase 149 — Pattern 1)
|
|
388
|
+
- Production project — production NUNCA tem rollback via "close PR" — use migration de reversão + `db push` + cuidados extras (backup + monitoramento)
|
|
389
|
+
- Quando você precisa preservar data changes — não há recovery dos dados após delete
|
|
390
|
+
|
|
391
|
+
### Workflow alternativo: push corrected migration
|
|
392
|
+
|
|
393
|
+
Se o branch ainda está em estado "failed" mas branch ainda existe (PR não foi fechado):
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
1. Identificar root cause via Dashboard → branch deployment logs (step 5 stderr)
|
|
397
|
+
2. Corrigir migration localmente
|
|
398
|
+
3. git commit + git push (mesmo PR)
|
|
399
|
+
4. Supabase webhook detecta push → re-run DAG do step 1
|
|
400
|
+
5. Se passa step 5 → step 6 (seed) e step 7 (deploy) executam
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Este workflow é **preferível** se o erro foi simples (typo, syntax error) — evita Branching Compute Hours extras do reset.
|
|
404
|
+
|
|
405
|
+
## Pattern 4: Schema drift após git rebase (REPAIR-04)
|
|
406
|
+
|
|
407
|
+
Cenário canônico em equipes que mergem migrations em paralelo via PRs em main.
|
|
408
|
+
|
|
409
|
+
### Problema canônico
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
Timeline:
|
|
413
|
+
T = Dev A cria PR-A com migration 20240106120000_dev_A.sql
|
|
414
|
+
T+1 = Dev B cria PR-B com migration 20240106130000_dev_B.sql
|
|
415
|
+
T+2 = PR-B é merged primeiro (dev_B agora está em main)
|
|
416
|
+
T+3 = Dev A faz git pull origin main → traz dev_B
|
|
417
|
+
T+4 = Dev A faz git rebase main em sua branch
|
|
418
|
+
T+5 = Estado: branch de Dev A tem dev_B (timestamp 13:00) + dev_A (timestamp 12:00)
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
**Problema:** após rebase, Dev A tem migrations em ordem:
|
|
422
|
+
|
|
423
|
+
```
|
|
424
|
+
supabase/migrations/
|
|
425
|
+
├── 20240106120000_dev_A.sql (mais antiga)
|
|
426
|
+
├── 20240106130000_dev_B.sql (mais nova)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Local `supabase db reset` aplica em ordem cronológica:
|
|
430
|
+
|
|
431
|
+
1. Aplica `20240106120000_dev_A.sql` PRIMEIRO
|
|
432
|
+
2. Aplica `20240106130000_dev_B.sql` DEPOIS
|
|
433
|
+
|
|
434
|
+
Se `dev_A` depende de schema state que só existe APÓS `dev_B` (ex: dev_A adiciona FK para tabela que dev_B criou), `supabase db reset` falha.
|
|
435
|
+
|
|
436
|
+
**Pior:** quando `db push` para production, ordem cronológica força dev_A primeiro → falha em produção.
|
|
437
|
+
|
|
438
|
+
### Solução canônica (4 passos)
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Passo 1: Pull main (traz migrations recentes da equipe)
|
|
442
|
+
git pull origin main
|
|
443
|
+
|
|
444
|
+
# Passo 2: Criar nova migration com timestamp atualizado (placeholder)
|
|
445
|
+
supabase migration new dev_A
|
|
446
|
+
# Cria: supabase/migrations/20240106140000_dev_A.sql (timestamp ATUAL, mais novo)
|
|
447
|
+
|
|
448
|
+
# Passo 3: Renomear migration antiga para o novo timestamp
|
|
449
|
+
mv supabase/migrations/20240106120000_dev_A.sql supabase/migrations/20240106140000_dev_A.sql
|
|
450
|
+
|
|
451
|
+
# (Passo 2 criou arquivo vazio; passo 3 sobrescreve com conteúdo correto)
|
|
452
|
+
|
|
453
|
+
# Passo 4: Reset local para reaplicar tudo em ordem cronológica correta
|
|
454
|
+
supabase db reset
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Resultado final
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
supabase/migrations/
|
|
461
|
+
├── 20240106130000_dev_B.sql (do teammate, vem primeiro)
|
|
462
|
+
├── 20240106140000_dev_A.sql (renomeada com timestamp posterior, vem depois)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
`supabase db reset` aplica em ordem correta:
|
|
466
|
+
|
|
467
|
+
1. Aplica `20240106130000_dev_B.sql` (tabela criada por dev_B)
|
|
468
|
+
2. Aplica `20240106140000_dev_A.sql` (FK funciona porque tabela já existe)
|
|
469
|
+
|
|
470
|
+
### Princípio canônico
|
|
471
|
+
|
|
472
|
+
> **Changes que dependem de earlier changes DEVEM ter later timestamps.**
|
|
473
|
+
>
|
|
474
|
+
> Append-only migration history não tolera reordering retroativo. Se você precisa ordenar migration A antes de B mas A tem timestamp mais antigo, **renomeie** A para timestamp posterior a B.
|
|
475
|
+
|
|
476
|
+
### Cuidado canônico — git history
|
|
477
|
+
|
|
478
|
+
Após `mv supabase/migrations/<old>.sql supabase/migrations/<new>.sql`:
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
# git detecta como rename (boa preservação de history)
|
|
482
|
+
git status
|
|
483
|
+
# renamed: supabase/migrations/20240106120000_dev_A.sql -> supabase/migrations/20240106140000_dev_A.sql
|
|
484
|
+
|
|
485
|
+
git add supabase/migrations/
|
|
486
|
+
git commit -m "fix: rebase migration dev_A após merge de dev_B em main"
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Caveat — se a migration JÁ FOI PUSHADA para preview/staging
|
|
490
|
+
|
|
491
|
+
Se sua migration `dev_A` já foi pushada para preview branch e DAG executou (mesmo se falhou), a tracking table do preview tem registro `20240106120000`. Renomear o arquivo local cria mismatch:
|
|
492
|
+
|
|
493
|
+
- Local folder: `20240106140000_dev_A.sql` (renomeado)
|
|
494
|
+
- Tracking table preview: `20240106120000` (registro antigo)
|
|
495
|
+
|
|
496
|
+
Solução canônica nesse caso:
|
|
497
|
+
|
|
498
|
+
1. Renomear arquivo localmente (passos 1-4 acima)
|
|
499
|
+
2. Close+reopen PR (Pattern 3 — rollback preview) → recria preview branch do zero
|
|
500
|
+
3. Push do branch corrigido → DAG roda com timestamp correto
|
|
501
|
+
|
|
502
|
+
### Quando este pattern NÃO se aplica
|
|
503
|
+
|
|
504
|
+
- Migrations independentes (não há dependência de ordem) — pode ignorar drift, ordem cronológica resolve corretamente
|
|
505
|
+
- Migrations já aplicadas em produção — NÃO renomeie migrations em produção; cria mismatch entre tracking table e folder local. Use forward-only migration de correção.
|
|
506
|
+
|
|
507
|
+
## Pattern 5: Permission denied troubleshooting (REPAIR-05)
|
|
508
|
+
|
|
509
|
+
Dois casos canônicos documentados na doc oficial Supabase — ambos exigem aplicação manual de GRANT via Dashboard SQL Editor.
|
|
510
|
+
|
|
511
|
+
### Caso 1 — db pull erro "permission denied for table _type"
|
|
512
|
+
|
|
513
|
+
#### Erro completo
|
|
514
|
+
|
|
515
|
+
```
|
|
516
|
+
$ supabase db pull
|
|
517
|
+
Error: Error running pg_dump on remote database:
|
|
518
|
+
pg_dump: error: query failed: ERROR: permission denied for table _type
|
|
519
|
+
pg_dump: error: query was: LOCK TABLE "graphql"."_type" IN ACCESS SHARE MODE
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### Causa canônica
|
|
523
|
+
|
|
524
|
+
Projetos Supabase **antigos** (criados antes da introdução do GraphQL schema com grants padrão) NÃO têm GRANTs corretos em `graphql._type`. `pg_dump` requer LOCK ACCESS SHARE em todas as tabelas do schema para snapshot consistente — falha sem GRANT.
|
|
525
|
+
|
|
526
|
+
#### Solução canônica
|
|
527
|
+
|
|
528
|
+
Executar no **Dashboard → SQL Editor** (não em migration file porque é one-time fix para schema graphql gerenciado pelo Supabase):
|
|
529
|
+
|
|
530
|
+
```sql
|
|
531
|
+
grant all on all tables in schema graphql to postgres, anon, authenticated, service_role;
|
|
532
|
+
grant all on all functions in schema graphql to postgres, anon, authenticated, service_role;
|
|
533
|
+
grant all on all sequences in schema graphql to postgres, anon, authenticated, service_role;
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
#### Verificação após fix
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
supabase db pull
|
|
540
|
+
# Output esperado: "Schema pulled successfully" sem erro de permission denied
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
#### Caveat canônico — projetos novos
|
|
544
|
+
|
|
545
|
+
Projetos criados após 2024 vêm com esses GRANTs configurados automaticamente. Se você está em projeto criado recentemente e ainda recebe esse erro, verifique se há roles customizadas que precisam de GRANT também:
|
|
546
|
+
|
|
547
|
+
```sql
|
|
548
|
+
-- exemplo: se você criou role "data_team_reader" e quer permitir db pull com ela
|
|
549
|
+
grant all on all tables in schema graphql to data_team_reader;
|
|
550
|
+
grant all on all functions in schema graphql to data_team_reader;
|
|
551
|
+
grant all on all sequences in schema graphql to data_team_reader;
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Caso 2 — db push erro 42501 com custom role
|
|
555
|
+
|
|
556
|
+
#### Erro completo
|
|
557
|
+
|
|
558
|
+
```
|
|
559
|
+
$ supabase db push
|
|
560
|
+
Applying migration 20240107120000_alter_orders.sql...
|
|
561
|
+
ERROR: permission denied for table orders (SQLSTATE 42501)
|
|
562
|
+
Error: failed to apply migration
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
#### Causa canônica
|
|
566
|
+
|
|
567
|
+
Tabela `orders` foi criada com **custom role** (ex: `app_admin` ou similar) em migration anterior. Quando `supabase db push` executa a próxima migration, o conexão é feita como role `postgres` (default do CLI), e `postgres` NÃO tem permission para modificar a tabela porque o owner é `app_admin`.
|
|
568
|
+
|
|
569
|
+
SQLSTATE `42501` é o código canônico Postgres para "insufficient_privilege". Cross-ref skill `supabase-postgres-roles` (v1.26) para entendimento completo de custom roles.
|
|
570
|
+
|
|
571
|
+
#### Solução canônica
|
|
572
|
+
|
|
573
|
+
Conceder membership do custom role para `postgres`:
|
|
574
|
+
|
|
575
|
+
```sql
|
|
576
|
+
grant "custom_role" to "postgres";
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Substituindo `custom_role` pelo nome real (ex: `app_admin`, `lead_manager`, etc.):
|
|
580
|
+
|
|
581
|
+
```sql
|
|
582
|
+
-- exemplo concreto
|
|
583
|
+
grant "app_admin" to "postgres";
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### Como funciona
|
|
587
|
+
|
|
588
|
+
- `grant "app_admin" to "postgres"` torna `postgres` **membro** do role `app_admin`
|
|
589
|
+
- Por default, roles em Postgres usam INHERIT — `postgres` herda permissions de `app_admin`
|
|
590
|
+
- Agora `postgres` consegue modificar tabelas que têm owner = `app_admin`
|
|
591
|
+
|
|
592
|
+
#### Caveat canônico — INHERIT vs SET ROLE
|
|
593
|
+
|
|
594
|
+
Se `app_admin` foi criado com NOINHERIT (cross-ref skill `supabase-postgres-roles` v1.26 — Pattern 3), simples GRANT membership NÃO é suficiente. `postgres` precisa `SET ROLE app_admin` explicitamente antes de cada operação:
|
|
595
|
+
|
|
596
|
+
```sql
|
|
597
|
+
-- na migration (não recomendado, mas funciona)
|
|
598
|
+
set role app_admin;
|
|
599
|
+
alter table public.orders add column foo text;
|
|
600
|
+
reset role;
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
Solução **preferível** se você está em projeto novo: criar custom roles com INHERIT default (cross-ref skill `supabase-postgres-roles` v1.26 — Pattern 3).
|
|
604
|
+
|
|
605
|
+
#### Quando aplicar este GRANT
|
|
606
|
+
|
|
607
|
+
Aplique **uma única vez** após criar a custom role:
|
|
608
|
+
|
|
609
|
+
```sql
|
|
610
|
+
-- na primeira migration que cria a custom role (cross-ref skill supabase-postgres-roles)
|
|
611
|
+
create role "app_admin" noinherit;
|
|
612
|
+
alter role "app_admin" with bypassrls;
|
|
613
|
+
grant "app_admin" to "postgres"; -- ⚡ esta linha resolve o erro 42501
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
Comments explicativos canônicos na migration:
|
|
617
|
+
|
|
618
|
+
```sql
|
|
619
|
+
-- GRANT membership de app_admin para postgres
|
|
620
|
+
-- Permite que supabase db push (conectado como postgres) modifique tabelas
|
|
621
|
+
-- com owner app_admin sem precisar SET ROLE explícito.
|
|
622
|
+
-- Sem isso: erro SQLSTATE 42501 ao alterar tabela.
|
|
623
|
+
grant "app_admin" to "postgres";
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### Tabela canônica — erros + soluções
|
|
627
|
+
|
|
628
|
+
| Erro | SQLSTATE | Comando que dispara | Solução canônica |
|
|
629
|
+
|---|---|---|---|
|
|
630
|
+
| `permission denied for table _type` | (sem código) pg_dump error | `supabase db pull` | `grant all on all tables in schema graphql to postgres, anon, authenticated, service_role` |
|
|
631
|
+
| `permission denied for table X` | 42501 | `supabase db push` | `grant "custom_role" to "postgres"` |
|
|
632
|
+
| `relation X already exists` | 42P07 | `supabase db push` | `migration repair --status applied <timestamp>` (Pattern 2) |
|
|
633
|
+
| `relation X does not exist` | 42P01 | `supabase db push` | Verificar ordem de migrations (Pattern 4) ou pull do remote (Pattern 1) |
|
|
634
|
+
|
|
635
|
+
## Anti-patterns
|
|
636
|
+
|
|
637
|
+
### Anti-pattern 1: Usar `migration repair --status reverted` esperando reverter SQL
|
|
638
|
+
|
|
639
|
+
**Errado:**
|
|
640
|
+
|
|
641
|
+
```bash
|
|
642
|
+
# Dev quer "desfazer" CREATE TABLE foo que migration 20240102 criou
|
|
643
|
+
supabase migration repair --status reverted 20240102140000
|
|
644
|
+
# Espera: tabela foo deletada
|
|
645
|
+
# Realidade: apenas registro de tracking table removido — tabela foo continua existindo
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Por quê:** `repair` é tracking-table-only. CAVEAT CRÍTICO repetido nesta skill (Pattern 2 + introdução). LLMs e humanos frequentemente assumem semantics de "rollback completo" — incorreto.
|
|
649
|
+
|
|
650
|
+
**Sintoma do bug:** próximo `supabase db push` tenta re-aplicar a migration → falha com `relation "foo" already exists` (SQLSTATE 42P07) → loop infinito de tentativas de repair.
|
|
651
|
+
|
|
652
|
+
**Certo:**
|
|
653
|
+
|
|
654
|
+
```bash
|
|
655
|
+
# Para reverter schema changes reais, crie nova migration
|
|
656
|
+
supabase migration new drop_foo
|
|
657
|
+
# Editar arquivo gerado:
|
|
658
|
+
# drop table if exists public.foo;
|
|
659
|
+
supabase db push
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Anti-pattern 2: Schema changes direto no remote bypassing migration files
|
|
663
|
+
|
|
664
|
+
**Errado:**
|
|
665
|
+
|
|
666
|
+
```sql
|
|
667
|
+
-- Dev abre Dashboard → SQL Editor → executa direto no DB remoto:
|
|
668
|
+
create table public.audit_log (
|
|
669
|
+
id uuid primary key default gen_random_uuid(),
|
|
670
|
+
event text not null,
|
|
671
|
+
created_at timestamptz not null default now()
|
|
672
|
+
);
|
|
673
|
+
|
|
674
|
+
-- Sem commit no git, sem migration file, sem registro na tracking table
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
**Por quê:** cria divergência canônica entre schema real (tabela existe) e tracking table (sem registro). Cross-ref Princípio 1. Próximo dev que clonar repo + rodar `supabase db reset` local NÃO terá a tabela.
|
|
678
|
+
|
|
679
|
+
**Sintomas:**
|
|
680
|
+
|
|
681
|
+
- Outros devs reportam "minha app não funciona, tabela audit_log não existe"
|
|
682
|
+
- CI/CD pipeline falha em ambientes novos (preview branches, persistent staging)
|
|
683
|
+
- `supabase db pull` mostra surpresas (tabela "remote-only")
|
|
684
|
+
|
|
685
|
+
**Certo:**
|
|
686
|
+
|
|
687
|
+
```bash
|
|
688
|
+
# 1. Criar migration file via CLI
|
|
689
|
+
supabase migration new create_audit_log
|
|
690
|
+
|
|
691
|
+
# 2. Editar arquivo gerado com SQL (incluindo GRANTs + RLS — cross-ref skill supabase-migrations)
|
|
692
|
+
# supabase/migrations/<timestamp>_create_audit_log.sql
|
|
693
|
+
|
|
694
|
+
# 3. Testar localmente
|
|
695
|
+
supabase db reset
|
|
696
|
+
|
|
697
|
+
# 4. Commit + push + PR (cross-ref skill supabase-branching-workflow Phase 149)
|
|
698
|
+
git add supabase/migrations/
|
|
699
|
+
git commit -m "feat: add audit_log table"
|
|
700
|
+
git push
|
|
701
|
+
# Abre PR → preview branch criado → DAG step 5 valida migration
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### Anti-pattern 3: Não rebase local antes de db push em equipe
|
|
705
|
+
|
|
706
|
+
**Errado:**
|
|
707
|
+
|
|
708
|
+
```
|
|
709
|
+
Dev A workflow:
|
|
710
|
+
1. Cria branch feature-A com migration 20240106120000_dev_A.sql
|
|
711
|
+
2. NÃO pulla main por 1 semana (dev_B foi merged enquanto isso)
|
|
712
|
+
3. Direto: supabase db push para staging
|
|
713
|
+
4. Resultado: ordem cronológica força dev_A antes de dev_B → falha
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
**Por quê:** ordem cronológica de migrations é determinada por timestamp. Sem rebase, sua migration pode estar "presa" no passado relativo a migrations da equipe.
|
|
717
|
+
|
|
718
|
+
**Sintomas:**
|
|
719
|
+
|
|
720
|
+
- `db push` falha com "relation X does not exist" (FK para tabela que dev_B criou)
|
|
721
|
+
- Staging branch entra em estado "failed" do DAG
|
|
722
|
+
- Production fica em risco de mesma falha se dev fizer merge sem revisão
|
|
723
|
+
|
|
724
|
+
**Certo:**
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
# Antes de QUALQUER db push
|
|
728
|
+
git pull origin main
|
|
729
|
+
git rebase main
|
|
730
|
+
|
|
731
|
+
# Se houver conflito de timestamps → aplicar Pattern 4 (rename migration files)
|
|
732
|
+
supabase migration list # diagnose primeiro
|
|
733
|
+
# se mismatch detectado, renomear migration antiga para timestamp atualizado
|
|
734
|
+
|
|
735
|
+
supabase db reset # validar localmente em ordem cronológica correta
|
|
736
|
+
supabase db push # só depois disso
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
### Anti-pattern 4: Concurrent db push from different machines
|
|
740
|
+
|
|
741
|
+
**Errado:**
|
|
742
|
+
|
|
743
|
+
```
|
|
744
|
+
Dev A (machine 1):
|
|
745
|
+
19:00 — supabase db push (target: staging)
|
|
746
|
+
|
|
747
|
+
Dev B (machine 2):
|
|
748
|
+
19:01 — supabase db push (target: staging)
|
|
749
|
+
↓ race condition
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
**Por quê:** dois processos `db push` simultâneos podem ambos detectar a mesma migration como pending → ambos tentam aplicar → race condition na tracking table → pode resultar em registro duplicado OU registro ausente após retry.
|
|
753
|
+
|
|
754
|
+
**Sintomas:**
|
|
755
|
+
|
|
756
|
+
- Tracking table corrompido (duplicate version OU missing version)
|
|
757
|
+
- Migration aplicada parcialmente (algumas statements rodaram, outras não)
|
|
758
|
+
- `supabase migration list` mostra estado inconsistente que não bate com nenhum cenário canônico
|
|
759
|
+
|
|
760
|
+
**Certo:**
|
|
761
|
+
|
|
762
|
+
- **Centralizar `db push` em CI/CD** — apenas pipelines (GitHub Actions, GitLab CI) executam `db push` em ambientes compartilhados (staging, production). Cross-ref skill `supabase-ci-cd-github-actions` (Phase 151).
|
|
763
|
+
- **Lock manual em produção** — se você precisa fazer manual push em production, comunique no canal #release-coordination ANTES (humano lock)
|
|
764
|
+
- **Dev workflow** — devs NUNCA fazem `db push` para staging direto da máquina local; sempre via PR + merge + CI/CD pipeline
|
|
765
|
+
|
|
766
|
+
### Anti-pattern 5: Renomear migrations em produção
|
|
767
|
+
|
|
768
|
+
**Errado:**
|
|
769
|
+
|
|
770
|
+
```bash
|
|
771
|
+
# Production tracking table tem registro 20240106120000
|
|
772
|
+
# Dev renomeia o arquivo local para 20240106140000 (sem entender o impacto)
|
|
773
|
+
mv supabase/migrations/20240106120000_old.sql supabase/migrations/20240106140000_old.sql
|
|
774
|
+
|
|
775
|
+
# Push para production
|
|
776
|
+
supabase db push --target=production
|
|
777
|
+
# ↓ falha: 20240106120000 (registrado) ≠ 20240106140000 (folder)
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
**Por quê:** tracking table em produção é **append-only history**. Renomear arquivos locais cria mismatch irreversível. Diferente de Pattern 4 (rename ANTES de qualquer push), em produção a migration JÁ foi registrada — renomear local é destrutivo.
|
|
781
|
+
|
|
782
|
+
**Sintomas:**
|
|
783
|
+
|
|
784
|
+
- `db push` para production falha permanentemente
|
|
785
|
+
- `migration repair` é necessário para corrigir, mas pode levar a mais bugs se aplicado errado
|
|
786
|
+
- Worst case: rollback de production via point-in-time recovery (custo + downtime)
|
|
787
|
+
|
|
788
|
+
**Certo:**
|
|
789
|
+
|
|
790
|
+
- **Renames de migration são VÁLIDOS apenas se nunca foram aplicados** (preview branch deletado + recriado, ou apenas em folder local sem nenhum push)
|
|
791
|
+
- **Em produção, sempre forward-only**: criar nova migration que desfaz/corrige, nunca renomear histórico
|
|
792
|
+
- **Treinamento de equipe**: documentar este anti-pattern no onboarding; novo dev pode descobrir Pattern 4 e aplicar inadvertidamente em produção
|
|
793
|
+
|
|
794
|
+
## Cross-suite integration (v1.27)
|
|
795
|
+
|
|
796
|
+
Esta skill é o **complemento operacional** das skills v1.27 introduzidas em Phases 149-152:
|
|
797
|
+
|
|
798
|
+
- **`supabase-branching-workflow`** (Phase 149) — quando DAG step 5 (migrate) falha em preview branch, use Pattern 3 (rollback via delete+reopen). Forward-ref de Phase 149 fechado nesta skill.
|
|
799
|
+
- **`supabase-config-toml-remotes`** (Phase 150) — secrets per-branch podem mascarar permission errors se a migration espera env var diferente. Diagnosticar via Pattern 5 quando aplicável.
|
|
800
|
+
- **`supabase-ci-cd-github-actions`** (Phase 151) — pipelines que executam `supabase db push` podem falhar com erros documentados em Pattern 5. Fix one-time via Dashboard SQL editor, depois pipeline funciona.
|
|
801
|
+
- **`supabase-pgtap-testing`** (Phase 152) — tests falhando em CI por schema desatualizado podem indicar tracking table mismatch — diagnose via Pattern 1 antes de assumir bug no test.
|
|
802
|
+
|
|
803
|
+
Esta skill é **standalone** — não cria agent novo. É consumida por:
|
|
804
|
+
|
|
805
|
+
- `supabase-migration-writer` — referencia para ações pós-falha de migration
|
|
806
|
+
- `supabase-rls-writer` (v1.23) — quando RLS depende de schema state que pode estar drifted
|
|
807
|
+
- Agents futuros Phase 154 (`supabase-branching-architect`, `supabase-cicd-pipeline-implementer`) — incorporam diagnóstico Pattern 1 em workflows recomendados
|
|
808
|
+
|
|
809
|
+
Pattern de handoff cooperativo herdado v1.23-v1.26: **architect** projeta workflow → **pipeline-implementer** materializa pipeline → quando falha, **migration-repair** skill é o "kit de emergência" canônico para recovery.
|
|
810
|
+
|
|
811
|
+
## Ver também
|
|
812
|
+
|
|
813
|
+
- [supabase-migrations](../supabase-migrations/SKILL.md) (v1.23) — pattern canônico de migration files (5 blocos obrigatórios + naming)
|
|
814
|
+
- [supabase-branching-workflow](../supabase-branching-workflow/SKILL.md) (v1.27, Phase 149) — preview branch lifecycle + DAG 7 steps + delete+reopen rollback
|
|
815
|
+
- [supabase-config-toml-remotes](../supabase-config-toml-remotes/SKILL.md) (v1.27, Phase 150) — `[remotes]` block + secrets per-branch
|
|
816
|
+
- [supabase-ci-cd-github-actions](../supabase-ci-cd-github-actions/SKILL.md) (v1.27, Phase 151) — 8 workflows canônicos GitHub Actions
|
|
817
|
+
- [supabase-pgtap-testing](../supabase-pgtap-testing/SKILL.md) (v1.27, Phase 152) — testes pgTAP integrados no DAG
|
|
818
|
+
- [supabase-postgres-roles](../supabase-postgres-roles/SKILL.md) (v1.26) — INHERIT/NOINHERIT, GRANT membership, predefined Supabase roles
|
|
819
|
+
- [evolucao-schema-compativel](../evolucao-schema-compativel/SKILL.md) (v1.22) — 3-step migration safe rolling upgrade (expand → migrate data → contract)
|
|
820
|
+
- [supabase-declarative-schema](../supabase-declarative-schema/SKILL.md) — workflow alternativo (declarative-first → diff → migrate)
|
|
821
|
+
- [supabase-rls-policies](../supabase-rls-policies/SKILL.md) (v1.23) — RLS deve ser parte de cada migration nova
|
|
822
|
+
- [glossário compartilhado](../_shared-supabase/glossary.md) — termos canônicos migration repair, tracking table, schema drift, sync error
|
|
823
|
+
- Doc oficial Supabase: [Migration Repair](https://supabase.com/docs/reference/cli/supabase-migration-repair), [Local Development](https://supabase.com/docs/guides/local-development/cli/getting-started), [Branching](https://supabase.com/docs/guides/deployment/branching)
|