@luanpdd/kit-mcp 1.33.0 → 1.35.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 (379) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +168 -168
  3. package/gates/agent-no-recursive-dispatch.md +84 -84
  4. package/kit/COMANDOS.md +138 -138
  5. package/kit/COMPATIBILITY.md +70 -70
  6. package/kit/README.md +76 -76
  7. package/kit/agents/advisor-researcher.md +109 -109
  8. package/kit/agents/ai-mutation-tester.md +289 -289
  9. package/kit/agents/assumptions-analyzer.md +110 -110
  10. package/kit/agents/audit-log-implementer.md +314 -314
  11. package/kit/agents/auditor-consistencia-isolamento.md +414 -414
  12. package/kit/agents/b2b-saas-architect.md +157 -157
  13. package/kit/agents/burn-rate-forecaster.md +153 -153
  14. package/kit/agents/cascading-failures-auditor.md +299 -299
  15. package/kit/agents/codebase-mapper.md +769 -769
  16. package/kit/agents/crm-pipeline-implementer.md +257 -257
  17. package/kit/agents/debugger.md +814 -814
  18. package/kit/agents/designer-ui.md +216 -216
  19. package/kit/agents/detector-tenant-quente.md +338 -338
  20. package/kit/agents/evolution-go-integrator.md +201 -201
  21. package/kit/agents/example-reviewer.md +22 -22
  22. package/kit/agents/executor.md +565 -565
  23. package/kit/agents/golden-signals-instrumenter.md +232 -232
  24. package/kit/agents/incident-investigator.md +238 -238
  25. package/kit/agents/integration-checker.md +203 -203
  26. package/kit/agents/invite-flow-implementer.md +190 -190
  27. package/kit/agents/legacy-characterizer.md +369 -369
  28. package/kit/agents/lgpd-compliance-auditor.md +296 -296
  29. package/kit/agents/load-shedding-instrumenter.md +290 -290
  30. package/kit/agents/multi-tenant-isolation-auditor.md +254 -254
  31. package/kit/agents/multi-tenant-rls-writer.md +341 -341
  32. package/kit/agents/nyquist-auditor.md +181 -181
  33. package/kit/agents/observability-coverage-auditor.md +316 -316
  34. package/kit/agents/observability-instrumenter.md +191 -191
  35. package/kit/agents/omm-auditor.md +291 -291
  36. package/kit/agents/org-onboarding-implementer.md +224 -224
  37. package/kit/agents/payload-capture-instrumenter.md +274 -274
  38. package/kit/agents/phase-researcher.md +697 -697
  39. package/kit/agents/plan-checker.md +275 -275
  40. package/kit/agents/planner.md +923 -923
  41. package/kit/agents/postmortem-writer.md +273 -273
  42. package/kit/agents/project-researcher.md +653 -653
  43. package/kit/agents/prr-conductor.md +287 -287
  44. package/kit/agents/refactor-safety-auditor.md +405 -405
  45. package/kit/agents/release-pipeline-auditor.md +364 -364
  46. package/kit/agents/research-synthesizer.md +246 -246
  47. package/kit/agents/roadmapper.md +678 -678
  48. package/kit/agents/schema-checker.md +160 -160
  49. package/kit/agents/seam-finder.md +360 -360
  50. package/kit/agents/shotgun-surgery-detector.md +350 -350
  51. package/kit/agents/slo-engineer.md +217 -217
  52. package/kit/agents/storytelling-analyst.md +300 -300
  53. package/kit/agents/supabase-architect.md +249 -249
  54. package/kit/agents/supabase-auth-bootstrapper.md +400 -400
  55. package/kit/agents/supabase-auth-hook-writer.md +418 -418
  56. package/kit/agents/supabase-branching-architect.md +563 -563
  57. package/kit/agents/supabase-cicd-pipeline-implementer.md +778 -778
  58. package/kit/agents/supabase-column-privileges-writer.md +400 -400
  59. package/kit/agents/supabase-edge-fn-tester.md +288 -288
  60. package/kit/agents/supabase-edge-fn-writer.md +341 -341
  61. package/kit/agents/supabase-mfa-implementer.md +439 -439
  62. package/kit/agents/supabase-migration-writer.md +386 -386
  63. package/kit/agents/supabase-oauth-server-implementer.md +507 -507
  64. package/kit/agents/supabase-rbac-implementer.md +393 -393
  65. package/kit/agents/supabase-realtime-implementer.md +364 -364
  66. package/kit/agents/supabase-rls-hardener.md +522 -522
  67. package/kit/agents/supabase-rls-writer.md +324 -324
  68. package/kit/agents/supabase-roles-implementer.md +356 -356
  69. package/kit/agents/supabase-social-auth-implementer.md +451 -451
  70. package/kit/agents/supabase-sso-saml-architect.md +549 -549
  71. package/kit/agents/supabase-storage-implementer.md +407 -407
  72. package/kit/agents/super-admin-implementer.md +282 -282
  73. package/kit/agents/toil-auditor.md +268 -268
  74. package/kit/agents/ui-auditor.md +438 -438
  75. package/kit/agents/ui-checker.md +305 -305
  76. package/kit/agents/ui-researcher.md +356 -356
  77. package/kit/agents/user-profiler.md +176 -176
  78. package/kit/agents/validador-evolucao-schema.md +336 -336
  79. package/kit/agents/verifier.md +729 -729
  80. package/kit/agents/workflow-generator.md +167 -0
  81. package/kit/commands/adicionar-backlog.md +75 -75
  82. package/kit/commands/adicionar-fase.md +42 -42
  83. package/kit/commands/adicionar-tarefa.md +45 -45
  84. package/kit/commands/adicionar-testes.md +41 -41
  85. package/kit/commands/ajuda.md +21 -21
  86. package/kit/commands/atualizar.md +37 -37
  87. package/kit/commands/auditar-cascading.md +111 -111
  88. package/kit/commands/auditar-marco.md +179 -179
  89. package/kit/commands/auditar-observabilidade-cobertura-workflow.md +121 -0
  90. package/kit/commands/auditar-observabilidade-cobertura.md +183 -183
  91. package/kit/commands/auditar-refactor.md +219 -219
  92. package/kit/commands/auditar-release.md +109 -109
  93. package/kit/commands/auditar-uat.md +23 -23
  94. package/kit/commands/autonomo.md +40 -40
  95. package/kit/commands/branch-pr.md +24 -24
  96. package/kit/commands/burn-rate-status.md +408 -408
  97. package/kit/commands/capturar-payloads.md +193 -193
  98. package/kit/commands/caracterizar.md +212 -212
  99. package/kit/commands/concluir-marco.md +247 -247
  100. package/kit/commands/configuracoes.md +36 -36
  101. package/kit/commands/criar-workflow.md +158 -0
  102. package/kit/commands/dados-distribuidos.md +188 -188
  103. package/kit/commands/definir-perfil.md +10 -10
  104. package/kit/commands/depurar.md +190 -190
  105. package/kit/commands/detectar-duplicacao.md +197 -197
  106. package/kit/commands/discutir-fase.md +131 -131
  107. package/kit/commands/encontrar-seams.md +136 -136
  108. package/kit/commands/entrar-discord.md +17 -17
  109. package/kit/commands/estatisticas.md +18 -18
  110. package/kit/commands/example-greeting.md +33 -33
  111. package/kit/commands/executar-fase.md +58 -58
  112. package/kit/commands/expresso.md +56 -56
  113. package/kit/commands/fase-ui.md +34 -34
  114. package/kit/commands/fazer.md +57 -57
  115. package/kit/commands/fio.md +125 -125
  116. package/kit/commands/fluxos-trabalho.md +64 -64
  117. package/kit/commands/forense.md +176 -176
  118. package/kit/commands/gerenciador.md +38 -38
  119. package/kit/commands/inserir-fase.md +31 -31
  120. package/kit/commands/legacy.md +263 -263
  121. package/kit/commands/limpeza.md +17 -17
  122. package/kit/commands/listar-hipoteses-fase.md +45 -45
  123. package/kit/commands/listar-workspaces.md +18 -18
  124. package/kit/commands/load-shedding.md +117 -117
  125. package/kit/commands/mapear-codebase.md +70 -70
  126. package/kit/commands/multi-tenant.md +163 -163
  127. package/kit/commands/nota.md +33 -33
  128. package/kit/commands/novo-marco.md +43 -43
  129. package/kit/commands/novo-projeto.md +41 -41
  130. package/kit/commands/novo-workspace.md +43 -43
  131. package/kit/commands/pausar-trabalho.md +37 -37
  132. package/kit/commands/perfil-usuario.md +45 -45
  133. package/kit/commands/pesquisar-fase.md +195 -195
  134. package/kit/commands/planejar-fase.md +67 -67
  135. package/kit/commands/planejar-lacunas.md +33 -33
  136. package/kit/commands/plantar-ideia.md +25 -25
  137. package/kit/commands/progresso.md +24 -24
  138. package/kit/commands/proximo.md +30 -30
  139. package/kit/commands/publicar.md +490 -490
  140. package/kit/commands/rapido.md +35 -35
  141. package/kit/commands/reaplicar-patches.md +124 -124
  142. package/kit/commands/refactor-seguro.md +321 -321
  143. package/kit/commands/relatorio-sessao.md +19 -19
  144. package/kit/commands/remover-fase.md +31 -31
  145. package/kit/commands/remover-workspace.md +26 -26
  146. package/kit/commands/resumo-marco.md +50 -50
  147. package/kit/commands/retomar-trabalho.md +40 -40
  148. package/kit/commands/revisar-backlog.md +60 -60
  149. package/kit/commands/revisar-ui.md +32 -32
  150. package/kit/commands/revisar.md +37 -37
  151. package/kit/commands/saude.md +21 -21
  152. package/kit/commands/setup-notion.md +93 -93
  153. package/kit/commands/storytelling.md +179 -179
  154. package/kit/commands/supabase.md +238 -238
  155. package/kit/commands/sync-main.md +68 -68
  156. package/kit/commands/validar-fase.md +35 -35
  157. package/kit/commands/verificar-tarefas.md +44 -44
  158. package/kit/commands/verificar-trabalho.md +64 -64
  159. package/kit/file-manifest.json +424 -419
  160. package/kit/framework/bin/lib/commands.cjs +959 -959
  161. package/kit/framework/bin/lib/config.cjs +442 -442
  162. package/kit/framework/bin/lib/core.cjs +1230 -1230
  163. package/kit/framework/bin/lib/frontmatter.cjs +336 -336
  164. package/kit/framework/bin/lib/init.cjs +1442 -1442
  165. package/kit/framework/bin/lib/milestone.cjs +252 -252
  166. package/kit/framework/bin/lib/model-profiles.cjs +68 -68
  167. package/kit/framework/bin/lib/phase.cjs +888 -888
  168. package/kit/framework/bin/lib/profile-output.cjs +952 -952
  169. package/kit/framework/bin/lib/profile-pipeline.cjs +539 -539
  170. package/kit/framework/bin/lib/roadmap.cjs +329 -329
  171. package/kit/framework/bin/lib/security.cjs +382 -382
  172. package/kit/framework/bin/lib/state.cjs +1031 -1031
  173. package/kit/framework/bin/lib/template.cjs +222 -222
  174. package/kit/framework/bin/lib/uat.cjs +282 -282
  175. package/kit/framework/bin/lib/verify.cjs +888 -888
  176. package/kit/framework/bin/lib/workstream.cjs +491 -491
  177. package/kit/framework/bin/tools.cjs +918 -918
  178. package/kit/framework/commands/workstreams.md +63 -63
  179. package/kit/framework/references/checkpoints.md +778 -778
  180. package/kit/framework/references/continuation-format.md +249 -249
  181. package/kit/framework/references/decimal-phase-calculation.md +64 -64
  182. package/kit/framework/references/git-integration.md +295 -295
  183. package/kit/framework/references/git-planning-commit.md +38 -38
  184. package/kit/framework/references/model-profile-resolution.md +36 -36
  185. package/kit/framework/references/model-profiles.md +139 -139
  186. package/kit/framework/references/phase-argument-parsing.md +61 -61
  187. package/kit/framework/references/planning-config.md +202 -202
  188. package/kit/framework/references/questioning.md +162 -162
  189. package/kit/framework/references/tdd.md +263 -263
  190. package/kit/framework/references/ui-brand.md +160 -160
  191. package/kit/framework/references/user-profiling.md +657 -657
  192. package/kit/framework/references/verification-patterns.md +612 -612
  193. package/kit/framework/references/workstream-flag.md +58 -58
  194. package/kit/framework/templates/DEBUG.md +164 -164
  195. package/kit/framework/templates/UAT.md +265 -265
  196. package/kit/framework/templates/UI-SPEC.md +100 -100
  197. package/kit/framework/templates/VALIDATION.md +76 -76
  198. package/kit/framework/templates/claude-md.md +122 -122
  199. package/kit/framework/templates/codebase/architecture.md +185 -185
  200. package/kit/framework/templates/codebase/concerns.md +205 -205
  201. package/kit/framework/templates/codebase/conventions.md +204 -204
  202. package/kit/framework/templates/codebase/integrations.md +192 -192
  203. package/kit/framework/templates/codebase/stack.md +158 -158
  204. package/kit/framework/templates/codebase/structure.md +199 -199
  205. package/kit/framework/templates/codebase/testing.md +301 -301
  206. package/kit/framework/templates/config.json +44 -44
  207. package/kit/framework/templates/context.md +352 -352
  208. package/kit/framework/templates/continue-here.md +78 -78
  209. package/kit/framework/templates/copilot-instructions.md +7 -7
  210. package/kit/framework/templates/debug-subagent-prompt.md +91 -91
  211. package/kit/framework/templates/dev-preferences.md +20 -20
  212. package/kit/framework/templates/discovery.md +146 -146
  213. package/kit/framework/templates/discussion-log.md +63 -63
  214. package/kit/framework/templates/milestone-archive.md +123 -123
  215. package/kit/framework/templates/milestone.md +115 -115
  216. package/kit/framework/templates/phase-prompt.md +610 -610
  217. package/kit/framework/templates/planner-subagent-prompt.md +117 -117
  218. package/kit/framework/templates/project.md +186 -186
  219. package/kit/framework/templates/requirements.md +231 -231
  220. package/kit/framework/templates/research-project/ARCHITECTURE.md +204 -204
  221. package/kit/framework/templates/research-project/FEATURES.md +147 -147
  222. package/kit/framework/templates/research-project/PITFALLS.md +200 -200
  223. package/kit/framework/templates/research-project/STACK.md +120 -120
  224. package/kit/framework/templates/research-project/SUMMARY.md +170 -170
  225. package/kit/framework/templates/research.md +419 -419
  226. package/kit/framework/templates/retrospective.md +54 -54
  227. package/kit/framework/templates/roadmap.md +202 -202
  228. package/kit/framework/templates/state.md +176 -176
  229. package/kit/framework/templates/summary-complex.md +59 -59
  230. package/kit/framework/templates/summary-minimal.md +41 -41
  231. package/kit/framework/templates/summary-standard.md +48 -48
  232. package/kit/framework/templates/summary.md +209 -209
  233. package/kit/framework/templates/user-profile.md +146 -146
  234. package/kit/framework/templates/user-setup.md +256 -256
  235. package/kit/framework/templates/verification-report.md +258 -258
  236. package/kit/framework/workflows/add-phase.md +112 -112
  237. package/kit/framework/workflows/add-tests.md +351 -351
  238. package/kit/framework/workflows/add-todo.md +158 -158
  239. package/kit/framework/workflows/audit-milestone.md +340 -340
  240. package/kit/framework/workflows/audit-uat.md +109 -109
  241. package/kit/framework/workflows/autonomous.md +891 -891
  242. package/kit/framework/workflows/check-todos.md +177 -177
  243. package/kit/framework/workflows/cleanup.md +152 -152
  244. package/kit/framework/workflows/complete-milestone.md +696 -696
  245. package/kit/framework/workflows/diagnose-issues.md +231 -231
  246. package/kit/framework/workflows/discovery-phase.md +289 -289
  247. package/kit/framework/workflows/discuss-phase-assumptions.md +653 -653
  248. package/kit/framework/workflows/discuss-phase.md +784 -784
  249. package/kit/framework/workflows/do.md +104 -104
  250. package/kit/framework/workflows/execute-phase.md +838 -838
  251. package/kit/framework/workflows/execute-plan.md +510 -510
  252. package/kit/framework/workflows/fast.md +102 -102
  253. package/kit/framework/workflows/forensics.md +265 -265
  254. package/kit/framework/workflows/health.md +181 -181
  255. package/kit/framework/workflows/help.md +619 -619
  256. package/kit/framework/workflows/insert-phase.md +130 -130
  257. package/kit/framework/workflows/list-phase-assumptions.md +178 -178
  258. package/kit/framework/workflows/list-workspaces.md +56 -56
  259. package/kit/framework/workflows/manager.md +362 -362
  260. package/kit/framework/workflows/map-codebase.md +377 -377
  261. package/kit/framework/workflows/milestone-summary.md +223 -223
  262. package/kit/framework/workflows/new-milestone.md +486 -486
  263. package/kit/framework/workflows/new-project.md +1159 -1159
  264. package/kit/framework/workflows/new-workspace.md +237 -237
  265. package/kit/framework/workflows/next.md +97 -97
  266. package/kit/framework/workflows/node-repair.md +92 -92
  267. package/kit/framework/workflows/note.md +156 -156
  268. package/kit/framework/workflows/pause-work.md +176 -176
  269. package/kit/framework/workflows/plan-milestone-gaps.md +273 -273
  270. package/kit/framework/workflows/plan-phase.md +765 -765
  271. package/kit/framework/workflows/plant-seed.md +169 -169
  272. package/kit/framework/workflows/pr-branch.md +129 -129
  273. package/kit/framework/workflows/profile-user.md +450 -450
  274. package/kit/framework/workflows/progress.md +507 -507
  275. package/kit/framework/workflows/quick.md +757 -757
  276. package/kit/framework/workflows/remove-phase.md +155 -155
  277. package/kit/framework/workflows/remove-workspace.md +90 -90
  278. package/kit/framework/workflows/research-phase.md +82 -82
  279. package/kit/framework/workflows/resume-project.md +326 -326
  280. package/kit/framework/workflows/review.md +228 -228
  281. package/kit/framework/workflows/session-report.md +146 -146
  282. package/kit/framework/workflows/settings.md +283 -283
  283. package/kit/framework/workflows/ship.md +228 -228
  284. package/kit/framework/workflows/stats.md +60 -60
  285. package/kit/framework/workflows/transition.md +671 -671
  286. package/kit/framework/workflows/ui-phase.md +302 -302
  287. package/kit/framework/workflows/ui-review.md +165 -165
  288. package/kit/framework/workflows/update.md +323 -323
  289. package/kit/framework/workflows/validate-phase.md +174 -174
  290. package/kit/framework/workflows/verify-phase.md +252 -252
  291. package/kit/framework/workflows/verify-work.md +637 -637
  292. package/kit/hooks/check-update.js +118 -118
  293. package/kit/hooks/context-monitor.js +163 -163
  294. package/kit/hooks/kit-attribution-reminder.cjs +92 -92
  295. package/kit/hooks/kit-router.cjs +137 -137
  296. package/kit/hooks/prompt-guard.js +103 -103
  297. package/kit/hooks/statusline.js +125 -125
  298. package/kit/hooks/workflow-guard.js +101 -101
  299. package/kit/settings.json +45 -45
  300. package/kit/skills/ai-prompt-characterization/SKILL.md +335 -335
  301. package/kit/skills/armadilhas-sistemas-distribuidos/SKILL.md +447 -447
  302. package/kit/skills/audit-log-multi-tenant/SKILL.md +340 -340
  303. package/kit/skills/b2b-saas-architecture/SKILL.md +300 -300
  304. package/kit/skills/consistencia-leitura-replica/SKILL.md +385 -385
  305. package/kit/skills/crm-lead-pipeline-patterns/SKILL.md +343 -343
  306. package/kit/skills/dynamic-workflow-authoring/SKILL.md +223 -0
  307. package/kit/skills/escolha-modelo-consistencia/SKILL.md +494 -494
  308. package/kit/skills/evolucao-schema-compativel/SKILL.md +448 -448
  309. package/kit/skills/evolution-go-whatsapp-integration/SKILL.md +322 -322
  310. package/kit/skills/example-skill/SKILL.md +42 -42
  311. package/kit/skills/legacy-api-only-applications/SKILL.md +358 -358
  312. package/kit/skills/legacy-characterization-tests/SKILL.md +330 -330
  313. package/kit/skills/legacy-effect-analysis/SKILL.md +331 -331
  314. package/kit/skills/legacy-extract-class/SKILL.md +203 -203
  315. package/kit/skills/legacy-programming-by-difference/SKILL.md +252 -252
  316. package/kit/skills/legacy-seams-and-test-harness/SKILL.md +460 -460
  317. package/kit/skills/legacy-shotgun-surgery/SKILL.md +286 -286
  318. package/kit/skills/legacy-sprout-wrap-techniques/SKILL.md +434 -434
  319. package/kit/skills/legacy-storytelling-naked-crc/SKILL.md +270 -270
  320. package/kit/skills/lgpd-multi-tenant-compliance/SKILL.md +340 -340
  321. package/kit/skills/member-invite-flow/SKILL.md +305 -305
  322. package/kit/skills/member-management-react-shadcn/SKILL.md +328 -328
  323. package/kit/skills/multi-tenant-performance-scaling/SKILL.md +316 -316
  324. package/kit/skills/multi-tenant-rls-hierarchy/SKILL.md +342 -342
  325. package/kit/skills/org-onboarding-flow/SKILL.md +257 -257
  326. package/kit/skills/org-switcher-react-pattern/SKILL.md +349 -349
  327. package/kit/skills/permission-gate-react-pattern/SKILL.md +271 -271
  328. package/kit/skills/postgres-isolamento-concorrencia/SKILL.md +552 -552
  329. package/kit/skills/pre-refactor-characterization/SKILL.md +421 -421
  330. package/kit/skills/rbac-permissions-matrix-supabase/SKILL.md +338 -338
  331. package/kit/skills/streams-eventos-cdc/SKILL.md +711 -711
  332. package/kit/skills/supabase-auth-hardening/SKILL.md +674 -674
  333. package/kit/skills/supabase-auth-hooks/SKILL.md +875 -875
  334. package/kit/skills/supabase-auth-methods/SKILL.md +486 -486
  335. package/kit/skills/supabase-auth-sessions/SKILL.md +579 -579
  336. package/kit/skills/supabase-auth-ssr/SKILL.md +306 -306
  337. package/kit/skills/supabase-branching-workflow/SKILL.md +544 -544
  338. package/kit/skills/supabase-ci-cd-github-actions/SKILL.md +880 -880
  339. package/kit/skills/supabase-column-level-security/SKILL.md +426 -426
  340. package/kit/skills/supabase-config-toml-remotes/SKILL.md +807 -807
  341. package/kit/skills/supabase-custom-claims-rbac/SKILL.md +472 -472
  342. package/kit/skills/supabase-edge-functions/SKILL.md +330 -330
  343. package/kit/skills/supabase-edge-functions-auth/SKILL.md +309 -309
  344. package/kit/skills/supabase-edge-functions-limits/SKILL.md +302 -302
  345. package/kit/skills/supabase-edge-functions-mcp-server/SKILL.md +279 -279
  346. package/kit/skills/supabase-edge-functions-testing/SKILL.md +277 -277
  347. package/kit/skills/supabase-edge-runtime-builtins/SKILL.md +357 -357
  348. package/kit/skills/supabase-enterprise-sso-saml/SKILL.md +545 -545
  349. package/kit/skills/supabase-jwt-signing-keys/SKILL.md +399 -399
  350. package/kit/skills/supabase-mfa/SKILL.md +488 -488
  351. package/kit/skills/supabase-migration-repair/SKILL.md +823 -823
  352. package/kit/skills/supabase-migrations/SKILL.md +297 -297
  353. package/kit/skills/supabase-oauth-server/SKILL.md +537 -537
  354. package/kit/skills/supabase-pgtap-testing/SKILL.md +1053 -1053
  355. package/kit/skills/supabase-postgres-roles/SKILL.md +392 -392
  356. package/kit/skills/supabase-realtime/SKILL.md +460 -460
  357. package/kit/skills/supabase-rls-defense-in-depth/SKILL.md +418 -418
  358. package/kit/skills/supabase-rls-policies/SKILL.md +635 -635
  359. package/kit/skills/supabase-social-oauth/SKILL.md +480 -480
  360. package/kit/skills/supabase-third-party-auth/SKILL.md +450 -450
  361. package/kit/skills/super-admin-platform-pattern/SKILL.md +326 -326
  362. package/kit/skills/tenant-quente-mitigacao/SKILL.md +605 -605
  363. package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
  364. package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
  365. package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
  366. package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
  367. package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
  368. package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
  369. package/kit/skills/ui-tipografia/SKILL.md +211 -211
  370. package/kit/skills/whatsapp-conversation-state-machine/SKILL.md +287 -287
  371. package/kit/workflows/auditar-observabilidade-cobertura.workflow.js +250 -0
  372. package/package.json +65 -63
  373. package/src/core/kit.js +333 -216
  374. package/src/core/reflect.js +247 -247
  375. package/src/core/registry.js +123 -112
  376. package/src/core/reverse-sync.js +448 -372
  377. package/src/core/sync.js +477 -437
  378. package/src/core/watch.js +121 -121
  379. package/src/mcp-server/index.js +794 -794
@@ -1,472 +1,472 @@
1
- ---
2
- name: supabase-custom-claims-rbac
3
- description: Use ao implementar Custom Claims via Custom Access Token Auth Hook para RBAC em Supabase…
4
- ---
5
-
6
- # Supabase — Custom Claims & RBAC via Auth Hooks
7
-
8
- ## Quando usar
9
-
10
- LLM carrega esta skill quando implementar **Role-Based Access Control (RBAC)** via Custom Claims no JWT. Pattern canônico Supabase v1.25.
11
-
12
- Trigger phrases:
13
-
14
- - "custom claims Supabase", "RBAC Supabase"
15
- - "Custom Access Token Auth Hook", "auth hook RBAC"
16
- - "user_role no JWT", "authorize() function"
17
- - "role-based access control com auth hook"
18
- - "como evitar JOIN em RLS policy" (custom claims é a alternativa moderna)
19
-
20
- ## Princípio canônico
21
-
22
- RBAC em Supabase tem **3 mecanismos de delivery** dos claims:
23
-
24
- 1. **`app_metadata`** (skill `supabase-rls-policies` v1.23) — JSONB no JWT setado via service_role admin API. Simples mas limitado (não suporta enum types, sem normalização).
25
- 2. **Dedicated role table com helper function STABLE** (skill `rbac-permissions-matrix-supabase` v1.21) — `user_roles` + `private.has_role(role)` consultada em policies. Dinâmico mas faz JOIN custoso por query.
26
- 3. **Custom Claims via Custom Access Token Auth Hook** (v1.25 — **RECOMENDADO**) — `user_role` injetado no JWT durante geração do token via auth hook. Evita JOIN em policies (claim lido direto via `auth.jwt() ->> 'user_role'`). Eventually consistent (refresh TTL).
27
-
28
- **Quando usar custom claims (v1.25):**
29
-
30
- - ✅ RBAC com 2-10 roles fixos por user (admin, moderator, user, etc.)
31
- - ✅ Permission matrix relativamente estática (mudanças em horas/dias, não segundos)
32
- - ✅ Policies que precisam ser rápidas (sem JOIN custoso)
33
- - ✅ Cliente front-end precisa saber o role (UI conditional rendering)
34
-
35
- **Quando NÃO usar custom claims:**
36
-
37
- - ❌ Permission mudada em real-time (segundos) — JWT freshness não cobre
38
- - ❌ Permission depende de row context (ex: "can edit if owner of this row") — use RLS row-level com `auth.uid()`
39
- - ❌ Multi-tenant com user em N orgs com role diferente em cada — custom claim é per-user, não per-org-context
40
-
41
- Para multi-tenant complexo, combine: custom claim para role global (super_admin) + RLS hierárquica com `private.has_role(role, org_id)` para context-aware (skill `multi-tenant-rls-hierarchy`).
42
-
43
- ## Pattern canônico — 7 passos
44
-
45
- ### Passo 1: Enum types
46
-
47
- Defina enum types Postgres para roles e permissions — tipo-seguro, refactorable, documentado.
48
-
49
- ```sql
50
- -- enum de roles canônicos
51
- create type public.app_role as enum ('admin', 'moderator', 'user');
52
-
53
- -- enum de permissions canônicos (resource.action)
54
- create type public.app_permission as enum (
55
- 'channels.delete',
56
- 'channels.create',
57
- 'messages.delete',
58
- 'messages.update',
59
- 'users.ban'
60
- );
61
- ```
62
-
63
- **Caveat:** adicionar novo enum value exige migration `alter type public.app_permission add value 'novo.permission'` — não pode ser feito dentro de transação (Postgres limitation).
64
-
65
- ### Passo 2: Tabelas user_roles + role_permissions
66
-
67
- ```sql
68
- -- USER → ROLE mapping (N:1 user pode ter múltiplos roles)
69
- create table public.user_roles (
70
- id bigint generated by default as identity primary key,
71
- user_id uuid references auth.users on delete cascade not null,
72
- role app_role not null,
73
- unique (user_id, role)
74
- );
75
- comment on table public.user_roles is 'Application roles for each user.';
76
-
77
- -- ROLE → PERMISSION mapping (N:N role tem múltiplas permissions)
78
- create table public.role_permissions (
79
- id bigint generated by default as identity primary key,
80
- role app_role not null,
81
- permission app_permission not null,
82
- unique (role, permission)
83
- );
84
- comment on table public.role_permissions is 'Application permissions for each role.';
85
- ```
86
-
87
- Seed inicial:
88
-
89
- ```sql
90
- insert into public.role_permissions (role, permission)
91
- values
92
- ('admin', 'channels.delete'),
93
- ('admin', 'channels.create'),
94
- ('admin', 'messages.delete'),
95
- ('admin', 'messages.update'),
96
- ('admin', 'users.ban'),
97
- ('moderator', 'messages.delete'),
98
- ('moderator', 'messages.update');
99
- ```
100
-
101
- ### Passo 3: Custom Access Token Auth Hook function
102
-
103
- A função `custom_access_token_hook(event jsonb) returns jsonb` roda **antes** do JWT ser issued — recebe o event (com `user_id` + claims atuais) e devolve event modificado.
104
-
105
- ```sql
106
- create or replace function public.custom_access_token_hook(event jsonb)
107
- returns jsonb
108
- language plpgsql
109
- stable
110
- as $$
111
- declare
112
- claims jsonb;
113
- user_role public.app_role;
114
- begin
115
- -- buscar role do user em user_roles
116
- select role into user_role
117
- from public.user_roles
118
- where user_id = (event->>'user_id')::uuid;
119
-
120
- claims := event->'claims';
121
-
122
- if user_role is not null then
123
- claims := jsonb_set(claims, '{user_role}', to_jsonb(user_role));
124
- else
125
- claims := jsonb_set(claims, '{user_role}', 'null');
126
- end if;
127
-
128
- -- atualiza objeto claims no event original
129
- event := jsonb_set(event, '{claims}', claims);
130
-
131
- return event;
132
- end;
133
- $$;
134
- ```
135
-
136
- **Caveat para multi-role:** se user tem múltiplos roles em `user_roles`, esta versão pega o primeiro (`select role into user_role`). Para múltiplos roles no JWT, use:
137
-
138
- ```sql
139
- -- variante multi-role: claim user_roles como array
140
- select array_agg(role) into user_roles_array
141
- from public.user_roles
142
- where user_id = (event->>'user_id')::uuid;
143
- -- ...
144
- claims := jsonb_set(claims, '{user_roles}', to_jsonb(user_roles_array));
145
- ```
146
-
147
- ### Passo 4: Permissions canônicos para `supabase_auth_admin`
148
-
149
- `supabase_auth_admin` é o Postgres role usado pelo Supabase Auth service ao invocar o hook. Precisa de permissions específicos:
150
-
151
- ```sql
152
- -- 1. acesso ao schema public
153
- grant usage on schema public to supabase_auth_admin;
154
-
155
- -- 2. permissão de EXECUTE no hook function (apenas auth_admin pode invocar)
156
- grant execute
157
- on function public.custom_access_token_hook
158
- to supabase_auth_admin;
159
-
160
- -- 3. REVOKE EXECUTE de roles públicos (cliente NÃO pode chamar diretamente)
161
- revoke execute
162
- on function public.custom_access_token_hook
163
- from authenticated, anon, public;
164
-
165
- -- 4. acesso à tabela user_roles
166
- grant all
167
- on table public.user_roles
168
- to supabase_auth_admin;
169
-
170
- -- 5. REVOKE acesso público à user_roles (cliente NÃO pode mutar roles)
171
- revoke all
172
- on table public.user_roles
173
- from authenticated, anon, public;
174
-
175
- -- 6. RLS policy permitindo supabase_auth_admin ler user_roles
176
- create policy "Allow auth admin to read user roles" on public.user_roles
177
- as permissive for select
178
- to supabase_auth_admin
179
- using (true);
180
- ```
181
-
182
- **Por quê REVOKE EXECUTE do hook:** sem isso, qualquer cliente autenticado poderia chamar `custom_access_token_hook(...)` e potencialmente abusar.
183
-
184
- **Por quê REVOKE ALL FROM authenticated em user_roles:** roles são metadado privilegiado — apenas admins (service_role) podem inserir/atualizar. Cliente não deve ter SELECT direto na tabela (consultar via claim do JWT).
185
-
186
- ### Passo 5: Habilitar o hook
187
-
188
- **Dashboard (production):**
189
-
190
- 1. Acesse `Authentication > Hooks (Beta)` no Dashboard Supabase
191
- 2. Selecione "Custom Access Token" hook type
192
- 3. Dropdown: selecione `public.custom_access_token_hook` (função criada no Passo 3)
193
- 4. Save
194
-
195
- **Local development:**
196
-
197
- Em `supabase/config.toml`:
198
-
199
- ```toml
200
- [auth.hook.custom_access_token]
201
- enabled = true
202
- uri = "pg-functions://postgres/public/custom_access_token_hook"
203
- ```
204
-
205
- Reinicie o Supabase local (`supabase stop && supabase start`).
206
-
207
- ### Passo 6: `authorize()` function
208
-
209
- A função `authorize(permission app_permission) returns boolean` é o coração do RBAC — lê `user_role` do JWT e checa se o role tem a permission.
210
-
211
- ```sql
212
- create or replace function public.authorize(
213
- requested_permission app_permission
214
- )
215
- returns boolean
216
- language plpgsql
217
- stable
218
- security definer
219
- set search_path = ''
220
- as $$
221
- declare
222
- bind_permissions int;
223
- user_role public.app_role;
224
- begin
225
- -- ler user_role do JWT (delivered via auth hook do Passo 3)
226
- select (auth.jwt() ->> 'user_role')::public.app_role into user_role;
227
-
228
- -- contar permissions matching
229
- select count(*)
230
- into bind_permissions
231
- from public.role_permissions
232
- where role_permissions.permission = requested_permission
233
- and role_permissions.role = user_role;
234
-
235
- return bind_permissions > 0;
236
- end;
237
- $$;
238
- ```
239
-
240
- **Decisões canônicas:**
241
-
242
- - `stable` — função consulta DB mas não muta; resultado é estável dentro de uma transação (Postgres pode cachear)
243
- - `security definer` — roda com privilégios do owner (geralmente `postgres`) — necessário para acessar role_permissions sem RLS recursivo
244
- - `set search_path = ''` — anti schema injection (cross-ref skill `supabase-database-functions`)
245
-
246
- ### Passo 7: RLS policies usando authorize()
247
-
248
- Em vez de hard-code role em policy, use `authorize(permission)`:
249
-
250
- ```sql
251
- -- ANTES (anti-pattern): hard-code role direto na policy
252
- create policy "Allow admin delete channels" on public.channels for delete
253
- to authenticated
254
- using ((auth.jwt() ->> 'user_role') = 'admin');
255
-
256
- -- DEPOIS (canônico v1.25): authorize() abstrai role → permission
257
- create policy "Allow authorized delete access" on public.channels for delete
258
- to authenticated
259
- using ((SELECT authorize('channels.delete')));
260
-
261
- create policy "Allow authorized delete access" on public.messages for delete
262
- to authenticated
263
- using ((SELECT authorize('messages.delete')));
264
- ```
265
-
266
- **Vantagens canônicas:**
267
-
268
- - Adicionar nova permission = INSERT em role_permissions (sem alterar policy)
269
- - Mudar quem tem permission = UPDATE em role_permissions
270
- - Policies ficam estáveis; matriz permissions evolui
271
- - Reutilizável em N policies
272
-
273
- **Por que `(SELECT authorize(...))` com wrapper:** caching (cross-ref REGRA #2 da skill `supabase-rls-policies` v1.23) — função roda 1 vez por query, não 1 vez por linha.
274
-
275
- ## Client-side — acessar custom claims
276
-
277
- Auth hook só modifica o **access_token JWT**, não a auth response. Para acessar custom claims no cliente, decode o JWT:
278
-
279
- ```bash
280
- npm install jwt-decode
281
- ```
282
-
283
- ```js
284
- import { jwtDecode } from 'jwt-decode'
285
- import { createClient } from '@supabase/supabase-js'
286
-
287
- const supabase = createClient(URL, ANON_KEY)
288
-
289
- // listener para mudanças de auth state (login, logout, refresh)
290
- supabase.auth.onAuthStateChange(async (event, session) => {
291
- if (session) {
292
- const jwt = jwtDecode(session.access_token)
293
- const userRole = jwt.user_role // 'admin' | 'moderator' | 'user' | null
294
-
295
- // usar userRole para UI conditional rendering
296
- if (userRole === 'admin') {
297
- // show admin panel
298
- }
299
- }
300
- })
301
- ```
302
-
303
- **Para Next.js v16 + SSR:** decode o JWT no server-side via middleware ou Server Component:
304
-
305
- ```ts
306
- // app/middleware.ts ou Server Component
307
- import { jwtDecode } from 'jwt-decode'
308
-
309
- const { data: { session } } = await supabase.auth.getSession()
310
- if (session) {
311
- const jwt = jwtDecode(session.access_token)
312
- const userRole = jwt.user_role
313
- // ...
314
- }
315
- ```
316
-
317
- **Para backend (Node.js/Python/etc):** use bibliotecas equivalentes:
318
-
319
- - Node.js: `jsonwebtoken`, `express-jwt`, `koa-jwt`
320
- - Python: `PyJWT`
321
- - Dart: `dart_jsonwebtoken`
322
- - .NET: `Microsoft.AspNetCore.Authentication.JwtBearer`
323
-
324
- ## ⚠ Caveat — JWT Freshness
325
-
326
- Mudanças em `user_roles` **NÃO** refletem imediatamente no JWT do user — apenas após **token refresh** (default TTL 1h em Supabase).
327
-
328
- **Cenários:**
329
-
330
- | Situação | Comportamento |
331
- |----------|---------------|
332
- | Admin adiciona role moderator ao user X | User X continua com `user_role: null` até próximo refresh (até 1h) |
333
- | Admin remove role admin do user Y | User Y continua com `user_role: admin` no JWT atual; após refresh, policies bloqueiam |
334
- | Permission adicionada em role_permissions (admin → users.ban) | Reflete IMEDIATAMENTE — authorize() consulta DB cada query (stable mas re-executa em query nova) |
335
-
336
- **Implicações:**
337
-
338
- - Adicionar role: aceitável demora (user pode logout/login para forçar refresh)
339
- - **Remover role: PROBLEMA** — user comprometido pode usar JWT antigo até expirar. Para invalidação imediata:
340
-
341
- ```ts
342
- // force logout via admin API (server-side com service_role)
343
- await supabase.auth.admin.signOut(userId)
344
- // próximo request do user vai falhar; user precisa login novamente
345
- ```
346
-
347
- - Mudança em permissions matrix (role_permissions): IMEDIATA — não precisa refresh
348
-
349
- ## Anti-patterns
350
-
351
- ### Anti-pattern 1: Esquecer GRANT EXECUTE ao supabase_auth_admin
352
-
353
- **Errado:**
354
- ```sql
355
- create or replace function public.custom_access_token_hook(event jsonb) returns jsonb ...;
356
- -- esqueceu o GRANT EXECUTE TO supabase_auth_admin
357
- ```
358
-
359
- **Por quê:** auth hook falha silenciosamente — JWT é issued mas SEM o claim `user_role`. Difícil de debug.
360
-
361
- **Certo:** sempre incluir os 6 GRANTs/REVOKEs do Passo 4.
362
-
363
- ### Anti-pattern 2: Hardcode role em policy ao invés de authorize()
364
-
365
- **Errado:**
366
- ```sql
367
- create policy "admin_delete" on public.channels for delete to authenticated
368
- using ((auth.jwt() ->> 'user_role') = 'admin');
369
- ```
370
-
371
- **Por quê:** acoplamento policy ↔ role. Mudar quem pode deletar requer ALTER POLICY (DDL); com authorize(), basta UPDATE em role_permissions.
372
-
373
- **Certo:** `using ((SELECT authorize('channels.delete')))` — policy estável, matriz evolui.
374
-
375
- ### Anti-pattern 3: Assumir JWT fresh sem invalidação
376
-
377
- **Errado:**
378
- ```ts
379
- // admin remove role admin do user X
380
- await supabase.from('user_roles').delete().eq('user_id', xId).eq('role', 'admin')
381
- // CRÍTICO: user X ainda tem JWT antigo válido por até 1h
382
- ```
383
-
384
- **Por quê:** revogação de role não é imediata. Em casos de comprometimento, atacante usa o JWT antigo para abusar de privilégios admin.
385
-
386
- **Certo:** sempre force logout após mudança crítica de role:
387
- ```ts
388
- await supabase.from('user_roles').delete().eq('user_id', xId).eq('role', 'admin')
389
- await supabase.auth.admin.signOut(xId) // força refresh imediato
390
- ```
391
-
392
- ### Anti-pattern 4: Mutar app_metadata do cliente para mudar role
393
-
394
- **Errado:**
395
- ```ts
396
- // no cliente
397
- await supabase.auth.updateUser({ data: { role: 'admin' } })
398
- // user_metadata é editável pelo cliente — privilege escalation
399
- ```
400
-
401
- **Por quê:** mesmo anti-pattern de `user_metadata` da skill `supabase-rls-policies` (REGRA #1). Pior — confunde "role via custom claim" com "role via user_metadata".
402
-
403
- **Certo:** roles são mutados APENAS via INSERT em `public.user_roles` por backend (service_role) ou admin API. Cliente nunca toca em metadata de role.
404
-
405
- ### Anti-pattern 5: Auth hook que faz query custosa
406
-
407
- **Errado:**
408
- ```sql
409
- create or replace function public.custom_access_token_hook(event jsonb) returns jsonb ... as $$
410
- begin
411
- -- query custosa em cada token issuance
412
- select * into user_data from public.users
413
- join public.organizations o on u.org_id = o.id
414
- join public.subscriptions s on o.id = s.org_id
415
- where u.id = (event->>'user_id')::uuid;
416
- -- ...
417
- end;
418
- $$;
419
- ```
420
-
421
- **Por quê:** hook roda em **cada login + cada refresh**. Query lenta degrada latência de auth. Bom hook é < 10ms.
422
-
423
- **Certo:** mantenha hook simples — query single table (user_roles), aggregate se necessário, sem JOINs. Se precisa de info complexa, materialize em coluna de user_roles (denormalize).
424
-
425
- ## Postgres Roles vs Custom Claims — distinção canônica (v1.26)
426
-
427
- **Custom Claims** (v1.25) e **Postgres Roles** (v1.26) são conceitos **complementares**, não substitutos:
428
-
429
- | | Custom Claims (v1.25) | Postgres Roles (v1.26) |
430
- |---|---|---|
431
- | Tipo de access | Application access (end-users) | System access (service accounts) |
432
- | Identidade | JWT claim `user_role` | Postgres login |
433
- | Quem usa | End-users via PostgREST | Cron jobs, BI tools, ETL, admin scripts |
434
- | Granularidade | Per-permission via `authorize()` | Per schema/table/function/column |
435
- | Dinamicidade | Eventually consistent (TTL refresh) | Estática (alterações via SQL DDL) |
436
- | Exemplo | "User admin pode deletar messages" | "Cron job pode SELECT em todas tabelas para backup" |
437
-
438
- **Combine quando ambos aplicam:**
439
-
440
- - End-user com role `admin` (via custom claim) acessa endpoint que invoca função `private.org_analytics()` com SECURITY DEFINER (que tem GRANT EXECUTE apenas para Postgres role `analytics_reader`)
441
- - Service account `metabase_reader` (Postgres role) acessa view `public.user_active_tasks` com `security_invoker=true` (que respeita RLS via auth.jwt() — mas auth.jwt() é null para Postgres role login, então policies precisam considerar service_role bypass)
442
-
443
- **NÃO use Postgres roles para application access:**
444
-
445
- - ❌ Criar role Postgres `app_admin` para gerenciar quem é admin no app
446
- - ❌ Criar role Postgres por end-user
447
- - ✅ Use RLS + Custom Claims via auth hook (pattern v1.25)
448
-
449
- **NÃO use Custom Claims para system access:**
450
-
451
- - ❌ Service account cron job autenticando via JWT customizado
452
- - ❌ BI tool authenticando via auth hook
453
- - ✅ Use Postgres role dedicado (pattern v1.26)
454
-
455
- Padrão completo de Postgres roles em [`supabase-postgres-roles`](../supabase-postgres-roles/SKILL.md) (v1.26).
456
-
457
- ## Cross-suite integration (v1.25)
458
-
459
- Esta skill é base para o agent novo `supabase-rbac-implementer` (Phase 139) — recebe spec (roles + permissions matrix) via `Task()` e materializa setup completo. Pattern de handoff cooperativo herdado de v1.23/v1.24.
460
-
461
- Para multi-tenant com role por org, **combine** custom claim (role global) + helper function PG (`private.has_role(role, org_id)` em RLS hierárquica — skill `multi-tenant-rls-hierarchy` v1.21). Custom claim sozinho não cobre context-aware multi-tenant.
462
-
463
- ## Ver também
464
-
465
- - [supabase-rbac-implementer](../../agents/supabase-rbac-implementer.md) (v1.25) — canonical materializer
466
- - [supabase-rls-policies](../supabase-rls-policies/SKILL.md) (v1.23) — section "RBAC via Custom Claims + authorize() function (v1.25)"
467
- - [supabase-rls-defense-in-depth](../supabase-rls-defense-in-depth/SKILL.md) (v1.24) — Camada 9 (Auth Hooks - Custom Claims) v1.25
468
- - [supabase-database-functions](../supabase-database-functions/SKILL.md) — pattern SECURITY DEFINER + supabase_auth_admin grants
469
- - [supabase-auth-ssr](../supabase-auth-ssr/SKILL.md) — Next.js v16 + onAuthStateChange + jwt-decode integration
470
- - [supabase-rls-hardener](../../agents/supabase-rls-hardener.md) (v1.23) — Detector 9 valida auth hook instalado (v1.25)
471
- - [rbac-permissions-matrix-supabase](../rbac-permissions-matrix-supabase/SKILL.md) (v1.21) — alternativa via helper function STABLE (vs custom claim v1.25)
472
- - [glossário compartilhado](../_shared-supabase/glossary.md) — termos custom claims, Custom Access Token Auth Hook, JWT user_role claim, authorize() function, supabase_auth_admin role, app_role enum, app_permission enum, jwt-decode client pattern
1
+ ---
2
+ name: supabase-custom-claims-rbac
3
+ description: Use ao implementar Custom Claims via Custom Access Token Auth Hook para RBAC em Supabase…
4
+ ---
5
+
6
+ # Supabase — Custom Claims & RBAC via Auth Hooks
7
+
8
+ ## Quando usar
9
+
10
+ LLM carrega esta skill quando implementar **Role-Based Access Control (RBAC)** via Custom Claims no JWT. Pattern canônico Supabase v1.25.
11
+
12
+ Trigger phrases:
13
+
14
+ - "custom claims Supabase", "RBAC Supabase"
15
+ - "Custom Access Token Auth Hook", "auth hook RBAC"
16
+ - "user_role no JWT", "authorize() function"
17
+ - "role-based access control com auth hook"
18
+ - "como evitar JOIN em RLS policy" (custom claims é a alternativa moderna)
19
+
20
+ ## Princípio canônico
21
+
22
+ RBAC em Supabase tem **3 mecanismos de delivery** dos claims:
23
+
24
+ 1. **`app_metadata`** (skill `supabase-rls-policies` v1.23) — JSONB no JWT setado via service_role admin API. Simples mas limitado (não suporta enum types, sem normalização).
25
+ 2. **Dedicated role table com helper function STABLE** (skill `rbac-permissions-matrix-supabase` v1.21) — `user_roles` + `private.has_role(role)` consultada em policies. Dinâmico mas faz JOIN custoso por query.
26
+ 3. **Custom Claims via Custom Access Token Auth Hook** (v1.25 — **RECOMENDADO**) — `user_role` injetado no JWT durante geração do token via auth hook. Evita JOIN em policies (claim lido direto via `auth.jwt() ->> 'user_role'`). Eventually consistent (refresh TTL).
27
+
28
+ **Quando usar custom claims (v1.25):**
29
+
30
+ - ✅ RBAC com 2-10 roles fixos por user (admin, moderator, user, etc.)
31
+ - ✅ Permission matrix relativamente estática (mudanças em horas/dias, não segundos)
32
+ - ✅ Policies que precisam ser rápidas (sem JOIN custoso)
33
+ - ✅ Cliente front-end precisa saber o role (UI conditional rendering)
34
+
35
+ **Quando NÃO usar custom claims:**
36
+
37
+ - ❌ Permission mudada em real-time (segundos) — JWT freshness não cobre
38
+ - ❌ Permission depende de row context (ex: "can edit if owner of this row") — use RLS row-level com `auth.uid()`
39
+ - ❌ Multi-tenant com user em N orgs com role diferente em cada — custom claim é per-user, não per-org-context
40
+
41
+ Para multi-tenant complexo, combine: custom claim para role global (super_admin) + RLS hierárquica com `private.has_role(role, org_id)` para context-aware (skill `multi-tenant-rls-hierarchy`).
42
+
43
+ ## Pattern canônico — 7 passos
44
+
45
+ ### Passo 1: Enum types
46
+
47
+ Defina enum types Postgres para roles e permissions — tipo-seguro, refactorable, documentado.
48
+
49
+ ```sql
50
+ -- enum de roles canônicos
51
+ create type public.app_role as enum ('admin', 'moderator', 'user');
52
+
53
+ -- enum de permissions canônicos (resource.action)
54
+ create type public.app_permission as enum (
55
+ 'channels.delete',
56
+ 'channels.create',
57
+ 'messages.delete',
58
+ 'messages.update',
59
+ 'users.ban'
60
+ );
61
+ ```
62
+
63
+ **Caveat:** adicionar novo enum value exige migration `alter type public.app_permission add value 'novo.permission'` — não pode ser feito dentro de transação (Postgres limitation).
64
+
65
+ ### Passo 2: Tabelas user_roles + role_permissions
66
+
67
+ ```sql
68
+ -- USER → ROLE mapping (N:1 user pode ter múltiplos roles)
69
+ create table public.user_roles (
70
+ id bigint generated by default as identity primary key,
71
+ user_id uuid references auth.users on delete cascade not null,
72
+ role app_role not null,
73
+ unique (user_id, role)
74
+ );
75
+ comment on table public.user_roles is 'Application roles for each user.';
76
+
77
+ -- ROLE → PERMISSION mapping (N:N role tem múltiplas permissions)
78
+ create table public.role_permissions (
79
+ id bigint generated by default as identity primary key,
80
+ role app_role not null,
81
+ permission app_permission not null,
82
+ unique (role, permission)
83
+ );
84
+ comment on table public.role_permissions is 'Application permissions for each role.';
85
+ ```
86
+
87
+ Seed inicial:
88
+
89
+ ```sql
90
+ insert into public.role_permissions (role, permission)
91
+ values
92
+ ('admin', 'channels.delete'),
93
+ ('admin', 'channels.create'),
94
+ ('admin', 'messages.delete'),
95
+ ('admin', 'messages.update'),
96
+ ('admin', 'users.ban'),
97
+ ('moderator', 'messages.delete'),
98
+ ('moderator', 'messages.update');
99
+ ```
100
+
101
+ ### Passo 3: Custom Access Token Auth Hook function
102
+
103
+ A função `custom_access_token_hook(event jsonb) returns jsonb` roda **antes** do JWT ser issued — recebe o event (com `user_id` + claims atuais) e devolve event modificado.
104
+
105
+ ```sql
106
+ create or replace function public.custom_access_token_hook(event jsonb)
107
+ returns jsonb
108
+ language plpgsql
109
+ stable
110
+ as $$
111
+ declare
112
+ claims jsonb;
113
+ user_role public.app_role;
114
+ begin
115
+ -- buscar role do user em user_roles
116
+ select role into user_role
117
+ from public.user_roles
118
+ where user_id = (event->>'user_id')::uuid;
119
+
120
+ claims := event->'claims';
121
+
122
+ if user_role is not null then
123
+ claims := jsonb_set(claims, '{user_role}', to_jsonb(user_role));
124
+ else
125
+ claims := jsonb_set(claims, '{user_role}', 'null');
126
+ end if;
127
+
128
+ -- atualiza objeto claims no event original
129
+ event := jsonb_set(event, '{claims}', claims);
130
+
131
+ return event;
132
+ end;
133
+ $$;
134
+ ```
135
+
136
+ **Caveat para multi-role:** se user tem múltiplos roles em `user_roles`, esta versão pega o primeiro (`select role into user_role`). Para múltiplos roles no JWT, use:
137
+
138
+ ```sql
139
+ -- variante multi-role: claim user_roles como array
140
+ select array_agg(role) into user_roles_array
141
+ from public.user_roles
142
+ where user_id = (event->>'user_id')::uuid;
143
+ -- ...
144
+ claims := jsonb_set(claims, '{user_roles}', to_jsonb(user_roles_array));
145
+ ```
146
+
147
+ ### Passo 4: Permissions canônicos para `supabase_auth_admin`
148
+
149
+ `supabase_auth_admin` é o Postgres role usado pelo Supabase Auth service ao invocar o hook. Precisa de permissions específicos:
150
+
151
+ ```sql
152
+ -- 1. acesso ao schema public
153
+ grant usage on schema public to supabase_auth_admin;
154
+
155
+ -- 2. permissão de EXECUTE no hook function (apenas auth_admin pode invocar)
156
+ grant execute
157
+ on function public.custom_access_token_hook
158
+ to supabase_auth_admin;
159
+
160
+ -- 3. REVOKE EXECUTE de roles públicos (cliente NÃO pode chamar diretamente)
161
+ revoke execute
162
+ on function public.custom_access_token_hook
163
+ from authenticated, anon, public;
164
+
165
+ -- 4. acesso à tabela user_roles
166
+ grant all
167
+ on table public.user_roles
168
+ to supabase_auth_admin;
169
+
170
+ -- 5. REVOKE acesso público à user_roles (cliente NÃO pode mutar roles)
171
+ revoke all
172
+ on table public.user_roles
173
+ from authenticated, anon, public;
174
+
175
+ -- 6. RLS policy permitindo supabase_auth_admin ler user_roles
176
+ create policy "Allow auth admin to read user roles" on public.user_roles
177
+ as permissive for select
178
+ to supabase_auth_admin
179
+ using (true);
180
+ ```
181
+
182
+ **Por quê REVOKE EXECUTE do hook:** sem isso, qualquer cliente autenticado poderia chamar `custom_access_token_hook(...)` e potencialmente abusar.
183
+
184
+ **Por quê REVOKE ALL FROM authenticated em user_roles:** roles são metadado privilegiado — apenas admins (service_role) podem inserir/atualizar. Cliente não deve ter SELECT direto na tabela (consultar via claim do JWT).
185
+
186
+ ### Passo 5: Habilitar o hook
187
+
188
+ **Dashboard (production):**
189
+
190
+ 1. Acesse `Authentication > Hooks (Beta)` no Dashboard Supabase
191
+ 2. Selecione "Custom Access Token" hook type
192
+ 3. Dropdown: selecione `public.custom_access_token_hook` (função criada no Passo 3)
193
+ 4. Save
194
+
195
+ **Local development:**
196
+
197
+ Em `supabase/config.toml`:
198
+
199
+ ```toml
200
+ [auth.hook.custom_access_token]
201
+ enabled = true
202
+ uri = "pg-functions://postgres/public/custom_access_token_hook"
203
+ ```
204
+
205
+ Reinicie o Supabase local (`supabase stop && supabase start`).
206
+
207
+ ### Passo 6: `authorize()` function
208
+
209
+ A função `authorize(permission app_permission) returns boolean` é o coração do RBAC — lê `user_role` do JWT e checa se o role tem a permission.
210
+
211
+ ```sql
212
+ create or replace function public.authorize(
213
+ requested_permission app_permission
214
+ )
215
+ returns boolean
216
+ language plpgsql
217
+ stable
218
+ security definer
219
+ set search_path = ''
220
+ as $$
221
+ declare
222
+ bind_permissions int;
223
+ user_role public.app_role;
224
+ begin
225
+ -- ler user_role do JWT (delivered via auth hook do Passo 3)
226
+ select (auth.jwt() ->> 'user_role')::public.app_role into user_role;
227
+
228
+ -- contar permissions matching
229
+ select count(*)
230
+ into bind_permissions
231
+ from public.role_permissions
232
+ where role_permissions.permission = requested_permission
233
+ and role_permissions.role = user_role;
234
+
235
+ return bind_permissions > 0;
236
+ end;
237
+ $$;
238
+ ```
239
+
240
+ **Decisões canônicas:**
241
+
242
+ - `stable` — função consulta DB mas não muta; resultado é estável dentro de uma transação (Postgres pode cachear)
243
+ - `security definer` — roda com privilégios do owner (geralmente `postgres`) — necessário para acessar role_permissions sem RLS recursivo
244
+ - `set search_path = ''` — anti schema injection (cross-ref skill `supabase-database-functions`)
245
+
246
+ ### Passo 7: RLS policies usando authorize()
247
+
248
+ Em vez de hard-code role em policy, use `authorize(permission)`:
249
+
250
+ ```sql
251
+ -- ANTES (anti-pattern): hard-code role direto na policy
252
+ create policy "Allow admin delete channels" on public.channels for delete
253
+ to authenticated
254
+ using ((auth.jwt() ->> 'user_role') = 'admin');
255
+
256
+ -- DEPOIS (canônico v1.25): authorize() abstrai role → permission
257
+ create policy "Allow authorized delete access" on public.channels for delete
258
+ to authenticated
259
+ using ((SELECT authorize('channels.delete')));
260
+
261
+ create policy "Allow authorized delete access" on public.messages for delete
262
+ to authenticated
263
+ using ((SELECT authorize('messages.delete')));
264
+ ```
265
+
266
+ **Vantagens canônicas:**
267
+
268
+ - Adicionar nova permission = INSERT em role_permissions (sem alterar policy)
269
+ - Mudar quem tem permission = UPDATE em role_permissions
270
+ - Policies ficam estáveis; matriz permissions evolui
271
+ - Reutilizável em N policies
272
+
273
+ **Por que `(SELECT authorize(...))` com wrapper:** caching (cross-ref REGRA #2 da skill `supabase-rls-policies` v1.23) — função roda 1 vez por query, não 1 vez por linha.
274
+
275
+ ## Client-side — acessar custom claims
276
+
277
+ Auth hook só modifica o **access_token JWT**, não a auth response. Para acessar custom claims no cliente, decode o JWT:
278
+
279
+ ```bash
280
+ npm install jwt-decode
281
+ ```
282
+
283
+ ```js
284
+ import { jwtDecode } from 'jwt-decode'
285
+ import { createClient } from '@supabase/supabase-js'
286
+
287
+ const supabase = createClient(URL, ANON_KEY)
288
+
289
+ // listener para mudanças de auth state (login, logout, refresh)
290
+ supabase.auth.onAuthStateChange(async (event, session) => {
291
+ if (session) {
292
+ const jwt = jwtDecode(session.access_token)
293
+ const userRole = jwt.user_role // 'admin' | 'moderator' | 'user' | null
294
+
295
+ // usar userRole para UI conditional rendering
296
+ if (userRole === 'admin') {
297
+ // show admin panel
298
+ }
299
+ }
300
+ })
301
+ ```
302
+
303
+ **Para Next.js v16 + SSR:** decode o JWT no server-side via middleware ou Server Component:
304
+
305
+ ```ts
306
+ // app/middleware.ts ou Server Component
307
+ import { jwtDecode } from 'jwt-decode'
308
+
309
+ const { data: { session } } = await supabase.auth.getSession()
310
+ if (session) {
311
+ const jwt = jwtDecode(session.access_token)
312
+ const userRole = jwt.user_role
313
+ // ...
314
+ }
315
+ ```
316
+
317
+ **Para backend (Node.js/Python/etc):** use bibliotecas equivalentes:
318
+
319
+ - Node.js: `jsonwebtoken`, `express-jwt`, `koa-jwt`
320
+ - Python: `PyJWT`
321
+ - Dart: `dart_jsonwebtoken`
322
+ - .NET: `Microsoft.AspNetCore.Authentication.JwtBearer`
323
+
324
+ ## ⚠ Caveat — JWT Freshness
325
+
326
+ Mudanças em `user_roles` **NÃO** refletem imediatamente no JWT do user — apenas após **token refresh** (default TTL 1h em Supabase).
327
+
328
+ **Cenários:**
329
+
330
+ | Situação | Comportamento |
331
+ |----------|---------------|
332
+ | Admin adiciona role moderator ao user X | User X continua com `user_role: null` até próximo refresh (até 1h) |
333
+ | Admin remove role admin do user Y | User Y continua com `user_role: admin` no JWT atual; após refresh, policies bloqueiam |
334
+ | Permission adicionada em role_permissions (admin → users.ban) | Reflete IMEDIATAMENTE — authorize() consulta DB cada query (stable mas re-executa em query nova) |
335
+
336
+ **Implicações:**
337
+
338
+ - Adicionar role: aceitável demora (user pode logout/login para forçar refresh)
339
+ - **Remover role: PROBLEMA** — user comprometido pode usar JWT antigo até expirar. Para invalidação imediata:
340
+
341
+ ```ts
342
+ // force logout via admin API (server-side com service_role)
343
+ await supabase.auth.admin.signOut(userId)
344
+ // próximo request do user vai falhar; user precisa login novamente
345
+ ```
346
+
347
+ - Mudança em permissions matrix (role_permissions): IMEDIATA — não precisa refresh
348
+
349
+ ## Anti-patterns
350
+
351
+ ### Anti-pattern 1: Esquecer GRANT EXECUTE ao supabase_auth_admin
352
+
353
+ **Errado:**
354
+ ```sql
355
+ create or replace function public.custom_access_token_hook(event jsonb) returns jsonb ...;
356
+ -- esqueceu o GRANT EXECUTE TO supabase_auth_admin
357
+ ```
358
+
359
+ **Por quê:** auth hook falha silenciosamente — JWT é issued mas SEM o claim `user_role`. Difícil de debug.
360
+
361
+ **Certo:** sempre incluir os 6 GRANTs/REVOKEs do Passo 4.
362
+
363
+ ### Anti-pattern 2: Hardcode role em policy ao invés de authorize()
364
+
365
+ **Errado:**
366
+ ```sql
367
+ create policy "admin_delete" on public.channels for delete to authenticated
368
+ using ((auth.jwt() ->> 'user_role') = 'admin');
369
+ ```
370
+
371
+ **Por quê:** acoplamento policy ↔ role. Mudar quem pode deletar requer ALTER POLICY (DDL); com authorize(), basta UPDATE em role_permissions.
372
+
373
+ **Certo:** `using ((SELECT authorize('channels.delete')))` — policy estável, matriz evolui.
374
+
375
+ ### Anti-pattern 3: Assumir JWT fresh sem invalidação
376
+
377
+ **Errado:**
378
+ ```ts
379
+ // admin remove role admin do user X
380
+ await supabase.from('user_roles').delete().eq('user_id', xId).eq('role', 'admin')
381
+ // CRÍTICO: user X ainda tem JWT antigo válido por até 1h
382
+ ```
383
+
384
+ **Por quê:** revogação de role não é imediata. Em casos de comprometimento, atacante usa o JWT antigo para abusar de privilégios admin.
385
+
386
+ **Certo:** sempre force logout após mudança crítica de role:
387
+ ```ts
388
+ await supabase.from('user_roles').delete().eq('user_id', xId).eq('role', 'admin')
389
+ await supabase.auth.admin.signOut(xId) // força refresh imediato
390
+ ```
391
+
392
+ ### Anti-pattern 4: Mutar app_metadata do cliente para mudar role
393
+
394
+ **Errado:**
395
+ ```ts
396
+ // no cliente
397
+ await supabase.auth.updateUser({ data: { role: 'admin' } })
398
+ // user_metadata é editável pelo cliente — privilege escalation
399
+ ```
400
+
401
+ **Por quê:** mesmo anti-pattern de `user_metadata` da skill `supabase-rls-policies` (REGRA #1). Pior — confunde "role via custom claim" com "role via user_metadata".
402
+
403
+ **Certo:** roles são mutados APENAS via INSERT em `public.user_roles` por backend (service_role) ou admin API. Cliente nunca toca em metadata de role.
404
+
405
+ ### Anti-pattern 5: Auth hook que faz query custosa
406
+
407
+ **Errado:**
408
+ ```sql
409
+ create or replace function public.custom_access_token_hook(event jsonb) returns jsonb ... as $$
410
+ begin
411
+ -- query custosa em cada token issuance
412
+ select * into user_data from public.users
413
+ join public.organizations o on u.org_id = o.id
414
+ join public.subscriptions s on o.id = s.org_id
415
+ where u.id = (event->>'user_id')::uuid;
416
+ -- ...
417
+ end;
418
+ $$;
419
+ ```
420
+
421
+ **Por quê:** hook roda em **cada login + cada refresh**. Query lenta degrada latência de auth. Bom hook é < 10ms.
422
+
423
+ **Certo:** mantenha hook simples — query single table (user_roles), aggregate se necessário, sem JOINs. Se precisa de info complexa, materialize em coluna de user_roles (denormalize).
424
+
425
+ ## Postgres Roles vs Custom Claims — distinção canônica (v1.26)
426
+
427
+ **Custom Claims** (v1.25) e **Postgres Roles** (v1.26) são conceitos **complementares**, não substitutos:
428
+
429
+ | | Custom Claims (v1.25) | Postgres Roles (v1.26) |
430
+ |---|---|---|
431
+ | Tipo de access | Application access (end-users) | System access (service accounts) |
432
+ | Identidade | JWT claim `user_role` | Postgres login |
433
+ | Quem usa | End-users via PostgREST | Cron jobs, BI tools, ETL, admin scripts |
434
+ | Granularidade | Per-permission via `authorize()` | Per schema/table/function/column |
435
+ | Dinamicidade | Eventually consistent (TTL refresh) | Estática (alterações via SQL DDL) |
436
+ | Exemplo | "User admin pode deletar messages" | "Cron job pode SELECT em todas tabelas para backup" |
437
+
438
+ **Combine quando ambos aplicam:**
439
+
440
+ - End-user com role `admin` (via custom claim) acessa endpoint que invoca função `private.org_analytics()` com SECURITY DEFINER (que tem GRANT EXECUTE apenas para Postgres role `analytics_reader`)
441
+ - Service account `metabase_reader` (Postgres role) acessa view `public.user_active_tasks` com `security_invoker=true` (que respeita RLS via auth.jwt() — mas auth.jwt() é null para Postgres role login, então policies precisam considerar service_role bypass)
442
+
443
+ **NÃO use Postgres roles para application access:**
444
+
445
+ - ❌ Criar role Postgres `app_admin` para gerenciar quem é admin no app
446
+ - ❌ Criar role Postgres por end-user
447
+ - ✅ Use RLS + Custom Claims via auth hook (pattern v1.25)
448
+
449
+ **NÃO use Custom Claims para system access:**
450
+
451
+ - ❌ Service account cron job autenticando via JWT customizado
452
+ - ❌ BI tool authenticando via auth hook
453
+ - ✅ Use Postgres role dedicado (pattern v1.26)
454
+
455
+ Padrão completo de Postgres roles em [`supabase-postgres-roles`](../supabase-postgres-roles/SKILL.md) (v1.26).
456
+
457
+ ## Cross-suite integration (v1.25)
458
+
459
+ Esta skill é base para o agent novo `supabase-rbac-implementer` (Phase 139) — recebe spec (roles + permissions matrix) via `Task()` e materializa setup completo. Pattern de handoff cooperativo herdado de v1.23/v1.24.
460
+
461
+ Para multi-tenant com role por org, **combine** custom claim (role global) + helper function PG (`private.has_role(role, org_id)` em RLS hierárquica — skill `multi-tenant-rls-hierarchy` v1.21). Custom claim sozinho não cobre context-aware multi-tenant.
462
+
463
+ ## Ver também
464
+
465
+ - [supabase-rbac-implementer](../../agents/supabase-rbac-implementer.md) (v1.25) — canonical materializer
466
+ - [supabase-rls-policies](../supabase-rls-policies/SKILL.md) (v1.23) — section "RBAC via Custom Claims + authorize() function (v1.25)"
467
+ - [supabase-rls-defense-in-depth](../supabase-rls-defense-in-depth/SKILL.md) (v1.24) — Camada 9 (Auth Hooks - Custom Claims) v1.25
468
+ - [supabase-database-functions](../supabase-database-functions/SKILL.md) — pattern SECURITY DEFINER + supabase_auth_admin grants
469
+ - [supabase-auth-ssr](../supabase-auth-ssr/SKILL.md) — Next.js v16 + onAuthStateChange + jwt-decode integration
470
+ - [supabase-rls-hardener](../../agents/supabase-rls-hardener.md) (v1.23) — Detector 9 valida auth hook instalado (v1.25)
471
+ - [rbac-permissions-matrix-supabase](../rbac-permissions-matrix-supabase/SKILL.md) (v1.21) — alternativa via helper function STABLE (vs custom claim v1.25)
472
+ - [glossário compartilhado](../_shared-supabase/glossary.md) — termos custom claims, Custom Access Token Auth Hook, JWT user_role claim, authorize() function, supabase_auth_admin role, app_role enum, app_permission enum, jwt-decode client pattern