@luanpdd/kit-mcp 1.30.2 → 1.32.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.
Files changed (365) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +168 -168
  3. package/gates/agent-no-recursive-dispatch.md +84 -82
  4. package/kit/COMANDOS.md +138 -138
  5. package/kit/COMPATIBILITY.md +5 -0
  6. package/kit/README.md +76 -76
  7. package/kit/agents/advisor-researcher.md +107 -106
  8. package/kit/agents/ai-mutation-tester.md +1 -0
  9. package/kit/agents/assumptions-analyzer.md +108 -107
  10. package/kit/agents/audit-log-implementer.md +314 -313
  11. package/kit/agents/auditor-consistencia-isolamento.md +414 -413
  12. package/kit/agents/b2b-saas-architect.md +157 -156
  13. package/kit/agents/burn-rate-forecaster.md +1 -0
  14. package/kit/agents/cascading-failures-auditor.md +299 -298
  15. package/kit/agents/codebase-mapper.md +769 -768
  16. package/kit/agents/crm-pipeline-implementer.md +257 -256
  17. package/kit/agents/debugger.md +814 -813
  18. package/kit/agents/detector-tenant-quente.md +338 -337
  19. package/kit/agents/evolution-go-integrator.md +201 -200
  20. package/kit/agents/example-reviewer.md +22 -21
  21. package/kit/agents/executor.md +565 -564
  22. package/kit/agents/golden-signals-instrumenter.md +1 -0
  23. package/kit/agents/incident-investigator.md +1 -0
  24. package/kit/agents/integration-checker.md +201 -200
  25. package/kit/agents/invite-flow-implementer.md +190 -189
  26. package/kit/agents/legacy-characterizer.md +369 -368
  27. package/kit/agents/lgpd-compliance-auditor.md +296 -295
  28. package/kit/agents/load-shedding-instrumenter.md +1 -0
  29. package/kit/agents/multi-tenant-isolation-auditor.md +254 -253
  30. package/kit/agents/multi-tenant-rls-writer.md +341 -340
  31. package/kit/agents/nyquist-auditor.md +179 -178
  32. package/kit/agents/observability-coverage-auditor.md +316 -315
  33. package/kit/agents/observability-instrumenter.md +1 -0
  34. package/kit/agents/omm-auditor.md +1 -0
  35. package/kit/agents/org-onboarding-implementer.md +224 -223
  36. package/kit/agents/payload-capture-instrumenter.md +274 -273
  37. package/kit/agents/phase-researcher.md +697 -696
  38. package/kit/agents/plan-checker.md +273 -272
  39. package/kit/agents/planner.md +923 -922
  40. package/kit/agents/postmortem-writer.md +1 -0
  41. package/kit/agents/project-researcher.md +653 -652
  42. package/kit/agents/prr-conductor.md +1 -0
  43. package/kit/agents/refactor-safety-auditor.md +405 -404
  44. package/kit/agents/release-pipeline-auditor.md +1 -0
  45. package/kit/agents/research-synthesizer.md +246 -245
  46. package/kit/agents/roadmapper.md +678 -677
  47. package/kit/agents/schema-checker.md +1 -0
  48. package/kit/agents/seam-finder.md +360 -359
  49. package/kit/agents/shotgun-surgery-detector.md +350 -349
  50. package/kit/agents/slo-engineer.md +1 -0
  51. package/kit/agents/storytelling-analyst.md +1 -0
  52. package/kit/agents/supabase-architect.md +1 -0
  53. package/kit/agents/supabase-auth-bootstrapper.md +16 -1
  54. package/kit/agents/supabase-auth-hook-writer.md +418 -0
  55. package/kit/agents/supabase-branching-architect.md +563 -562
  56. package/kit/agents/supabase-cicd-pipeline-implementer.md +778 -777
  57. package/kit/agents/supabase-column-privileges-writer.md +400 -399
  58. package/kit/agents/supabase-edge-fn-tester.md +2 -1
  59. package/kit/agents/supabase-edge-fn-writer.md +2 -1
  60. package/kit/agents/supabase-mfa-implementer.md +439 -0
  61. package/kit/agents/supabase-migration-writer.md +386 -385
  62. package/kit/agents/supabase-oauth-server-implementer.md +507 -0
  63. package/kit/agents/supabase-rbac-implementer.md +393 -392
  64. package/kit/agents/supabase-realtime-implementer.md +364 -363
  65. package/kit/agents/supabase-rls-hardener.md +522 -521
  66. package/kit/agents/supabase-rls-writer.md +324 -323
  67. package/kit/agents/supabase-roles-implementer.md +356 -355
  68. package/kit/agents/supabase-social-auth-implementer.md +451 -0
  69. package/kit/agents/supabase-sso-saml-architect.md +549 -0
  70. package/kit/agents/supabase-storage-implementer.md +1 -0
  71. package/kit/agents/super-admin-implementer.md +282 -281
  72. package/kit/agents/toil-auditor.md +1 -0
  73. package/kit/agents/ui-auditor.md +438 -437
  74. package/kit/agents/ui-checker.md +303 -302
  75. package/kit/agents/ui-researcher.md +356 -355
  76. package/kit/agents/user-profiler.md +176 -175
  77. package/kit/agents/validador-evolucao-schema.md +336 -335
  78. package/kit/agents/verifier.md +729 -728
  79. package/kit/commands/adicionar-backlog.md +75 -75
  80. package/kit/commands/adicionar-fase.md +42 -42
  81. package/kit/commands/adicionar-tarefa.md +45 -45
  82. package/kit/commands/adicionar-testes.md +41 -41
  83. package/kit/commands/ajuda.md +21 -21
  84. package/kit/commands/atualizar.md +37 -37
  85. package/kit/commands/auditar-cascading.md +111 -111
  86. package/kit/commands/auditar-marco.md +179 -179
  87. package/kit/commands/auditar-observabilidade-cobertura.md +183 -183
  88. package/kit/commands/auditar-refactor.md +219 -219
  89. package/kit/commands/auditar-release.md +109 -109
  90. package/kit/commands/auditar-uat.md +23 -23
  91. package/kit/commands/autonomo.md +40 -40
  92. package/kit/commands/branch-pr.md +24 -24
  93. package/kit/commands/burn-rate-status.md +408 -408
  94. package/kit/commands/capturar-payloads.md +193 -193
  95. package/kit/commands/caracterizar.md +212 -212
  96. package/kit/commands/concluir-marco.md +247 -247
  97. package/kit/commands/configuracoes.md +36 -36
  98. package/kit/commands/dados-distribuidos.md +188 -188
  99. package/kit/commands/definir-perfil.md +10 -10
  100. package/kit/commands/depurar.md +190 -190
  101. package/kit/commands/detectar-duplicacao.md +197 -197
  102. package/kit/commands/discutir-fase.md +131 -131
  103. package/kit/commands/encontrar-seams.md +136 -136
  104. package/kit/commands/entrar-discord.md +17 -17
  105. package/kit/commands/estatisticas.md +18 -18
  106. package/kit/commands/example-greeting.md +33 -33
  107. package/kit/commands/executar-fase.md +58 -58
  108. package/kit/commands/expresso.md +56 -56
  109. package/kit/commands/fase-ui.md +34 -34
  110. package/kit/commands/fazer.md +57 -57
  111. package/kit/commands/fio.md +125 -125
  112. package/kit/commands/fluxos-trabalho.md +64 -64
  113. package/kit/commands/forense.md +176 -176
  114. package/kit/commands/gerenciador.md +38 -38
  115. package/kit/commands/inserir-fase.md +31 -31
  116. package/kit/commands/legacy.md +263 -263
  117. package/kit/commands/limpeza.md +17 -17
  118. package/kit/commands/listar-hipoteses-fase.md +45 -45
  119. package/kit/commands/listar-workspaces.md +18 -18
  120. package/kit/commands/load-shedding.md +117 -117
  121. package/kit/commands/mapear-codebase.md +70 -70
  122. package/kit/commands/multi-tenant.md +163 -163
  123. package/kit/commands/nota.md +33 -33
  124. package/kit/commands/novo-marco.md +43 -43
  125. package/kit/commands/novo-projeto.md +41 -41
  126. package/kit/commands/novo-workspace.md +43 -43
  127. package/kit/commands/pausar-trabalho.md +37 -37
  128. package/kit/commands/perfil-usuario.md +45 -45
  129. package/kit/commands/pesquisar-fase.md +195 -195
  130. package/kit/commands/planejar-fase.md +67 -67
  131. package/kit/commands/planejar-lacunas.md +33 -33
  132. package/kit/commands/plantar-ideia.md +25 -25
  133. package/kit/commands/progresso.md +24 -24
  134. package/kit/commands/proximo.md +30 -30
  135. package/kit/commands/publicar.md +490 -490
  136. package/kit/commands/rapido.md +35 -35
  137. package/kit/commands/reaplicar-patches.md +124 -124
  138. package/kit/commands/refactor-seguro.md +321 -321
  139. package/kit/commands/relatorio-sessao.md +19 -19
  140. package/kit/commands/remover-fase.md +31 -31
  141. package/kit/commands/remover-workspace.md +26 -26
  142. package/kit/commands/resumo-marco.md +50 -50
  143. package/kit/commands/retomar-trabalho.md +40 -40
  144. package/kit/commands/revisar-backlog.md +60 -60
  145. package/kit/commands/revisar-ui.md +32 -32
  146. package/kit/commands/revisar.md +37 -37
  147. package/kit/commands/saude.md +21 -21
  148. package/kit/commands/setup-notion.md +93 -93
  149. package/kit/commands/storytelling.md +179 -179
  150. package/kit/commands/supabase.md +21 -1
  151. package/kit/commands/sync-main.md +68 -68
  152. package/kit/commands/validar-fase.md +35 -35
  153. package/kit/commands/verificar-tarefas.md +44 -44
  154. package/kit/commands/verificar-trabalho.md +64 -64
  155. package/kit/file-manifest.json +100 -84
  156. package/kit/framework/bin/lib/commands.cjs +959 -959
  157. package/kit/framework/bin/lib/config.cjs +442 -442
  158. package/kit/framework/bin/lib/core.cjs +1230 -1230
  159. package/kit/framework/bin/lib/frontmatter.cjs +336 -336
  160. package/kit/framework/bin/lib/init.cjs +1442 -1442
  161. package/kit/framework/bin/lib/milestone.cjs +252 -252
  162. package/kit/framework/bin/lib/model-profiles.cjs +68 -68
  163. package/kit/framework/bin/lib/phase.cjs +888 -888
  164. package/kit/framework/bin/lib/profile-output.cjs +952 -952
  165. package/kit/framework/bin/lib/profile-pipeline.cjs +539 -539
  166. package/kit/framework/bin/lib/roadmap.cjs +329 -329
  167. package/kit/framework/bin/lib/security.cjs +382 -382
  168. package/kit/framework/bin/lib/state.cjs +1031 -1031
  169. package/kit/framework/bin/lib/template.cjs +222 -222
  170. package/kit/framework/bin/lib/uat.cjs +282 -282
  171. package/kit/framework/bin/lib/verify.cjs +888 -888
  172. package/kit/framework/bin/lib/workstream.cjs +491 -491
  173. package/kit/framework/bin/tools.cjs +918 -918
  174. package/kit/framework/commands/workstreams.md +63 -63
  175. package/kit/framework/references/checkpoints.md +778 -778
  176. package/kit/framework/references/continuation-format.md +249 -249
  177. package/kit/framework/references/decimal-phase-calculation.md +64 -64
  178. package/kit/framework/references/git-integration.md +295 -295
  179. package/kit/framework/references/git-planning-commit.md +38 -38
  180. package/kit/framework/references/model-profile-resolution.md +36 -36
  181. package/kit/framework/references/model-profiles.md +139 -139
  182. package/kit/framework/references/phase-argument-parsing.md +61 -61
  183. package/kit/framework/references/planning-config.md +202 -202
  184. package/kit/framework/references/questioning.md +162 -162
  185. package/kit/framework/references/tdd.md +263 -263
  186. package/kit/framework/references/ui-brand.md +160 -160
  187. package/kit/framework/references/user-profiling.md +657 -657
  188. package/kit/framework/references/verification-patterns.md +612 -612
  189. package/kit/framework/references/workstream-flag.md +58 -58
  190. package/kit/framework/templates/DEBUG.md +164 -164
  191. package/kit/framework/templates/UAT.md +265 -265
  192. package/kit/framework/templates/UI-SPEC.md +100 -100
  193. package/kit/framework/templates/VALIDATION.md +76 -76
  194. package/kit/framework/templates/claude-md.md +122 -122
  195. package/kit/framework/templates/codebase/architecture.md +185 -185
  196. package/kit/framework/templates/codebase/concerns.md +205 -205
  197. package/kit/framework/templates/codebase/conventions.md +204 -204
  198. package/kit/framework/templates/codebase/integrations.md +192 -192
  199. package/kit/framework/templates/codebase/stack.md +158 -158
  200. package/kit/framework/templates/codebase/structure.md +199 -199
  201. package/kit/framework/templates/codebase/testing.md +301 -301
  202. package/kit/framework/templates/config.json +44 -44
  203. package/kit/framework/templates/context.md +352 -352
  204. package/kit/framework/templates/continue-here.md +78 -78
  205. package/kit/framework/templates/copilot-instructions.md +7 -7
  206. package/kit/framework/templates/debug-subagent-prompt.md +91 -91
  207. package/kit/framework/templates/dev-preferences.md +20 -20
  208. package/kit/framework/templates/discovery.md +146 -146
  209. package/kit/framework/templates/discussion-log.md +63 -63
  210. package/kit/framework/templates/milestone-archive.md +123 -123
  211. package/kit/framework/templates/milestone.md +115 -115
  212. package/kit/framework/templates/phase-prompt.md +610 -610
  213. package/kit/framework/templates/planner-subagent-prompt.md +117 -117
  214. package/kit/framework/templates/project.md +186 -186
  215. package/kit/framework/templates/requirements.md +231 -231
  216. package/kit/framework/templates/research-project/ARCHITECTURE.md +204 -204
  217. package/kit/framework/templates/research-project/FEATURES.md +147 -147
  218. package/kit/framework/templates/research-project/PITFALLS.md +200 -200
  219. package/kit/framework/templates/research-project/STACK.md +120 -120
  220. package/kit/framework/templates/research-project/SUMMARY.md +170 -170
  221. package/kit/framework/templates/research.md +419 -419
  222. package/kit/framework/templates/retrospective.md +54 -54
  223. package/kit/framework/templates/roadmap.md +202 -202
  224. package/kit/framework/templates/state.md +176 -176
  225. package/kit/framework/templates/summary-complex.md +59 -59
  226. package/kit/framework/templates/summary-minimal.md +41 -41
  227. package/kit/framework/templates/summary-standard.md +48 -48
  228. package/kit/framework/templates/summary.md +209 -209
  229. package/kit/framework/templates/user-profile.md +146 -146
  230. package/kit/framework/templates/user-setup.md +256 -256
  231. package/kit/framework/templates/verification-report.md +258 -258
  232. package/kit/framework/workflows/add-phase.md +112 -112
  233. package/kit/framework/workflows/add-tests.md +351 -351
  234. package/kit/framework/workflows/add-todo.md +158 -158
  235. package/kit/framework/workflows/audit-milestone.md +340 -340
  236. package/kit/framework/workflows/audit-uat.md +109 -109
  237. package/kit/framework/workflows/autonomous.md +891 -891
  238. package/kit/framework/workflows/check-todos.md +177 -177
  239. package/kit/framework/workflows/cleanup.md +152 -152
  240. package/kit/framework/workflows/complete-milestone.md +696 -696
  241. package/kit/framework/workflows/diagnose-issues.md +231 -231
  242. package/kit/framework/workflows/discovery-phase.md +289 -289
  243. package/kit/framework/workflows/discuss-phase-assumptions.md +653 -653
  244. package/kit/framework/workflows/discuss-phase.md +784 -784
  245. package/kit/framework/workflows/do.md +104 -104
  246. package/kit/framework/workflows/execute-phase.md +838 -838
  247. package/kit/framework/workflows/execute-plan.md +510 -510
  248. package/kit/framework/workflows/fast.md +102 -102
  249. package/kit/framework/workflows/forensics.md +265 -265
  250. package/kit/framework/workflows/health.md +181 -181
  251. package/kit/framework/workflows/help.md +619 -619
  252. package/kit/framework/workflows/insert-phase.md +130 -130
  253. package/kit/framework/workflows/list-phase-assumptions.md +178 -178
  254. package/kit/framework/workflows/list-workspaces.md +56 -56
  255. package/kit/framework/workflows/manager.md +362 -362
  256. package/kit/framework/workflows/map-codebase.md +377 -377
  257. package/kit/framework/workflows/milestone-summary.md +223 -223
  258. package/kit/framework/workflows/new-milestone.md +486 -486
  259. package/kit/framework/workflows/new-project.md +1159 -1159
  260. package/kit/framework/workflows/new-workspace.md +237 -237
  261. package/kit/framework/workflows/next.md +97 -97
  262. package/kit/framework/workflows/node-repair.md +92 -92
  263. package/kit/framework/workflows/note.md +156 -156
  264. package/kit/framework/workflows/pause-work.md +176 -176
  265. package/kit/framework/workflows/plan-milestone-gaps.md +273 -273
  266. package/kit/framework/workflows/plan-phase.md +765 -765
  267. package/kit/framework/workflows/plant-seed.md +169 -169
  268. package/kit/framework/workflows/pr-branch.md +129 -129
  269. package/kit/framework/workflows/profile-user.md +450 -450
  270. package/kit/framework/workflows/progress.md +507 -507
  271. package/kit/framework/workflows/quick.md +757 -757
  272. package/kit/framework/workflows/remove-phase.md +155 -155
  273. package/kit/framework/workflows/remove-workspace.md +90 -90
  274. package/kit/framework/workflows/research-phase.md +82 -82
  275. package/kit/framework/workflows/resume-project.md +326 -326
  276. package/kit/framework/workflows/review.md +228 -228
  277. package/kit/framework/workflows/session-report.md +146 -146
  278. package/kit/framework/workflows/settings.md +283 -283
  279. package/kit/framework/workflows/ship.md +228 -228
  280. package/kit/framework/workflows/stats.md +60 -60
  281. package/kit/framework/workflows/transition.md +671 -671
  282. package/kit/framework/workflows/ui-phase.md +302 -302
  283. package/kit/framework/workflows/ui-review.md +165 -165
  284. package/kit/framework/workflows/update.md +323 -323
  285. package/kit/framework/workflows/validate-phase.md +174 -174
  286. package/kit/framework/workflows/verify-phase.md +252 -252
  287. package/kit/framework/workflows/verify-work.md +637 -637
  288. package/kit/hooks/check-update.js +118 -118
  289. package/kit/hooks/context-monitor.js +163 -163
  290. package/kit/hooks/kit-attribution-reminder.cjs +29 -50
  291. package/kit/hooks/kit-router.cjs +137 -0
  292. package/kit/hooks/prompt-guard.js +103 -103
  293. package/kit/hooks/statusline.js +125 -125
  294. package/kit/hooks/workflow-guard.js +101 -101
  295. package/kit/settings.json +45 -45
  296. package/kit/skills/ai-prompt-characterization/SKILL.md +335 -335
  297. package/kit/skills/armadilhas-sistemas-distribuidos/SKILL.md +447 -447
  298. package/kit/skills/audit-log-multi-tenant/SKILL.md +340 -340
  299. package/kit/skills/b2b-saas-architecture/SKILL.md +300 -300
  300. package/kit/skills/consistencia-leitura-replica/SKILL.md +385 -385
  301. package/kit/skills/crm-lead-pipeline-patterns/SKILL.md +343 -343
  302. package/kit/skills/escolha-modelo-consistencia/SKILL.md +494 -494
  303. package/kit/skills/evolucao-schema-compativel/SKILL.md +448 -448
  304. package/kit/skills/evolution-go-whatsapp-integration/SKILL.md +322 -322
  305. package/kit/skills/example-skill/SKILL.md +42 -42
  306. package/kit/skills/legacy-api-only-applications/SKILL.md +358 -358
  307. package/kit/skills/legacy-characterization-tests/SKILL.md +330 -330
  308. package/kit/skills/legacy-effect-analysis/SKILL.md +331 -331
  309. package/kit/skills/legacy-extract-class/SKILL.md +203 -203
  310. package/kit/skills/legacy-programming-by-difference/SKILL.md +252 -252
  311. package/kit/skills/legacy-seams-and-test-harness/SKILL.md +460 -460
  312. package/kit/skills/legacy-shotgun-surgery/SKILL.md +286 -286
  313. package/kit/skills/legacy-sprout-wrap-techniques/SKILL.md +434 -434
  314. package/kit/skills/legacy-storytelling-naked-crc/SKILL.md +270 -270
  315. package/kit/skills/lgpd-multi-tenant-compliance/SKILL.md +340 -340
  316. package/kit/skills/member-invite-flow/SKILL.md +305 -305
  317. package/kit/skills/member-management-react-shadcn/SKILL.md +328 -328
  318. package/kit/skills/multi-tenant-performance-scaling/SKILL.md +316 -316
  319. package/kit/skills/multi-tenant-rls-hierarchy/SKILL.md +342 -342
  320. package/kit/skills/org-onboarding-flow/SKILL.md +257 -257
  321. package/kit/skills/org-switcher-react-pattern/SKILL.md +349 -349
  322. package/kit/skills/permission-gate-react-pattern/SKILL.md +271 -271
  323. package/kit/skills/postgres-isolamento-concorrencia/SKILL.md +552 -552
  324. package/kit/skills/pre-refactor-characterization/SKILL.md +421 -421
  325. package/kit/skills/rbac-permissions-matrix-supabase/SKILL.md +338 -338
  326. package/kit/skills/streams-eventos-cdc/SKILL.md +711 -711
  327. package/kit/skills/supabase-auth-hardening/SKILL.md +674 -0
  328. package/kit/skills/supabase-auth-hooks/SKILL.md +875 -0
  329. package/kit/skills/supabase-auth-methods/SKILL.md +486 -0
  330. package/kit/skills/supabase-auth-sessions/SKILL.md +579 -0
  331. package/kit/skills/supabase-auth-ssr/SKILL.md +60 -14
  332. package/kit/skills/supabase-branching-workflow/SKILL.md +544 -544
  333. package/kit/skills/supabase-ci-cd-github-actions/SKILL.md +880 -880
  334. package/kit/skills/supabase-column-level-security/SKILL.md +426 -426
  335. package/kit/skills/supabase-config-toml-remotes/SKILL.md +807 -807
  336. package/kit/skills/supabase-custom-claims-rbac/SKILL.md +472 -472
  337. package/kit/skills/supabase-edge-functions/SKILL.md +1 -1
  338. package/kit/skills/supabase-edge-functions-auth/SKILL.md +1 -1
  339. package/kit/skills/supabase-edge-functions-limits/SKILL.md +1 -1
  340. package/kit/skills/supabase-edge-functions-mcp-server/SKILL.md +1 -1
  341. package/kit/skills/supabase-edge-functions-testing/SKILL.md +1 -1
  342. package/kit/skills/supabase-edge-runtime-builtins/SKILL.md +1 -1
  343. package/kit/skills/supabase-enterprise-sso-saml/SKILL.md +545 -0
  344. package/kit/skills/supabase-jwt-signing-keys/SKILL.md +399 -0
  345. package/kit/skills/supabase-mfa/SKILL.md +488 -0
  346. package/kit/skills/supabase-migration-repair/SKILL.md +823 -823
  347. package/kit/skills/supabase-migrations/SKILL.md +297 -297
  348. package/kit/skills/supabase-oauth-server/SKILL.md +537 -0
  349. package/kit/skills/supabase-pgtap-testing/SKILL.md +1053 -1053
  350. package/kit/skills/supabase-postgres-roles/SKILL.md +392 -392
  351. package/kit/skills/supabase-realtime/SKILL.md +460 -460
  352. package/kit/skills/supabase-rls-defense-in-depth/SKILL.md +418 -418
  353. package/kit/skills/supabase-rls-policies/SKILL.md +635 -635
  354. package/kit/skills/supabase-social-oauth/SKILL.md +480 -0
  355. package/kit/skills/supabase-third-party-auth/SKILL.md +450 -0
  356. package/kit/skills/super-admin-platform-pattern/SKILL.md +326 -326
  357. package/kit/skills/tenant-quente-mitigacao/SKILL.md +605 -605
  358. package/kit/skills/whatsapp-conversation-state-machine/SKILL.md +287 -287
  359. package/package.json +1 -1
  360. package/src/core/kit.js +216 -216
  361. package/src/core/reflect.js +247 -247
  362. package/src/core/reverse-sync.js +372 -372
  363. package/src/core/sync.js +437 -418
  364. package/src/core/watch.js +121 -121
  365. package/src/mcp-server/index.js +794 -746
@@ -1,807 +1,807 @@
1
- ---
2
- name: supabase-config-toml-remotes
3
- description: Use ao configurar Supabase para branching — `[remotes.<name>]` block + branch-specific overrides + secrets per-branch (NÃO herdam) + dotenvx pattern (.env.keys + .env.preview encrypted) + 6…
4
- ---
5
-
6
- # Supabase — Config TOML & Remotes
7
-
8
- ## Quando usar
9
-
10
- Branching Supabase exige configuração per-branch via `supabase/config.toml` — blocos `[remotes.<name>]` declaram **overrides versionados em git** que o Deploy DAG step 4 (configure) aplica em cada branch.
11
-
12
- Esta skill é par-conjugado com `supabase-branching-workflow` (Phase 149) — branching workflow descreve **quando** branches são criados; esta skill descreve **como** configurar.
13
-
14
- Trigger phrases:
15
-
16
- - "remotes block Supabase", "[remotes] config.toml"
17
- - "branch-specific config Supabase", "config.toml staging override"
18
- - "secrets per-branch Supabase", "supabase secrets set"
19
- - "dotenvx Supabase", ".env.keys .env.preview"
20
- - "encrypted: Supabase config", "env() vs encrypted: syntax"
21
- - "Supabase encrypted fields", "auth.hook secrets encrypted"
22
- - "designated secret fields"
23
- - "branch project_id Supabase"
24
-
25
- **Use APENAS para:**
26
-
27
- - Configurar persistent branches (staging, QA, production) via `[remotes.<branch>]` block
28
- - Materializar overrides per-ambiente (db.pool_size, api.max_rows, auth.external.*, edge_runtime.secrets)
29
- - Gerenciar secrets per-branch via `supabase secrets set --env-file`
30
- - Versionar secrets encrypted em git via dotenvx pattern (.env.keys + .env.preview/.env.production)
31
-
32
- **NÃO use para:**
33
-
34
- - Substituir secret vault corporativo (Vault, AWS Secrets Manager) — dotenvx é git-tracked encrypted; vault corporativo tem audit trail + rotation policies
35
- - Gerenciar secrets de runtime de Edge Functions sem `supabase secrets set` — `env()` em config.toml é build-time do CLI, não runtime do projeto
36
- - Versionar a chave de decryption (`.env.keys`) — NUNCA committar; é equivalente a vazar password master
37
- - Apontar `[remotes.<name>]` para branch deletado — operações falham silenciosamente
38
-
39
- ## Princípio canônico
40
-
41
- Três princípios canônicos:
42
-
43
- 1. **`config.toml` é source of truth versionado.** `[remotes.<branch>]` block declara overrides explícitos commitados em git — Deploy DAG step 4 (configure) re-aplica em cada deploy. Sem deriva entre o que está em git e o que está no branch.
44
-
45
- 2. **dotenvx para secrets git-tracked.** `.env.keys` (decryption key, **SEMPRE gitignored**) + `.env.preview`/`.env.production` (encrypted values, committed em git). Permite versionar secrets sem expor — git history rastreia mudanças de secrets sem PII em plaintext.
46
-
47
- 3. **Secrets NÃO herdam entre branches.** Cada branch tem credenciais únicas; criar persistent branch `staging` NÃO copia secrets do `main`. Reset manual via `supabase secrets set --env-file` para CADA branch — incluindo o branch `main` original.
48
-
49
- ### Distinção canônica `env()` vs `encrypted:`
50
-
51
- | | `env(VAR_NAME)` | `encrypted:<value>` |
52
- |---|---|---|
53
- | Resolução | Runtime CLI (build-time) | Decryption via `.env.keys` |
54
- | Onde funciona | **Qualquer** field em config.toml | **APENAS** designated secret fields (Pattern 5) |
55
- | Workflow | Setar env var no shell antes do CLI | Encriptar via `dotenvx set`, committed em git |
56
- | Caveat | Resolve para env var **local** do CLI, NÃO para secrets do projeto Supabase (runtime das Edge Functions) | Em field **não-designated** é silent no-op (literal string usada como valor) |
57
- | Caso de uso | Secrets em env vars do CI (GitHub Actions) | Secrets versionados encrypted em git via dotenvx |
58
-
59
- ## Pattern 1: `[remotes]` block — referenciar branch existente (CFG-01)
60
-
61
- `[remotes.<name>]` em `config.toml` declara que **este bloco se aplica APENAS ao branch nomeado** identificado pelo `project_id`.
62
-
63
- ### Pré-requisito
64
-
65
- Branch já criado (persistent via CLI ou preview via PR webhook):
66
-
67
- ```bash
68
- # criar persistent branch via CLI
69
- supabase --experimental branches create staging --persistent
70
-
71
- # (preview branches são criados automaticamente via GitHub PR — cross-ref skill supabase-branching-workflow Pattern 3)
72
- ```
73
-
74
- ### Workflow canônico
75
-
76
- **Step 1: Obter `project_id` do branch:**
77
-
78
- ```bash
79
- supabase --experimental branches list
80
-
81
- # output esperado:
82
- # BRANCH NAME BRANCH PROJECT ID STATUS
83
- # main main-project-ref active
84
- # staging staging-dedicated-ref active
85
- # pr-42-feature pr42-feature-ref active
86
- ```
87
-
88
- **Step 2: Adicionar `[remotes.<branch>]` block no `supabase/config.toml`:**
89
-
90
- ```toml
91
- [remotes.staging]
92
- project_id = "staging-dedicated-ref"
93
-
94
- [remotes.staging.db.seed]
95
- enabled = true
96
- sql_paths = ["./seeds/staging.sql"]
97
- ```
98
-
99
- **Step 3: Commitar `config.toml` em git → Deploy DAG step 4 (configure) aplica overrides no branch.**
100
-
101
- ### Exemplo TOML — múltiplos branches
102
-
103
- ```toml
104
- # bloco base — aplica a TODOS os branches (incluindo main)
105
- [db]
106
- port = 54322
107
- pool_size = 15
108
-
109
- [api]
110
- port = 54321
111
- max_rows = 1000
112
-
113
- # branch staging — overrides específicos
114
- [remotes.staging]
115
- project_id = "staging-dedicated-ref"
116
-
117
- [remotes.staging.db.seed]
118
- enabled = true
119
- sql_paths = ["./seeds/staging.sql"]
120
-
121
- # branch production — sem seeds em produção
122
- [remotes.production]
123
- project_id = "production-dedicated-ref"
124
-
125
- [remotes.production.db.seed]
126
- enabled = false
127
- ```
128
-
129
- ### Caveat — branch deletado
130
-
131
- `project_id` deve ser de branch **existente**. Se branch foi deletado:
132
-
133
- - Bloco `[remotes.<branch>]` continua válido sintaticamente
134
- - CLI rejeita commands com erro `branch not found`
135
- - DAG step 4 (configure) silenciosamente skip o branch deletado
136
-
137
- **Mitigação:** revisão trimestral — `supabase --experimental branches list` + remover blocos `[remotes.<deleted>]` correspondentes.
138
-
139
- ### Caveat — `project_id` único por bloco
140
-
141
- Cada `[remotes.<name>]` deve apontar para **branch dedicado** criado especificamente. NÃO reutilizar `project_id` do `main` para `staging` (cross-ref Anti-pattern 5).
142
-
143
- ## Pattern 2: Branch-specific configuration overrides (CFG-02)
144
-
145
- Princípio: config base (sem `[remotes...]` prefix) aplica a TODOS os branches; `[remotes.<name>.<section>]` aplica override APENAS no branch nomeado.
146
-
147
- ### Categorias de fields override-able (canônicas)
148
-
149
- **db (database tuning):**
150
-
151
- ```toml
152
- [db]
153
- port = 54322
154
- pool_size = 15 # default
155
-
156
- # staging override
157
- [remotes.staging.db]
158
- port = 54322 # mesma porta — só pool_size muda
159
- pool_size = 25
160
- ```
161
-
162
- **api (PostgREST):**
163
-
164
- ```toml
165
- [api]
166
- port = 54321
167
- max_rows = 1000
168
- schemas = ["public"]
169
-
170
- # staging quer ver schema extensions para debug
171
- [remotes.staging.api]
172
- max_rows = 5000 # debug — limite maior
173
- schemas = ["public", "extensions"]
174
- ```
175
-
176
- **db.seed:**
177
-
178
- ```toml
179
- # default — sem seed
180
- [db.seed]
181
- enabled = false
182
- sql_paths = []
183
-
184
- # staging — seed sintético para QA
185
- [remotes.staging.db.seed]
186
- enabled = true
187
- sql_paths = ["./seeds/staging.sql"]
188
-
189
- # preview — seed minimal para smoke tests
190
- [remotes.preview.db.seed]
191
- enabled = true
192
- sql_paths = ["./seeds/preview-smoke.sql"]
193
- ```
194
-
195
- **auth.external.* (OAuth providers):**
196
-
197
- ```toml
198
- # production GitHub OAuth
199
- [auth.external.github]
200
- enabled = true
201
- client_id = "Iv1.production-app-id"
202
- secret = "encrypted:LSi...prod-github-secret-encrypted...=="
203
-
204
- # staging GitHub OAuth — app diferente
205
- [remotes.staging.auth.external.github]
206
- enabled = true
207
- client_id = "Iv1.staging-app-id"
208
- secret = "encrypted:LSi...staging-github-secret-encrypted...=="
209
- redirect_uri = "https://staging.example.com/auth/callback"
210
- ```
211
-
212
- **edge_runtime.secrets:**
213
-
214
- ```toml
215
- [edge_runtime.secrets]
216
- SENDGRID_API_KEY = "encrypted:LSi...prod-sendgrid-encrypted...=="
217
-
218
- # staging — SendGrid sandbox
219
- [remotes.staging.edge_runtime.secrets]
220
- SENDGRID_API_KEY = "encrypted:LSi...staging-sendgrid-encrypted...=="
221
- SENDGRID_SANDBOX_MODE = "env(STAGING_SENDGRID_SANDBOX_MODE)"
222
- ```
223
-
224
- ### Tabela canônica de fields override-able
225
-
226
- | Section | Fields | Caso de uso típico |
227
- |---------|--------|---------------------|
228
- | `db` | `port`, `pool_size` | Tuning pool size per ambiente (staging menor) |
229
- | `api` | `port`, `max_rows`, `schemas` | Diferenciar response limits + schemas expostos |
230
- | `db.seed` | `enabled`, `sql_paths` | Seeds diferentes por branch |
231
- | `auth.external.<provider>` | `enabled`, `client_id`, `secret`, `redirect_uri` | OAuth keys per ambiente |
232
- | `auth.email.smtp` | `host`, `port`, `user`, `pass` | SMTP staging vs produção |
233
- | `auth.sms.<provider>` | `account_sid`, `auth_token`, etc. | SMS provider keys per ambiente |
234
- | `edge_runtime.secrets.<KEY>` | custom env vars | API keys per branch (SendGrid, Stripe, OpenAI) |
235
- | `studio.openai_api_key` | string | Key diferente para staging studio (lower limits) |
236
-
237
- ### Caveat — merge behavior
238
-
239
- `[remotes.staging.db]` com `pool_size = 25` NÃO sobrescreve `[db]` global completamente — apenas o field específico (`pool_size`). Outros fields do `[db]` global (port, etc.) continuam aplicados.
240
-
241
- ```toml
242
- # config base
243
- [db]
244
- port = 54322
245
- pool_size = 15
246
- shadow_port = 54320
247
-
248
- # staging override — apenas pool_size muda
249
- [remotes.staging.db]
250
- pool_size = 25
251
- # resultado em staging: port=54322, pool_size=25, shadow_port=54320 (mantidos da base)
252
- ```
253
-
254
- ### Caveat — re-deploy required
255
-
256
- Alterações em `config.toml` precisam ser pushed para o branch — Deploy DAG step 4 (configure) só roda em novo deploy (push novo commit no PR ou re-run via Dashboard).
257
-
258
- ## Pattern 3: Secrets management per-branch (CFG-03)
259
-
260
- ### Caveat canônico — secrets NÃO herdam
261
-
262
- > **Secrets NÃO herdam entre branches.** Criar persistent branch `staging` NÃO copia secrets do `main`. Cada branch precisa ter secrets setados separadamente.
263
-
264
- Implicação prática:
265
-
266
- - `Deno.env.get("SENDGRID_API_KEY")` em Edge Function no branch staging retorna `undefined` até `supabase secrets set` ser executado para o staging
267
- - Esse comportamento é silent — sem warning no DAG, sem alert do CLI
268
-
269
- ### CLI canônico
270
-
271
- ```bash
272
- # Set secrets a partir de .env file (recomendação canônica)
273
- supabase secrets set --env-file ./supabase/.env
274
-
275
- # Set secret individual
276
- supabase secrets set SMTP_HOST=smtp.example.com
277
-
278
- # Listar secrets do branch atual
279
- supabase secrets list
280
-
281
- # Remover secret
282
- supabase secrets unset SMTP_HOST
283
- ```
284
-
285
- ### Workflow per-branch canônico
286
-
287
- ```bash
288
- # 1. criar staging branch
289
- supabase --experimental branches create staging --persistent
290
-
291
- # 2. obter project_id do staging
292
- supabase --experimental branches list | grep staging
293
- # output: staging staging-dedicated-ref active
294
-
295
- # 3. link CLI para o branch staging
296
- supabase link --project-ref staging-dedicated-ref
297
-
298
- # 4. setar secrets DO STAGING (arquivo dedicado)
299
- supabase secrets set --env-file ./supabase/.env.staging
300
-
301
- # 5. validar — listar secrets do staging
302
- supabase secrets list
303
-
304
- # 6. voltar para main quando terminar
305
- supabase link --project-ref main-project-ref
306
- ```
307
-
308
- ### Exemplo `.env.staging`
309
-
310
- ```bash
311
- # .env.staging — secrets específicos do branch staging
312
- # Gitignored se não usa dotenvx (Pattern 4); encrypted se usa.
313
- SMTP_HOST=smtp.staging.example.com
314
- SMTP_USER=staging-user
315
- SMTP_PASS=staging-pass
316
- SENDGRID_API_KEY=SG.staging-api-key
317
- OPENAI_API_KEY=sk-staging-openai-key
318
- STRIPE_SECRET_KEY=sk_test_staging_stripe
319
- ```
320
-
321
- ### Caveat — secrets vs config.toml `env()`
322
-
323
- Distinção CRÍTICA — fonte de confusão comum:
324
-
325
- | | `supabase secrets set` | `env()` em config.toml |
326
- |---|---|---|
327
- | Resolvido | Runtime das **Edge Functions** | Build-time do **CLI local** |
328
- | Acesso | `Deno.env.get("KEY")` no código Deno | Substituição literal no `config.toml` pré-deploy |
329
- | Storage | Supabase backend (per-branch) | Env var do shell que rodou o CLI |
330
- | Lifecycle | Persistido no branch | Volátil (só durante invocação do CLI) |
331
-
332
- Exemplo concreto:
333
-
334
- ```bash
335
- # Setar secret no branch (runtime Edge Function)
336
- supabase secrets set SENDGRID_API_KEY=sk-real-key
337
- # → Deno.env.get("SENDGRID_API_KEY") em Edge Function retorna "sk-real-key"
338
-
339
- # Setar env var local (build-time config.toml)
340
- export SENDGRID_API_KEY=sk-different-key
341
- supabase db push
342
- # → config.toml com env(SENDGRID_API_KEY) resolve para "sk-different-key" (do shell)
343
- # → Edge Function ainda retorna "sk-real-key" (do supabase secrets set anterior)
344
- ```
345
-
346
- ### Recomendação canônica
347
-
348
- Usar **dotenvx pattern** (Pattern 4) para versionar secrets encrypted em git em vez de gerenciar `.env.staging` separadamente em cada máquina.
349
-
350
- ## Pattern 4: dotenvx pattern + `encrypted:` vs `env()` syntax (CFG-04)
351
-
352
- ### Princípio dotenvx
353
-
354
- dotenvx ([dotenvx.com](https://dotenvx.com/)) é uma evolução de `dotenv` que permite **encryption symmetric** de valores no arquivo `.env`:
355
-
356
- - Encrypted values podem ser committed em git (`.env.preview`, `.env.production`)
357
- - Decryption key (`.env.keys`) **NUNCA é committed** — gitignored sempre
358
- - Permite versionar secrets sem expor — git history rastreia mudanças de secrets sem PII em plaintext
359
-
360
- ### Tabela canônica de file types (dotenvx convenção)
361
-
362
- | File | Env | gitignore | Encrypted | Caso de uso |
363
- |------|-----|-----------|-----------|-------------|
364
- | `.env.keys` | All | **YES** (NUNCA committar) | No (key plaintext) | Decryption master key |
365
- | `.env.local` | Local dev | YES | No (plaintext OK local) | Overrides de dev individual |
366
- | `.env.production` | Production | No (committed) | YES | Secrets de produção encrypted |
367
- | `.env.preview` | Branches preview | No (committed) | YES | Secrets de preview branches encrypted |
368
- | `.env` | Any (fallback) | Maybe | YES | Default file (custom) |
369
-
370
- **Atenção canônica:** `.env.keys` em `.gitignore` é obrigação canônica — sem isso, o pattern dotenvx é equivalente a commitar secrets plaintext.
371
-
372
- ### Workflow canônico dotenvx
373
-
374
- ```bash
375
- # 1. instalar dotenvx (devDependency)
376
- npm install -D @dotenvx/dotenvx
377
-
378
- # 2. adicionar .env.keys ao .gitignore (BLOQUEANTE — fazer ANTES de qualquer set)
379
- echo ".env.keys" >> .gitignore
380
- git add .gitignore
381
- git commit -m "chore: gitignore dotenvx decryption key"
382
-
383
- # 3. encrypted set — gera .env.keys automaticamente na primeira vez
384
- npx @dotenvx/dotenvx set SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET "ghs_real_secret" -f supabase/.env.preview
385
- # Output:
386
- # set SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET (encrypted) (.env.preview)
387
- # wrote new public-private encryption keys to .env.keys
388
-
389
- # 4. commitar .env.preview (encrypted) + verificar .env.keys NÃO foi committed
390
- git status
391
- # modified: supabase/.env.preview
392
- # (.env.keys NÃO deve aparecer)
393
- git add supabase/.env.preview
394
- git commit -m "feat: add encrypted GitHub OAuth secret for preview"
395
-
396
- # 5. usar com supabase CLI (carregar via --env-file)
397
- npx supabase secrets set --env-file supabase/.env.keys
398
- # ou em workflow CI (decripta + roda CLI):
399
- npx @dotenvx/dotenvx run -- supabase secrets set --env-file supabase/.env.preview
400
- ```
401
-
402
- ### Sintaxes em `config.toml`
403
-
404
- **Option A: `encrypted:<value>` directly em designated secret field:**
405
-
406
- ```toml
407
- [auth.external.github]
408
- enabled = true
409
- client_id = "Iv1.app-id-public"
410
- # secret é designated secret field (Pattern 5 Grupo 8) — encrypted: é decriptado via .env.keys
411
- secret = "encrypted:LSiME...github-secret-encrypted-payload...=="
412
- ```
413
-
414
- **Option B: `env(VAR_NAME)` para resolver via env var (qualquer field):**
415
-
416
- ```toml
417
- [auth.external.github]
418
- enabled = true
419
- client_id = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_CLIENT_ID)"
420
- secret = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET)"
421
- ```
422
-
423
- ### Warning canônico — `encrypted:` é restrito
424
-
425
- > **`encrypted:` syntax SÓ funciona em designated secret fields** (Pattern 5 — 6 grupos canônicos). Em outros campos não decripta silenciosamente — o valor literal `"encrypted:LSiME..."` é usado como string, expondo o payload encrypted como se fosse plaintext.
426
-
427
- Exemplo concreto do falso silencioso:
428
-
429
- ```toml
430
- # ERRADO — auth.email.smtp.host NÃO é designated secret field
431
- [auth.email.smtp]
432
- host = "encrypted:LSi...wrong...==" # ← silent no-op
433
- # resultado: SMTP tenta conectar em host literal "encrypted:LSi...wrong...==" → DNS fail
434
-
435
- # CERTO — auth.email.smtp.pass É designated (Pattern 5 Grupo 4)
436
- [auth.email.smtp]
437
- host = "smtp.example.com" # plain
438
- pass = "encrypted:LSi...correct-pass...==" # ← decriptado
439
- ```
440
-
441
- ### Quando usar qual
442
-
443
- - **`encrypted:`** — quando quer versionar o secret **encrypted em git** (workflow dotenvx); aplicar APENAS em fields designados (Pattern 5)
444
- - **`env()`** — quando secrets vivem em env vars do CI/local; works em **qualquer field**; flexibilidade ao custo de não versionar em git (rotação via update env var no CI)
445
-
446
- Recomendação canônica para teams maduros: `encrypted:` em produção (auditável via git history) + `env()` em dev local (volátil).
447
-
448
- ## Pattern 5: 6 grupos de encrypted fields canônicos (CFG-05)
449
-
450
- Princípio: apenas estes fields aceitam `encrypted:<value>` syntax — qualquer outro field é **silent no-op** (cross-ref Pattern 4 Warning).
451
-
452
- ### Lista canônica COMPLETA dos 6 grupos lógicos
453
-
454
- A documentação Supabase agrupa estes como **6 grupos lógicos** (Studio, Database, Auth Core/Email/Captcha/Hooks/SMS/External, Edge Runtime) — apresentamos expandido para máxima clareza por subcategoria.
455
-
456
- ### Grupo 1: Studio
457
-
458
- | Field | Caso de uso |
459
- |-------|-------------|
460
- | `studio.openai_api_key` | Studio AI features (SQL suggestions, schema generation) |
461
-
462
- ### Grupo 2: Database
463
-
464
- | Field | Caso de uso |
465
- |-------|-------------|
466
- | `db.root_key` | Root key para encryption-at-rest (Vault) |
467
- | `db.vault.*` (todas subkeys) | Supabase Vault — encryption keys gerenciadas |
468
-
469
- ### Grupo 3: Auth Core
470
-
471
- | Field | Caso de uso |
472
- |-------|-------------|
473
- | `auth.publishable_key` | API publishable key (substitui anon key v2) |
474
- | `auth.secret_key` | API secret key (substitui service_role key v2) |
475
- | `auth.jwt_secret` | JWT signing secret (HS256) |
476
-
477
- ### Grupo 4: Auth Email
478
-
479
- | Field | Caso de uso |
480
- |-------|-------------|
481
- | `auth.email.smtp.pass` | Password do SMTP server (SendGrid, AWS SES, Mailgun, etc.) |
482
-
483
- ### Grupo 5: Auth Captcha
484
-
485
- | Field | Caso de uso |
486
- |-------|-------------|
487
- | `auth.captcha.secret` | hCaptcha ou Turnstile secret key |
488
-
489
- ### Grupo 6: Auth Hooks
490
-
491
- Todos os 6 Auth Hooks (cross-ref skill `supabase-custom-claims-rbac` v1.25):
492
-
493
- | Field | Caso de uso |
494
- |-------|-------------|
495
- | `auth.hook.mfa_verification_attempt.secrets` | Custom MFA verification hook |
496
- | `auth.hook.password_verification_attempt.secrets` | Custom password verification hook |
497
- | `auth.hook.custom_access_token.secrets` | Custom Access Token Auth Hook (RBAC v1.25) |
498
- | `auth.hook.send_sms.secrets` | Custom SMS sender hook |
499
- | `auth.hook.send_email.secrets` | Custom email sender hook |
500
- | `auth.hook.before_user_created.secrets` | Hook para validar/rejeitar signup |
501
-
502
- ### Grupo 7: Auth SMS providers
503
-
504
- 5 providers SMS canônicos:
505
-
506
- | Field | Caso de uso |
507
- |-------|-------------|
508
- | `auth.sms.twilio.auth_token` | Twilio SMS provider |
509
- | `auth.sms.twilio_verify.auth_token` | Twilio Verify (MFA) |
510
- | `auth.sms.messagebird.access_key` | MessageBird provider |
511
- | `auth.sms.textlocal.api_key` | Textlocal (UK provider) |
512
- | `auth.sms.vonage.api_secret` | Vonage (ex-Nexmo) |
513
-
514
- ### Grupo 8: Auth External providers
515
-
516
- | Field | Caso de uso |
517
- |-------|-------------|
518
- | `auth.external.<provider>.secret` | Qualquer OAuth provider — github, google, facebook, apple, twitter, discord, gitlab, bitbucket, azure, linkedin, notion, slack, spotify, twitch, kakao, keycloak, workos, zoom, figma, fly |
519
-
520
- ### Grupo 9: Edge Runtime
521
-
522
- | Field | Caso de uso |
523
- |-------|-------------|
524
- | `edge_runtime.secrets.*` (todas subkeys) | Env vars custom para Edge Functions (SENDGRID, STRIPE, OPENAI, etc.) |
525
-
526
- ### Exemplo TOML completo cobrindo múltiplos grupos
527
-
528
- ```toml
529
- # Grupo 1: Studio
530
- [studio]
531
- openai_api_key = "encrypted:LSi...studio-key-encrypted...=="
532
-
533
- # Grupo 2: Database (Vault)
534
- [db.vault]
535
- secret_master_key = "encrypted:LSi...vault-master-encrypted...=="
536
-
537
- # Grupo 3: Auth Core
538
- [auth]
539
- jwt_secret = "encrypted:LSi...jwt-secret-encrypted...=="
540
- secret_key = "encrypted:LSi...secret-key-encrypted...=="
541
-
542
- # Grupo 4: Auth Email
543
- [auth.email.smtp]
544
- host = "smtp.sendgrid.net"
545
- port = 587
546
- user = "apikey"
547
- pass = "encrypted:LSi...smtp-pass-encrypted...=="
548
-
549
- # Grupo 5: Auth Captcha
550
- [auth.captcha]
551
- enabled = true
552
- provider = "hcaptcha"
553
- secret = "encrypted:LSi...captcha-secret-encrypted...=="
554
-
555
- # Grupo 6: Auth Hooks
556
- [auth.hook.custom_access_token]
557
- enabled = true
558
- uri = "pg-functions://postgres/auth/custom_access_token_hook"
559
- secrets = "encrypted:LSi...hook-secret-encrypted...=="
560
-
561
- [auth.hook.send_email]
562
- enabled = true
563
- uri = "https://example.com/auth/send-email-hook"
564
- secrets = "encrypted:LSi...email-hook-secret-encrypted...=="
565
-
566
- # Grupo 7: Auth SMS (Twilio)
567
- [auth.sms.twilio]
568
- enabled = true
569
- account_sid = "ACxxxxxxxxxxxx"
570
- message_service_sid = "MGxxxxxxxxxxxx"
571
- auth_token = "encrypted:LSi...twilio-token-encrypted...=="
572
-
573
- # Grupo 8: Auth External (GitHub OAuth)
574
- [auth.external.github]
575
- enabled = true
576
- client_id = "Iv1.xxxxxxx"
577
- secret = "encrypted:LSi...github-secret-encrypted...=="
578
-
579
- # Grupo 9: Edge Runtime
580
- [edge_runtime.secrets]
581
- OPENAI_API_KEY = "encrypted:LSi...openai-edge-encrypted...=="
582
- SENDGRID_API_KEY = "encrypted:LSi...sendgrid-edge-encrypted...=="
583
- STRIPE_SECRET_KEY = "encrypted:LSi...stripe-edge-encrypted...=="
584
- ```
585
-
586
- ### Caveat — lista pode evoluir com versões do CLI
587
-
588
- A lista de designated secret fields pode evoluir com novas versões do Supabase CLI (novos providers OAuth, novos Auth Hooks, etc.). Para refresh periódico:
589
-
590
- ```bash
591
- # verificar versão do CLI
592
- supabase --version
593
-
594
- # consultar doc oficial:
595
- # https://supabase.com/docs/guides/local-development/cli/config
596
- ```
597
-
598
- **Recomendação canônica:** review trimestral da lista vs doc oficial — Supabase publica updates regularmente.
599
-
600
- ## Anti-patterns
601
-
602
- ### Anti-pattern 1: Usar `encrypted:` em field não-designated
603
-
604
- **Errado:**
605
-
606
- ```toml
607
- [auth.email.smtp]
608
- host = "encrypted:LSi...wrong-host...==" # smtp.host NÃO é designated
609
- port = 587
610
- ```
611
-
612
- **Por quê:** valor literal é usado como string — SMTP tenta conectar em host literal `"encrypted:LSi...=="`, DNS lookup falha silenciosamente, emails não são enviados, sem erro claro no log.
613
-
614
- **Certo:** consultar Pattern 5 — usar `encrypted:` APENAS nos grupos canônicos. Para `auth.email.smtp.host` use plaintext (não é secret) ou `env(SMTP_HOST)`:
615
-
616
- ```toml
617
- [auth.email.smtp]
618
- host = "smtp.sendgrid.net" # plaintext OK (não é secret)
619
- port = 587
620
- user = "apikey"
621
- pass = "encrypted:LSi...correct-pass...==" # designated secret field
622
- ```
623
-
624
- ### Anti-pattern 2: Assumir secrets herdam entre branches
625
-
626
- **Errado:** criar `staging` branch e assumir que `SENDGRID_API_KEY` do `main` está disponível.
627
-
628
- ```bash
629
- supabase --experimental branches create staging --persistent
630
- # (assume erradamente que secrets do main foram copiados)
631
-
632
- # Edge Function no staging — falha
633
- const apiKey = Deno.env.get("SENDGRID_API_KEY"); // undefined
634
- ```
635
-
636
- **Por quê:** secrets são **per-branch** — staging tem env vars vazias até `supabase secrets set` rodar separadamente; Edge Functions retornam `undefined`; código quebra sem erro claro no DAG.
637
-
638
- **Certo:** rodar `supabase secrets set --env-file` para **CADA branch** (main + staging + preview + production):
639
-
640
- ```bash
641
- # para cada branch
642
- for branch in main staging production; do
643
- supabase link --project-ref "${branch}-project-ref"
644
- supabase secrets set --env-file "./supabase/.env.${branch}"
645
- done
646
- ```
647
-
648
- Documentar workflow no onboarding do projeto.
649
-
650
- ### Anti-pattern 3: Commitar `.env.keys` no git
651
-
652
- **Errado:** `.env.keys` aparece em `git status` e dev faz `git add` distraído:
653
-
654
- ```bash
655
- git status
656
- # Changes not staged for commit:
657
- # modified: supabase/.env.preview
658
- # modified: .env.keys ← BLOQUEANTE
659
- git add .
660
- git commit -m "feat: add preview secrets" # vazou a chave master
661
- git push
662
- ```
663
-
664
- **Por quê:** `.env.keys` é a chave de **decryption master** — com ela, qualquer um decripta `.env.preview`/`.env.production` e tem acesso a TODOS os secrets encrypted; equivalente a vazar password master + todos os tokens OAuth + todas as API keys de uma vez.
665
-
666
- **Certo:**
667
-
668
- ```bash
669
- # adicionar SEMPRE ao .gitignore — ANTES de qualquer set
670
- echo ".env.keys" >> .gitignore
671
- git add .gitignore
672
- git commit -m "chore: gitignore dotenvx decryption key"
673
- ```
674
-
675
- Se foi committed por engano:
676
-
677
- 1. `git filter-repo` (ou BFG) para limpar history
678
- 2. **Rotacionar TODOS os secrets encrypted imediatamente** — sem confiar que ninguém viu antes
679
- 3. Re-encrypt valores em `.env.preview`/`.env.production` com nova `.env.keys`
680
- 4. Force-push branches afetados
681
- 5. Notificar team + auditar acessos
682
-
683
- ### Anti-pattern 4: Confundir `env()` vs `encrypted:` syntax
684
-
685
- **Errado:** tentar combinar os dois prefixos:
686
-
687
- ```toml
688
- [auth.external.github]
689
- secret = "encrypted:env(GITHUB_SECRET)" # syntax inválida — mistura prefixos
690
- ```
691
-
692
- **Por quê:** Supabase CLI parser não combina os dois — valor literal `"encrypted:env(GITHUB_SECRET)"` é usado como string, OAuth callback falha com `invalid client_secret`.
693
-
694
- **Certo:** escolher UM:
695
-
696
- ```toml
697
- # Option A: env() resolve via env var
698
- [auth.external.github]
699
- secret = "env(GITHUB_SECRET)"
700
-
701
- # Option B: encrypted: via dotenvx decryption
702
- [auth.external.github]
703
- secret = "encrypted:LSi...payload-encrypted...=="
704
- ```
705
-
706
- Nunca combinar.
707
-
708
- ### Anti-pattern 5: Reusar `project_id` entre `[remotes]` blocks
709
-
710
- **Errado:**
711
-
712
- ```toml
713
- [remotes.staging]
714
- project_id = "main-project-ref" # ← mesmo ref do main
715
-
716
- [remotes.production]
717
- project_id = "main-project-ref" # ← mesmo ref do main
718
- ```
719
-
720
- **Por quê:** `[remotes.<name>]` deve apontar para branch **DEDICADO** criado via `supabase --experimental branches create`; usar mesmo `project_id` para múltiplos `[remotes]` causa configs sobrescritas no DAG step 4 (configure) — última definição vence, comportamento imprevisível.
721
-
722
- **Certo:** criar branch por ambiente + obter `project_id` único:
723
-
724
- ```bash
725
- supabase --experimental branches create staging --persistent
726
- supabase --experimental branches create production --persistent
727
- supabase --experimental branches list
728
- # BRANCH NAME BRANCH PROJECT ID
729
- # main main-project-ref
730
- # staging staging-dedicated-ref
731
- # production production-dedicated-ref
732
- ```
733
-
734
- ```toml
735
- [remotes.staging]
736
- project_id = "staging-dedicated-ref"
737
-
738
- [remotes.production]
739
- project_id = "production-dedicated-ref"
740
- ```
741
-
742
- ### Anti-pattern 6: Esperar `env()` em config.toml resolver para secrets do projeto
743
-
744
- **Errado:** setar secret via `supabase secrets set` e esperar que `config.toml` com `env()` resolva:
745
-
746
- ```bash
747
- # setar secret no projeto (runtime Edge Functions)
748
- supabase secrets set SENDGRID_API_KEY=sk-real-key
749
-
750
- # config.toml
751
- [edge_runtime.secrets]
752
- # expecta erradamente que o secret do projeto seja resolvido
753
- SENDGRID_API_KEY = "env(SENDGRID_API_KEY)"
754
- ```
755
-
756
- **Por quê:** `env()` em config.toml resolve para env var **do CLI local** (build-time), **NÃO para secrets do projeto Supabase** (runtime das Edge Functions). Se o shell que roda o CLI não tem `SENDGRID_API_KEY` exportado, resolve para string vazia → config quebrada.
757
-
758
- **Certo:**
759
-
760
- - **Para secrets de Edge Functions runtime:** `supabase secrets set` + `Deno.env.get("SENDGRID_API_KEY")` no código Deno
761
- - **Para config.toml build-time:** setar env var no shell antes de rodar CLI:
762
-
763
- ```bash
764
- export SENDGRID_API_KEY=sk-build-time-key
765
- supabase db push
766
- # config.toml com env(SENDGRID_API_KEY) resolve para "sk-build-time-key"
767
- ```
768
-
769
- Em workflow CI (GitHub Actions): expor secret no env do step:
770
-
771
- ```yaml
772
- - name: Push to Supabase
773
- env:
774
- SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
775
- run: supabase db push
776
- ```
777
-
778
- ## Cross-suite integration (v1.27)
779
-
780
- Esta skill é par-conjugado com `supabase-branching-workflow` (Phase 149) — branching workflow descreve **quando** branches são criados; config-toml-remotes descreve **como** configurar.
781
-
782
- Cross-refs canônicas com outras skills v1.27 (Phases 150-153):
783
-
784
- - **supabase-branching-workflow** (Phase 149) — Deploy DAG step 4 (configure) lê `[remotes.<branch>]` block desta skill
785
- - **supabase-ci-cd-github-actions** (Phase 151, futura) — 8 workflows GitHub Actions que exportam env vars + rodam `supabase db push` com `--env-file` (cross-ref Pattern 3 + Pattern 4)
786
- - **supabase-pgtap-testing** (Phase 152, futura) — testes pgTAP que rodam em remote branches via `--db-url` derivada de `[remotes.<branch>]`
787
- - **supabase-migration-repair** (Phase 153, futura) — `migration repair` per `[remotes.<branch>]` quando drift detectado
788
-
789
- Base para agent novo v1.27:
790
-
791
- - **supabase-cicd-pipeline-implementer** (Phase 154, futura) — recebe spec via `Task()` e materializa `[remotes.<branch>]` blocks na config + GitHub Actions workflows com dotenvx integration
792
-
793
- Pattern de handoff cooperativo herdado v1.23-v1.26: **architect** projeta strategy → **cicd-pipeline-implementer** materializa → **release-pipeline-auditor** (v1.10) audita hermeticidade. Nenhum agente descarta upstream — handoff cooperativo SQL (princípio canônico v1.23).
794
-
795
- ## Ver também
796
-
797
- - [supabase-branching-workflow](../supabase-branching-workflow/SKILL.md) (v1.27, Phase 149) — pré-requisito conceitual; Deploy DAG step 4 (configure) aplica `[remotes]`
798
- - [supabase-ci-cd-github-actions](../supabase-ci-cd-github-actions/SKILL.md) (v1.27, Phase 151) — workflows GitHub Actions com `--env-file` + `supabase secrets set`
799
- - [supabase-pgtap-testing](../supabase-pgtap-testing/SKILL.md) (v1.27, Phase 152) — testes que rodam em remote branches via `--db-url`
800
- - [supabase-migration-repair](../supabase-migration-repair/SKILL.md) (v1.27, Phase 153) — `migration repair` per `[remotes.<branch>]`
801
- - [supabase-migrations](../supabase-migrations/SKILL.md) (v1.23) — migrations aplicadas no branch via `supabase db push --linked`
802
- - [supabase-edge-functions](../supabase-edge-functions/SKILL.md) — `Deno.env.get()` lê secrets setados via `supabase secrets set --env-file`
803
- - [supabase-auth-ssr](../supabase-auth-ssr/SKILL.md) — `auth.external.*.secret` encrypted fields usados no auth flow
804
- - [supabase-custom-claims-rbac](../supabase-custom-claims-rbac/SKILL.md) (v1.25) — `auth.hook.custom_access_token.secrets` é Auth Hook (Grupo 6)
805
- - [supabase-postgres-roles](../supabase-postgres-roles/SKILL.md) (v1.26) — cross-ref para system access via secrets DB (`db.root_key`, `db.vault`)
806
- - [glossário compartilhado](../_shared-supabase/glossary.md) — termos `[remotes]`, encrypted:, env(), dotenvx, .env.keys, .env.preview, designated secret fields, branch project_id
807
- - Doc oficial: [Branching Configuration](https://supabase.com/docs/guides/deployment/branching#configuration), [Config Reference](https://supabase.com/docs/guides/local-development/cli/config), [dotenvx](https://dotenvx.com/), [Auth Hooks](https://supabase.com/docs/guides/auth/auth-hooks)
1
+ ---
2
+ name: supabase-config-toml-remotes
3
+ description: Use ao configurar Supabase para branching — `[remotes.<name>]` block + branch-specific overrides + secrets per-branch (NÃO herdam) + dotenvx pattern (.env.keys + .env.preview encrypted) + 6…
4
+ ---
5
+
6
+ # Supabase — Config TOML & Remotes
7
+
8
+ ## Quando usar
9
+
10
+ Branching Supabase exige configuração per-branch via `supabase/config.toml` — blocos `[remotes.<name>]` declaram **overrides versionados em git** que o Deploy DAG step 4 (configure) aplica em cada branch.
11
+
12
+ Esta skill é par-conjugado com `supabase-branching-workflow` (Phase 149) — branching workflow descreve **quando** branches são criados; esta skill descreve **como** configurar.
13
+
14
+ Trigger phrases:
15
+
16
+ - "remotes block Supabase", "[remotes] config.toml"
17
+ - "branch-specific config Supabase", "config.toml staging override"
18
+ - "secrets per-branch Supabase", "supabase secrets set"
19
+ - "dotenvx Supabase", ".env.keys .env.preview"
20
+ - "encrypted: Supabase config", "env() vs encrypted: syntax"
21
+ - "Supabase encrypted fields", "auth.hook secrets encrypted"
22
+ - "designated secret fields"
23
+ - "branch project_id Supabase"
24
+
25
+ **Use APENAS para:**
26
+
27
+ - Configurar persistent branches (staging, QA, production) via `[remotes.<branch>]` block
28
+ - Materializar overrides per-ambiente (db.pool_size, api.max_rows, auth.external.*, edge_runtime.secrets)
29
+ - Gerenciar secrets per-branch via `supabase secrets set --env-file`
30
+ - Versionar secrets encrypted em git via dotenvx pattern (.env.keys + .env.preview/.env.production)
31
+
32
+ **NÃO use para:**
33
+
34
+ - Substituir secret vault corporativo (Vault, AWS Secrets Manager) — dotenvx é git-tracked encrypted; vault corporativo tem audit trail + rotation policies
35
+ - Gerenciar secrets de runtime de Edge Functions sem `supabase secrets set` — `env()` em config.toml é build-time do CLI, não runtime do projeto
36
+ - Versionar a chave de decryption (`.env.keys`) — NUNCA committar; é equivalente a vazar password master
37
+ - Apontar `[remotes.<name>]` para branch deletado — operações falham silenciosamente
38
+
39
+ ## Princípio canônico
40
+
41
+ Três princípios canônicos:
42
+
43
+ 1. **`config.toml` é source of truth versionado.** `[remotes.<branch>]` block declara overrides explícitos commitados em git — Deploy DAG step 4 (configure) re-aplica em cada deploy. Sem deriva entre o que está em git e o que está no branch.
44
+
45
+ 2. **dotenvx para secrets git-tracked.** `.env.keys` (decryption key, **SEMPRE gitignored**) + `.env.preview`/`.env.production` (encrypted values, committed em git). Permite versionar secrets sem expor — git history rastreia mudanças de secrets sem PII em plaintext.
46
+
47
+ 3. **Secrets NÃO herdam entre branches.** Cada branch tem credenciais únicas; criar persistent branch `staging` NÃO copia secrets do `main`. Reset manual via `supabase secrets set --env-file` para CADA branch — incluindo o branch `main` original.
48
+
49
+ ### Distinção canônica `env()` vs `encrypted:`
50
+
51
+ | | `env(VAR_NAME)` | `encrypted:<value>` |
52
+ |---|---|---|
53
+ | Resolução | Runtime CLI (build-time) | Decryption via `.env.keys` |
54
+ | Onde funciona | **Qualquer** field em config.toml | **APENAS** designated secret fields (Pattern 5) |
55
+ | Workflow | Setar env var no shell antes do CLI | Encriptar via `dotenvx set`, committed em git |
56
+ | Caveat | Resolve para env var **local** do CLI, NÃO para secrets do projeto Supabase (runtime das Edge Functions) | Em field **não-designated** é silent no-op (literal string usada como valor) |
57
+ | Caso de uso | Secrets em env vars do CI (GitHub Actions) | Secrets versionados encrypted em git via dotenvx |
58
+
59
+ ## Pattern 1: `[remotes]` block — referenciar branch existente (CFG-01)
60
+
61
+ `[remotes.<name>]` em `config.toml` declara que **este bloco se aplica APENAS ao branch nomeado** identificado pelo `project_id`.
62
+
63
+ ### Pré-requisito
64
+
65
+ Branch já criado (persistent via CLI ou preview via PR webhook):
66
+
67
+ ```bash
68
+ # criar persistent branch via CLI
69
+ supabase --experimental branches create staging --persistent
70
+
71
+ # (preview branches são criados automaticamente via GitHub PR — cross-ref skill supabase-branching-workflow Pattern 3)
72
+ ```
73
+
74
+ ### Workflow canônico
75
+
76
+ **Step 1: Obter `project_id` do branch:**
77
+
78
+ ```bash
79
+ supabase --experimental branches list
80
+
81
+ # output esperado:
82
+ # BRANCH NAME BRANCH PROJECT ID STATUS
83
+ # main main-project-ref active
84
+ # staging staging-dedicated-ref active
85
+ # pr-42-feature pr42-feature-ref active
86
+ ```
87
+
88
+ **Step 2: Adicionar `[remotes.<branch>]` block no `supabase/config.toml`:**
89
+
90
+ ```toml
91
+ [remotes.staging]
92
+ project_id = "staging-dedicated-ref"
93
+
94
+ [remotes.staging.db.seed]
95
+ enabled = true
96
+ sql_paths = ["./seeds/staging.sql"]
97
+ ```
98
+
99
+ **Step 3: Commitar `config.toml` em git → Deploy DAG step 4 (configure) aplica overrides no branch.**
100
+
101
+ ### Exemplo TOML — múltiplos branches
102
+
103
+ ```toml
104
+ # bloco base — aplica a TODOS os branches (incluindo main)
105
+ [db]
106
+ port = 54322
107
+ pool_size = 15
108
+
109
+ [api]
110
+ port = 54321
111
+ max_rows = 1000
112
+
113
+ # branch staging — overrides específicos
114
+ [remotes.staging]
115
+ project_id = "staging-dedicated-ref"
116
+
117
+ [remotes.staging.db.seed]
118
+ enabled = true
119
+ sql_paths = ["./seeds/staging.sql"]
120
+
121
+ # branch production — sem seeds em produção
122
+ [remotes.production]
123
+ project_id = "production-dedicated-ref"
124
+
125
+ [remotes.production.db.seed]
126
+ enabled = false
127
+ ```
128
+
129
+ ### Caveat — branch deletado
130
+
131
+ `project_id` deve ser de branch **existente**. Se branch foi deletado:
132
+
133
+ - Bloco `[remotes.<branch>]` continua válido sintaticamente
134
+ - CLI rejeita commands com erro `branch not found`
135
+ - DAG step 4 (configure) silenciosamente skip o branch deletado
136
+
137
+ **Mitigação:** revisão trimestral — `supabase --experimental branches list` + remover blocos `[remotes.<deleted>]` correspondentes.
138
+
139
+ ### Caveat — `project_id` único por bloco
140
+
141
+ Cada `[remotes.<name>]` deve apontar para **branch dedicado** criado especificamente. NÃO reutilizar `project_id` do `main` para `staging` (cross-ref Anti-pattern 5).
142
+
143
+ ## Pattern 2: Branch-specific configuration overrides (CFG-02)
144
+
145
+ Princípio: config base (sem `[remotes...]` prefix) aplica a TODOS os branches; `[remotes.<name>.<section>]` aplica override APENAS no branch nomeado.
146
+
147
+ ### Categorias de fields override-able (canônicas)
148
+
149
+ **db (database tuning):**
150
+
151
+ ```toml
152
+ [db]
153
+ port = 54322
154
+ pool_size = 15 # default
155
+
156
+ # staging override
157
+ [remotes.staging.db]
158
+ port = 54322 # mesma porta — só pool_size muda
159
+ pool_size = 25
160
+ ```
161
+
162
+ **api (PostgREST):**
163
+
164
+ ```toml
165
+ [api]
166
+ port = 54321
167
+ max_rows = 1000
168
+ schemas = ["public"]
169
+
170
+ # staging quer ver schema extensions para debug
171
+ [remotes.staging.api]
172
+ max_rows = 5000 # debug — limite maior
173
+ schemas = ["public", "extensions"]
174
+ ```
175
+
176
+ **db.seed:**
177
+
178
+ ```toml
179
+ # default — sem seed
180
+ [db.seed]
181
+ enabled = false
182
+ sql_paths = []
183
+
184
+ # staging — seed sintético para QA
185
+ [remotes.staging.db.seed]
186
+ enabled = true
187
+ sql_paths = ["./seeds/staging.sql"]
188
+
189
+ # preview — seed minimal para smoke tests
190
+ [remotes.preview.db.seed]
191
+ enabled = true
192
+ sql_paths = ["./seeds/preview-smoke.sql"]
193
+ ```
194
+
195
+ **auth.external.* (OAuth providers):**
196
+
197
+ ```toml
198
+ # production GitHub OAuth
199
+ [auth.external.github]
200
+ enabled = true
201
+ client_id = "Iv1.production-app-id"
202
+ secret = "encrypted:LSi...prod-github-secret-encrypted...=="
203
+
204
+ # staging GitHub OAuth — app diferente
205
+ [remotes.staging.auth.external.github]
206
+ enabled = true
207
+ client_id = "Iv1.staging-app-id"
208
+ secret = "encrypted:LSi...staging-github-secret-encrypted...=="
209
+ redirect_uri = "https://staging.example.com/auth/callback"
210
+ ```
211
+
212
+ **edge_runtime.secrets:**
213
+
214
+ ```toml
215
+ [edge_runtime.secrets]
216
+ SENDGRID_API_KEY = "encrypted:LSi...prod-sendgrid-encrypted...=="
217
+
218
+ # staging — SendGrid sandbox
219
+ [remotes.staging.edge_runtime.secrets]
220
+ SENDGRID_API_KEY = "encrypted:LSi...staging-sendgrid-encrypted...=="
221
+ SENDGRID_SANDBOX_MODE = "env(STAGING_SENDGRID_SANDBOX_MODE)"
222
+ ```
223
+
224
+ ### Tabela canônica de fields override-able
225
+
226
+ | Section | Fields | Caso de uso típico |
227
+ |---------|--------|---------------------|
228
+ | `db` | `port`, `pool_size` | Tuning pool size per ambiente (staging menor) |
229
+ | `api` | `port`, `max_rows`, `schemas` | Diferenciar response limits + schemas expostos |
230
+ | `db.seed` | `enabled`, `sql_paths` | Seeds diferentes por branch |
231
+ | `auth.external.<provider>` | `enabled`, `client_id`, `secret`, `redirect_uri` | OAuth keys per ambiente |
232
+ | `auth.email.smtp` | `host`, `port`, `user`, `pass` | SMTP staging vs produção |
233
+ | `auth.sms.<provider>` | `account_sid`, `auth_token`, etc. | SMS provider keys per ambiente |
234
+ | `edge_runtime.secrets.<KEY>` | custom env vars | API keys per branch (SendGrid, Stripe, OpenAI) |
235
+ | `studio.openai_api_key` | string | Key diferente para staging studio (lower limits) |
236
+
237
+ ### Caveat — merge behavior
238
+
239
+ `[remotes.staging.db]` com `pool_size = 25` NÃO sobrescreve `[db]` global completamente — apenas o field específico (`pool_size`). Outros fields do `[db]` global (port, etc.) continuam aplicados.
240
+
241
+ ```toml
242
+ # config base
243
+ [db]
244
+ port = 54322
245
+ pool_size = 15
246
+ shadow_port = 54320
247
+
248
+ # staging override — apenas pool_size muda
249
+ [remotes.staging.db]
250
+ pool_size = 25
251
+ # resultado em staging: port=54322, pool_size=25, shadow_port=54320 (mantidos da base)
252
+ ```
253
+
254
+ ### Caveat — re-deploy required
255
+
256
+ Alterações em `config.toml` precisam ser pushed para o branch — Deploy DAG step 4 (configure) só roda em novo deploy (push novo commit no PR ou re-run via Dashboard).
257
+
258
+ ## Pattern 3: Secrets management per-branch (CFG-03)
259
+
260
+ ### Caveat canônico — secrets NÃO herdam
261
+
262
+ > **Secrets NÃO herdam entre branches.** Criar persistent branch `staging` NÃO copia secrets do `main`. Cada branch precisa ter secrets setados separadamente.
263
+
264
+ Implicação prática:
265
+
266
+ - `Deno.env.get("SENDGRID_API_KEY")` em Edge Function no branch staging retorna `undefined` até `supabase secrets set` ser executado para o staging
267
+ - Esse comportamento é silent — sem warning no DAG, sem alert do CLI
268
+
269
+ ### CLI canônico
270
+
271
+ ```bash
272
+ # Set secrets a partir de .env file (recomendação canônica)
273
+ supabase secrets set --env-file ./supabase/.env
274
+
275
+ # Set secret individual
276
+ supabase secrets set SMTP_HOST=smtp.example.com
277
+
278
+ # Listar secrets do branch atual
279
+ supabase secrets list
280
+
281
+ # Remover secret
282
+ supabase secrets unset SMTP_HOST
283
+ ```
284
+
285
+ ### Workflow per-branch canônico
286
+
287
+ ```bash
288
+ # 1. criar staging branch
289
+ supabase --experimental branches create staging --persistent
290
+
291
+ # 2. obter project_id do staging
292
+ supabase --experimental branches list | grep staging
293
+ # output: staging staging-dedicated-ref active
294
+
295
+ # 3. link CLI para o branch staging
296
+ supabase link --project-ref staging-dedicated-ref
297
+
298
+ # 4. setar secrets DO STAGING (arquivo dedicado)
299
+ supabase secrets set --env-file ./supabase/.env.staging
300
+
301
+ # 5. validar — listar secrets do staging
302
+ supabase secrets list
303
+
304
+ # 6. voltar para main quando terminar
305
+ supabase link --project-ref main-project-ref
306
+ ```
307
+
308
+ ### Exemplo `.env.staging`
309
+
310
+ ```bash
311
+ # .env.staging — secrets específicos do branch staging
312
+ # Gitignored se não usa dotenvx (Pattern 4); encrypted se usa.
313
+ SMTP_HOST=smtp.staging.example.com
314
+ SMTP_USER=staging-user
315
+ SMTP_PASS=staging-pass
316
+ SENDGRID_API_KEY=SG.staging-api-key
317
+ OPENAI_API_KEY=sk-staging-openai-key
318
+ STRIPE_SECRET_KEY=sk_test_staging_stripe
319
+ ```
320
+
321
+ ### Caveat — secrets vs config.toml `env()`
322
+
323
+ Distinção CRÍTICA — fonte de confusão comum:
324
+
325
+ | | `supabase secrets set` | `env()` em config.toml |
326
+ |---|---|---|
327
+ | Resolvido | Runtime das **Edge Functions** | Build-time do **CLI local** |
328
+ | Acesso | `Deno.env.get("KEY")` no código Deno | Substituição literal no `config.toml` pré-deploy |
329
+ | Storage | Supabase backend (per-branch) | Env var do shell que rodou o CLI |
330
+ | Lifecycle | Persistido no branch | Volátil (só durante invocação do CLI) |
331
+
332
+ Exemplo concreto:
333
+
334
+ ```bash
335
+ # Setar secret no branch (runtime Edge Function)
336
+ supabase secrets set SENDGRID_API_KEY=sk-real-key
337
+ # → Deno.env.get("SENDGRID_API_KEY") em Edge Function retorna "sk-real-key"
338
+
339
+ # Setar env var local (build-time config.toml)
340
+ export SENDGRID_API_KEY=sk-different-key
341
+ supabase db push
342
+ # → config.toml com env(SENDGRID_API_KEY) resolve para "sk-different-key" (do shell)
343
+ # → Edge Function ainda retorna "sk-real-key" (do supabase secrets set anterior)
344
+ ```
345
+
346
+ ### Recomendação canônica
347
+
348
+ Usar **dotenvx pattern** (Pattern 4) para versionar secrets encrypted em git em vez de gerenciar `.env.staging` separadamente em cada máquina.
349
+
350
+ ## Pattern 4: dotenvx pattern + `encrypted:` vs `env()` syntax (CFG-04)
351
+
352
+ ### Princípio dotenvx
353
+
354
+ dotenvx ([dotenvx.com](https://dotenvx.com/)) é uma evolução de `dotenv` que permite **encryption symmetric** de valores no arquivo `.env`:
355
+
356
+ - Encrypted values podem ser committed em git (`.env.preview`, `.env.production`)
357
+ - Decryption key (`.env.keys`) **NUNCA é committed** — gitignored sempre
358
+ - Permite versionar secrets sem expor — git history rastreia mudanças de secrets sem PII em plaintext
359
+
360
+ ### Tabela canônica de file types (dotenvx convenção)
361
+
362
+ | File | Env | gitignore | Encrypted | Caso de uso |
363
+ |------|-----|-----------|-----------|-------------|
364
+ | `.env.keys` | All | **YES** (NUNCA committar) | No (key plaintext) | Decryption master key |
365
+ | `.env.local` | Local dev | YES | No (plaintext OK local) | Overrides de dev individual |
366
+ | `.env.production` | Production | No (committed) | YES | Secrets de produção encrypted |
367
+ | `.env.preview` | Branches preview | No (committed) | YES | Secrets de preview branches encrypted |
368
+ | `.env` | Any (fallback) | Maybe | YES | Default file (custom) |
369
+
370
+ **Atenção canônica:** `.env.keys` em `.gitignore` é obrigação canônica — sem isso, o pattern dotenvx é equivalente a commitar secrets plaintext.
371
+
372
+ ### Workflow canônico dotenvx
373
+
374
+ ```bash
375
+ # 1. instalar dotenvx (devDependency)
376
+ npm install -D @dotenvx/dotenvx
377
+
378
+ # 2. adicionar .env.keys ao .gitignore (BLOQUEANTE — fazer ANTES de qualquer set)
379
+ echo ".env.keys" >> .gitignore
380
+ git add .gitignore
381
+ git commit -m "chore: gitignore dotenvx decryption key"
382
+
383
+ # 3. encrypted set — gera .env.keys automaticamente na primeira vez
384
+ npx @dotenvx/dotenvx set SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET "ghs_real_secret" -f supabase/.env.preview
385
+ # Output:
386
+ # set SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET (encrypted) (.env.preview)
387
+ # wrote new public-private encryption keys to .env.keys
388
+
389
+ # 4. commitar .env.preview (encrypted) + verificar .env.keys NÃO foi committed
390
+ git status
391
+ # modified: supabase/.env.preview
392
+ # (.env.keys NÃO deve aparecer)
393
+ git add supabase/.env.preview
394
+ git commit -m "feat: add encrypted GitHub OAuth secret for preview"
395
+
396
+ # 5. usar com supabase CLI (carregar via --env-file)
397
+ npx supabase secrets set --env-file supabase/.env.keys
398
+ # ou em workflow CI (decripta + roda CLI):
399
+ npx @dotenvx/dotenvx run -- supabase secrets set --env-file supabase/.env.preview
400
+ ```
401
+
402
+ ### Sintaxes em `config.toml`
403
+
404
+ **Option A: `encrypted:<value>` directly em designated secret field:**
405
+
406
+ ```toml
407
+ [auth.external.github]
408
+ enabled = true
409
+ client_id = "Iv1.app-id-public"
410
+ # secret é designated secret field (Pattern 5 Grupo 8) — encrypted: é decriptado via .env.keys
411
+ secret = "encrypted:LSiME...github-secret-encrypted-payload...=="
412
+ ```
413
+
414
+ **Option B: `env(VAR_NAME)` para resolver via env var (qualquer field):**
415
+
416
+ ```toml
417
+ [auth.external.github]
418
+ enabled = true
419
+ client_id = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_CLIENT_ID)"
420
+ secret = "env(SUPABASE_AUTH_EXTERNAL_GITHUB_SECRET)"
421
+ ```
422
+
423
+ ### Warning canônico — `encrypted:` é restrito
424
+
425
+ > **`encrypted:` syntax SÓ funciona em designated secret fields** (Pattern 5 — 6 grupos canônicos). Em outros campos não decripta silenciosamente — o valor literal `"encrypted:LSiME..."` é usado como string, expondo o payload encrypted como se fosse plaintext.
426
+
427
+ Exemplo concreto do falso silencioso:
428
+
429
+ ```toml
430
+ # ERRADO — auth.email.smtp.host NÃO é designated secret field
431
+ [auth.email.smtp]
432
+ host = "encrypted:LSi...wrong...==" # ← silent no-op
433
+ # resultado: SMTP tenta conectar em host literal "encrypted:LSi...wrong...==" → DNS fail
434
+
435
+ # CERTO — auth.email.smtp.pass É designated (Pattern 5 Grupo 4)
436
+ [auth.email.smtp]
437
+ host = "smtp.example.com" # plain
438
+ pass = "encrypted:LSi...correct-pass...==" # ← decriptado
439
+ ```
440
+
441
+ ### Quando usar qual
442
+
443
+ - **`encrypted:`** — quando quer versionar o secret **encrypted em git** (workflow dotenvx); aplicar APENAS em fields designados (Pattern 5)
444
+ - **`env()`** — quando secrets vivem em env vars do CI/local; works em **qualquer field**; flexibilidade ao custo de não versionar em git (rotação via update env var no CI)
445
+
446
+ Recomendação canônica para teams maduros: `encrypted:` em produção (auditável via git history) + `env()` em dev local (volátil).
447
+
448
+ ## Pattern 5: 6 grupos de encrypted fields canônicos (CFG-05)
449
+
450
+ Princípio: apenas estes fields aceitam `encrypted:<value>` syntax — qualquer outro field é **silent no-op** (cross-ref Pattern 4 Warning).
451
+
452
+ ### Lista canônica COMPLETA dos 6 grupos lógicos
453
+
454
+ A documentação Supabase agrupa estes como **6 grupos lógicos** (Studio, Database, Auth Core/Email/Captcha/Hooks/SMS/External, Edge Runtime) — apresentamos expandido para máxima clareza por subcategoria.
455
+
456
+ ### Grupo 1: Studio
457
+
458
+ | Field | Caso de uso |
459
+ |-------|-------------|
460
+ | `studio.openai_api_key` | Studio AI features (SQL suggestions, schema generation) |
461
+
462
+ ### Grupo 2: Database
463
+
464
+ | Field | Caso de uso |
465
+ |-------|-------------|
466
+ | `db.root_key` | Root key para encryption-at-rest (Vault) |
467
+ | `db.vault.*` (todas subkeys) | Supabase Vault — encryption keys gerenciadas |
468
+
469
+ ### Grupo 3: Auth Core
470
+
471
+ | Field | Caso de uso |
472
+ |-------|-------------|
473
+ | `auth.publishable_key` | API publishable key (substitui anon key v2) |
474
+ | `auth.secret_key` | API secret key (substitui service_role key v2) |
475
+ | `auth.jwt_secret` | JWT signing secret (HS256) |
476
+
477
+ ### Grupo 4: Auth Email
478
+
479
+ | Field | Caso de uso |
480
+ |-------|-------------|
481
+ | `auth.email.smtp.pass` | Password do SMTP server (SendGrid, AWS SES, Mailgun, etc.) |
482
+
483
+ ### Grupo 5: Auth Captcha
484
+
485
+ | Field | Caso de uso |
486
+ |-------|-------------|
487
+ | `auth.captcha.secret` | hCaptcha ou Turnstile secret key |
488
+
489
+ ### Grupo 6: Auth Hooks
490
+
491
+ Todos os 6 Auth Hooks (cross-ref skill `supabase-custom-claims-rbac` v1.25):
492
+
493
+ | Field | Caso de uso |
494
+ |-------|-------------|
495
+ | `auth.hook.mfa_verification_attempt.secrets` | Custom MFA verification hook |
496
+ | `auth.hook.password_verification_attempt.secrets` | Custom password verification hook |
497
+ | `auth.hook.custom_access_token.secrets` | Custom Access Token Auth Hook (RBAC v1.25) |
498
+ | `auth.hook.send_sms.secrets` | Custom SMS sender hook |
499
+ | `auth.hook.send_email.secrets` | Custom email sender hook |
500
+ | `auth.hook.before_user_created.secrets` | Hook para validar/rejeitar signup |
501
+
502
+ ### Grupo 7: Auth SMS providers
503
+
504
+ 5 providers SMS canônicos:
505
+
506
+ | Field | Caso de uso |
507
+ |-------|-------------|
508
+ | `auth.sms.twilio.auth_token` | Twilio SMS provider |
509
+ | `auth.sms.twilio_verify.auth_token` | Twilio Verify (MFA) |
510
+ | `auth.sms.messagebird.access_key` | MessageBird provider |
511
+ | `auth.sms.textlocal.api_key` | Textlocal (UK provider) |
512
+ | `auth.sms.vonage.api_secret` | Vonage (ex-Nexmo) |
513
+
514
+ ### Grupo 8: Auth External providers
515
+
516
+ | Field | Caso de uso |
517
+ |-------|-------------|
518
+ | `auth.external.<provider>.secret` | Qualquer OAuth provider — github, google, facebook, apple, twitter, discord, gitlab, bitbucket, azure, linkedin, notion, slack, spotify, twitch, kakao, keycloak, workos, zoom, figma, fly |
519
+
520
+ ### Grupo 9: Edge Runtime
521
+
522
+ | Field | Caso de uso |
523
+ |-------|-------------|
524
+ | `edge_runtime.secrets.*` (todas subkeys) | Env vars custom para Edge Functions (SENDGRID, STRIPE, OPENAI, etc.) |
525
+
526
+ ### Exemplo TOML completo cobrindo múltiplos grupos
527
+
528
+ ```toml
529
+ # Grupo 1: Studio
530
+ [studio]
531
+ openai_api_key = "encrypted:LSi...studio-key-encrypted...=="
532
+
533
+ # Grupo 2: Database (Vault)
534
+ [db.vault]
535
+ secret_master_key = "encrypted:LSi...vault-master-encrypted...=="
536
+
537
+ # Grupo 3: Auth Core
538
+ [auth]
539
+ jwt_secret = "encrypted:LSi...jwt-secret-encrypted...=="
540
+ secret_key = "encrypted:LSi...secret-key-encrypted...=="
541
+
542
+ # Grupo 4: Auth Email
543
+ [auth.email.smtp]
544
+ host = "smtp.sendgrid.net"
545
+ port = 587
546
+ user = "apikey"
547
+ pass = "encrypted:LSi...smtp-pass-encrypted...=="
548
+
549
+ # Grupo 5: Auth Captcha
550
+ [auth.captcha]
551
+ enabled = true
552
+ provider = "hcaptcha"
553
+ secret = "encrypted:LSi...captcha-secret-encrypted...=="
554
+
555
+ # Grupo 6: Auth Hooks
556
+ [auth.hook.custom_access_token]
557
+ enabled = true
558
+ uri = "pg-functions://postgres/auth/custom_access_token_hook"
559
+ secrets = "encrypted:LSi...hook-secret-encrypted...=="
560
+
561
+ [auth.hook.send_email]
562
+ enabled = true
563
+ uri = "https://example.com/auth/send-email-hook"
564
+ secrets = "encrypted:LSi...email-hook-secret-encrypted...=="
565
+
566
+ # Grupo 7: Auth SMS (Twilio)
567
+ [auth.sms.twilio]
568
+ enabled = true
569
+ account_sid = "ACxxxxxxxxxxxx"
570
+ message_service_sid = "MGxxxxxxxxxxxx"
571
+ auth_token = "encrypted:LSi...twilio-token-encrypted...=="
572
+
573
+ # Grupo 8: Auth External (GitHub OAuth)
574
+ [auth.external.github]
575
+ enabled = true
576
+ client_id = "Iv1.xxxxxxx"
577
+ secret = "encrypted:LSi...github-secret-encrypted...=="
578
+
579
+ # Grupo 9: Edge Runtime
580
+ [edge_runtime.secrets]
581
+ OPENAI_API_KEY = "encrypted:LSi...openai-edge-encrypted...=="
582
+ SENDGRID_API_KEY = "encrypted:LSi...sendgrid-edge-encrypted...=="
583
+ STRIPE_SECRET_KEY = "encrypted:LSi...stripe-edge-encrypted...=="
584
+ ```
585
+
586
+ ### Caveat — lista pode evoluir com versões do CLI
587
+
588
+ A lista de designated secret fields pode evoluir com novas versões do Supabase CLI (novos providers OAuth, novos Auth Hooks, etc.). Para refresh periódico:
589
+
590
+ ```bash
591
+ # verificar versão do CLI
592
+ supabase --version
593
+
594
+ # consultar doc oficial:
595
+ # https://supabase.com/docs/guides/local-development/cli/config
596
+ ```
597
+
598
+ **Recomendação canônica:** review trimestral da lista vs doc oficial — Supabase publica updates regularmente.
599
+
600
+ ## Anti-patterns
601
+
602
+ ### Anti-pattern 1: Usar `encrypted:` em field não-designated
603
+
604
+ **Errado:**
605
+
606
+ ```toml
607
+ [auth.email.smtp]
608
+ host = "encrypted:LSi...wrong-host...==" # smtp.host NÃO é designated
609
+ port = 587
610
+ ```
611
+
612
+ **Por quê:** valor literal é usado como string — SMTP tenta conectar em host literal `"encrypted:LSi...=="`, DNS lookup falha silenciosamente, emails não são enviados, sem erro claro no log.
613
+
614
+ **Certo:** consultar Pattern 5 — usar `encrypted:` APENAS nos grupos canônicos. Para `auth.email.smtp.host` use plaintext (não é secret) ou `env(SMTP_HOST)`:
615
+
616
+ ```toml
617
+ [auth.email.smtp]
618
+ host = "smtp.sendgrid.net" # plaintext OK (não é secret)
619
+ port = 587
620
+ user = "apikey"
621
+ pass = "encrypted:LSi...correct-pass...==" # designated secret field
622
+ ```
623
+
624
+ ### Anti-pattern 2: Assumir secrets herdam entre branches
625
+
626
+ **Errado:** criar `staging` branch e assumir que `SENDGRID_API_KEY` do `main` está disponível.
627
+
628
+ ```bash
629
+ supabase --experimental branches create staging --persistent
630
+ # (assume erradamente que secrets do main foram copiados)
631
+
632
+ # Edge Function no staging — falha
633
+ const apiKey = Deno.env.get("SENDGRID_API_KEY"); // undefined
634
+ ```
635
+
636
+ **Por quê:** secrets são **per-branch** — staging tem env vars vazias até `supabase secrets set` rodar separadamente; Edge Functions retornam `undefined`; código quebra sem erro claro no DAG.
637
+
638
+ **Certo:** rodar `supabase secrets set --env-file` para **CADA branch** (main + staging + preview + production):
639
+
640
+ ```bash
641
+ # para cada branch
642
+ for branch in main staging production; do
643
+ supabase link --project-ref "${branch}-project-ref"
644
+ supabase secrets set --env-file "./supabase/.env.${branch}"
645
+ done
646
+ ```
647
+
648
+ Documentar workflow no onboarding do projeto.
649
+
650
+ ### Anti-pattern 3: Commitar `.env.keys` no git
651
+
652
+ **Errado:** `.env.keys` aparece em `git status` e dev faz `git add` distraído:
653
+
654
+ ```bash
655
+ git status
656
+ # Changes not staged for commit:
657
+ # modified: supabase/.env.preview
658
+ # modified: .env.keys ← BLOQUEANTE
659
+ git add .
660
+ git commit -m "feat: add preview secrets" # vazou a chave master
661
+ git push
662
+ ```
663
+
664
+ **Por quê:** `.env.keys` é a chave de **decryption master** — com ela, qualquer um decripta `.env.preview`/`.env.production` e tem acesso a TODOS os secrets encrypted; equivalente a vazar password master + todos os tokens OAuth + todas as API keys de uma vez.
665
+
666
+ **Certo:**
667
+
668
+ ```bash
669
+ # adicionar SEMPRE ao .gitignore — ANTES de qualquer set
670
+ echo ".env.keys" >> .gitignore
671
+ git add .gitignore
672
+ git commit -m "chore: gitignore dotenvx decryption key"
673
+ ```
674
+
675
+ Se foi committed por engano:
676
+
677
+ 1. `git filter-repo` (ou BFG) para limpar history
678
+ 2. **Rotacionar TODOS os secrets encrypted imediatamente** — sem confiar que ninguém viu antes
679
+ 3. Re-encrypt valores em `.env.preview`/`.env.production` com nova `.env.keys`
680
+ 4. Force-push branches afetados
681
+ 5. Notificar team + auditar acessos
682
+
683
+ ### Anti-pattern 4: Confundir `env()` vs `encrypted:` syntax
684
+
685
+ **Errado:** tentar combinar os dois prefixos:
686
+
687
+ ```toml
688
+ [auth.external.github]
689
+ secret = "encrypted:env(GITHUB_SECRET)" # syntax inválida — mistura prefixos
690
+ ```
691
+
692
+ **Por quê:** Supabase CLI parser não combina os dois — valor literal `"encrypted:env(GITHUB_SECRET)"` é usado como string, OAuth callback falha com `invalid client_secret`.
693
+
694
+ **Certo:** escolher UM:
695
+
696
+ ```toml
697
+ # Option A: env() resolve via env var
698
+ [auth.external.github]
699
+ secret = "env(GITHUB_SECRET)"
700
+
701
+ # Option B: encrypted: via dotenvx decryption
702
+ [auth.external.github]
703
+ secret = "encrypted:LSi...payload-encrypted...=="
704
+ ```
705
+
706
+ Nunca combinar.
707
+
708
+ ### Anti-pattern 5: Reusar `project_id` entre `[remotes]` blocks
709
+
710
+ **Errado:**
711
+
712
+ ```toml
713
+ [remotes.staging]
714
+ project_id = "main-project-ref" # ← mesmo ref do main
715
+
716
+ [remotes.production]
717
+ project_id = "main-project-ref" # ← mesmo ref do main
718
+ ```
719
+
720
+ **Por quê:** `[remotes.<name>]` deve apontar para branch **DEDICADO** criado via `supabase --experimental branches create`; usar mesmo `project_id` para múltiplos `[remotes]` causa configs sobrescritas no DAG step 4 (configure) — última definição vence, comportamento imprevisível.
721
+
722
+ **Certo:** criar branch por ambiente + obter `project_id` único:
723
+
724
+ ```bash
725
+ supabase --experimental branches create staging --persistent
726
+ supabase --experimental branches create production --persistent
727
+ supabase --experimental branches list
728
+ # BRANCH NAME BRANCH PROJECT ID
729
+ # main main-project-ref
730
+ # staging staging-dedicated-ref
731
+ # production production-dedicated-ref
732
+ ```
733
+
734
+ ```toml
735
+ [remotes.staging]
736
+ project_id = "staging-dedicated-ref"
737
+
738
+ [remotes.production]
739
+ project_id = "production-dedicated-ref"
740
+ ```
741
+
742
+ ### Anti-pattern 6: Esperar `env()` em config.toml resolver para secrets do projeto
743
+
744
+ **Errado:** setar secret via `supabase secrets set` e esperar que `config.toml` com `env()` resolva:
745
+
746
+ ```bash
747
+ # setar secret no projeto (runtime Edge Functions)
748
+ supabase secrets set SENDGRID_API_KEY=sk-real-key
749
+
750
+ # config.toml
751
+ [edge_runtime.secrets]
752
+ # expecta erradamente que o secret do projeto seja resolvido
753
+ SENDGRID_API_KEY = "env(SENDGRID_API_KEY)"
754
+ ```
755
+
756
+ **Por quê:** `env()` em config.toml resolve para env var **do CLI local** (build-time), **NÃO para secrets do projeto Supabase** (runtime das Edge Functions). Se o shell que roda o CLI não tem `SENDGRID_API_KEY` exportado, resolve para string vazia → config quebrada.
757
+
758
+ **Certo:**
759
+
760
+ - **Para secrets de Edge Functions runtime:** `supabase secrets set` + `Deno.env.get("SENDGRID_API_KEY")` no código Deno
761
+ - **Para config.toml build-time:** setar env var no shell antes de rodar CLI:
762
+
763
+ ```bash
764
+ export SENDGRID_API_KEY=sk-build-time-key
765
+ supabase db push
766
+ # config.toml com env(SENDGRID_API_KEY) resolve para "sk-build-time-key"
767
+ ```
768
+
769
+ Em workflow CI (GitHub Actions): expor secret no env do step:
770
+
771
+ ```yaml
772
+ - name: Push to Supabase
773
+ env:
774
+ SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
775
+ run: supabase db push
776
+ ```
777
+
778
+ ## Cross-suite integration (v1.27)
779
+
780
+ Esta skill é par-conjugado com `supabase-branching-workflow` (Phase 149) — branching workflow descreve **quando** branches são criados; config-toml-remotes descreve **como** configurar.
781
+
782
+ Cross-refs canônicas com outras skills v1.27 (Phases 150-153):
783
+
784
+ - **supabase-branching-workflow** (Phase 149) — Deploy DAG step 4 (configure) lê `[remotes.<branch>]` block desta skill
785
+ - **supabase-ci-cd-github-actions** (Phase 151, futura) — 8 workflows GitHub Actions que exportam env vars + rodam `supabase db push` com `--env-file` (cross-ref Pattern 3 + Pattern 4)
786
+ - **supabase-pgtap-testing** (Phase 152, futura) — testes pgTAP que rodam em remote branches via `--db-url` derivada de `[remotes.<branch>]`
787
+ - **supabase-migration-repair** (Phase 153, futura) — `migration repair` per `[remotes.<branch>]` quando drift detectado
788
+
789
+ Base para agent novo v1.27:
790
+
791
+ - **supabase-cicd-pipeline-implementer** (Phase 154, futura) — recebe spec via `Task()` e materializa `[remotes.<branch>]` blocks na config + GitHub Actions workflows com dotenvx integration
792
+
793
+ Pattern de handoff cooperativo herdado v1.23-v1.26: **architect** projeta strategy → **cicd-pipeline-implementer** materializa → **release-pipeline-auditor** (v1.10) audita hermeticidade. Nenhum agente descarta upstream — handoff cooperativo SQL (princípio canônico v1.23).
794
+
795
+ ## Ver também
796
+
797
+ - [supabase-branching-workflow](../supabase-branching-workflow/SKILL.md) (v1.27, Phase 149) — pré-requisito conceitual; Deploy DAG step 4 (configure) aplica `[remotes]`
798
+ - [supabase-ci-cd-github-actions](../supabase-ci-cd-github-actions/SKILL.md) (v1.27, Phase 151) — workflows GitHub Actions com `--env-file` + `supabase secrets set`
799
+ - [supabase-pgtap-testing](../supabase-pgtap-testing/SKILL.md) (v1.27, Phase 152) — testes que rodam em remote branches via `--db-url`
800
+ - [supabase-migration-repair](../supabase-migration-repair/SKILL.md) (v1.27, Phase 153) — `migration repair` per `[remotes.<branch>]`
801
+ - [supabase-migrations](../supabase-migrations/SKILL.md) (v1.23) — migrations aplicadas no branch via `supabase db push --linked`
802
+ - [supabase-edge-functions](../supabase-edge-functions/SKILL.md) — `Deno.env.get()` lê secrets setados via `supabase secrets set --env-file`
803
+ - [supabase-auth-ssr](../supabase-auth-ssr/SKILL.md) — `auth.external.*.secret` encrypted fields usados no auth flow
804
+ - [supabase-custom-claims-rbac](../supabase-custom-claims-rbac/SKILL.md) (v1.25) — `auth.hook.custom_access_token.secrets` é Auth Hook (Grupo 6)
805
+ - [supabase-postgres-roles](../supabase-postgres-roles/SKILL.md) (v1.26) — cross-ref para system access via secrets DB (`db.root_key`, `db.vault`)
806
+ - [glossário compartilhado](../_shared-supabase/glossary.md) — termos `[remotes]`, encrypted:, env(), dotenvx, .env.keys, .env.preview, designated secret fields, branch project_id
807
+ - Doc oficial: [Branching Configuration](https://supabase.com/docs/guides/deployment/branching#configuration), [Config Reference](https://supabase.com/docs/guides/local-development/cli/config), [dotenvx](https://dotenvx.com/), [Auth Hooks](https://supabase.com/docs/guides/auth/auth-hooks)