@luanpdd/kit-mcp 1.33.0 → 1.34.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 (376) 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/commands/adicionar-backlog.md +75 -75
  81. package/kit/commands/adicionar-fase.md +42 -42
  82. package/kit/commands/adicionar-tarefa.md +45 -45
  83. package/kit/commands/adicionar-testes.md +41 -41
  84. package/kit/commands/ajuda.md +21 -21
  85. package/kit/commands/atualizar.md +37 -37
  86. package/kit/commands/auditar-cascading.md +111 -111
  87. package/kit/commands/auditar-marco.md +179 -179
  88. package/kit/commands/auditar-observabilidade-cobertura-workflow.md +121 -0
  89. package/kit/commands/auditar-observabilidade-cobertura.md +183 -183
  90. package/kit/commands/auditar-refactor.md +219 -219
  91. package/kit/commands/auditar-release.md +109 -109
  92. package/kit/commands/auditar-uat.md +23 -23
  93. package/kit/commands/autonomo.md +40 -40
  94. package/kit/commands/branch-pr.md +24 -24
  95. package/kit/commands/burn-rate-status.md +408 -408
  96. package/kit/commands/capturar-payloads.md +193 -193
  97. package/kit/commands/caracterizar.md +212 -212
  98. package/kit/commands/concluir-marco.md +247 -247
  99. package/kit/commands/configuracoes.md +36 -36
  100. package/kit/commands/dados-distribuidos.md +188 -188
  101. package/kit/commands/definir-perfil.md +10 -10
  102. package/kit/commands/depurar.md +190 -190
  103. package/kit/commands/detectar-duplicacao.md +197 -197
  104. package/kit/commands/discutir-fase.md +131 -131
  105. package/kit/commands/encontrar-seams.md +136 -136
  106. package/kit/commands/entrar-discord.md +17 -17
  107. package/kit/commands/estatisticas.md +18 -18
  108. package/kit/commands/example-greeting.md +33 -33
  109. package/kit/commands/executar-fase.md +58 -58
  110. package/kit/commands/expresso.md +56 -56
  111. package/kit/commands/fase-ui.md +34 -34
  112. package/kit/commands/fazer.md +57 -57
  113. package/kit/commands/fio.md +125 -125
  114. package/kit/commands/fluxos-trabalho.md +64 -64
  115. package/kit/commands/forense.md +176 -176
  116. package/kit/commands/gerenciador.md +38 -38
  117. package/kit/commands/inserir-fase.md +31 -31
  118. package/kit/commands/legacy.md +263 -263
  119. package/kit/commands/limpeza.md +17 -17
  120. package/kit/commands/listar-hipoteses-fase.md +45 -45
  121. package/kit/commands/listar-workspaces.md +18 -18
  122. package/kit/commands/load-shedding.md +117 -117
  123. package/kit/commands/mapear-codebase.md +70 -70
  124. package/kit/commands/multi-tenant.md +163 -163
  125. package/kit/commands/nota.md +33 -33
  126. package/kit/commands/novo-marco.md +43 -43
  127. package/kit/commands/novo-projeto.md +41 -41
  128. package/kit/commands/novo-workspace.md +43 -43
  129. package/kit/commands/pausar-trabalho.md +37 -37
  130. package/kit/commands/perfil-usuario.md +45 -45
  131. package/kit/commands/pesquisar-fase.md +195 -195
  132. package/kit/commands/planejar-fase.md +67 -67
  133. package/kit/commands/planejar-lacunas.md +33 -33
  134. package/kit/commands/plantar-ideia.md +25 -25
  135. package/kit/commands/progresso.md +24 -24
  136. package/kit/commands/proximo.md +30 -30
  137. package/kit/commands/publicar.md +490 -490
  138. package/kit/commands/rapido.md +35 -35
  139. package/kit/commands/reaplicar-patches.md +124 -124
  140. package/kit/commands/refactor-seguro.md +321 -321
  141. package/kit/commands/relatorio-sessao.md +19 -19
  142. package/kit/commands/remover-fase.md +31 -31
  143. package/kit/commands/remover-workspace.md +26 -26
  144. package/kit/commands/resumo-marco.md +50 -50
  145. package/kit/commands/retomar-trabalho.md +40 -40
  146. package/kit/commands/revisar-backlog.md +60 -60
  147. package/kit/commands/revisar-ui.md +32 -32
  148. package/kit/commands/revisar.md +37 -37
  149. package/kit/commands/saude.md +21 -21
  150. package/kit/commands/setup-notion.md +93 -93
  151. package/kit/commands/storytelling.md +179 -179
  152. package/kit/commands/supabase.md +238 -238
  153. package/kit/commands/sync-main.md +68 -68
  154. package/kit/commands/validar-fase.md +35 -35
  155. package/kit/commands/verificar-tarefas.md +44 -44
  156. package/kit/commands/verificar-trabalho.md +64 -64
  157. package/kit/file-manifest.json +13 -11
  158. package/kit/framework/bin/lib/commands.cjs +959 -959
  159. package/kit/framework/bin/lib/config.cjs +442 -442
  160. package/kit/framework/bin/lib/core.cjs +1230 -1230
  161. package/kit/framework/bin/lib/frontmatter.cjs +336 -336
  162. package/kit/framework/bin/lib/init.cjs +1442 -1442
  163. package/kit/framework/bin/lib/milestone.cjs +252 -252
  164. package/kit/framework/bin/lib/model-profiles.cjs +68 -68
  165. package/kit/framework/bin/lib/phase.cjs +888 -888
  166. package/kit/framework/bin/lib/profile-output.cjs +952 -952
  167. package/kit/framework/bin/lib/profile-pipeline.cjs +539 -539
  168. package/kit/framework/bin/lib/roadmap.cjs +329 -329
  169. package/kit/framework/bin/lib/security.cjs +382 -382
  170. package/kit/framework/bin/lib/state.cjs +1031 -1031
  171. package/kit/framework/bin/lib/template.cjs +222 -222
  172. package/kit/framework/bin/lib/uat.cjs +282 -282
  173. package/kit/framework/bin/lib/verify.cjs +888 -888
  174. package/kit/framework/bin/lib/workstream.cjs +491 -491
  175. package/kit/framework/bin/tools.cjs +918 -918
  176. package/kit/framework/commands/workstreams.md +63 -63
  177. package/kit/framework/references/checkpoints.md +778 -778
  178. package/kit/framework/references/continuation-format.md +249 -249
  179. package/kit/framework/references/decimal-phase-calculation.md +64 -64
  180. package/kit/framework/references/git-integration.md +295 -295
  181. package/kit/framework/references/git-planning-commit.md +38 -38
  182. package/kit/framework/references/model-profile-resolution.md +36 -36
  183. package/kit/framework/references/model-profiles.md +139 -139
  184. package/kit/framework/references/phase-argument-parsing.md +61 -61
  185. package/kit/framework/references/planning-config.md +202 -202
  186. package/kit/framework/references/questioning.md +162 -162
  187. package/kit/framework/references/tdd.md +263 -263
  188. package/kit/framework/references/ui-brand.md +160 -160
  189. package/kit/framework/references/user-profiling.md +657 -657
  190. package/kit/framework/references/verification-patterns.md +612 -612
  191. package/kit/framework/references/workstream-flag.md +58 -58
  192. package/kit/framework/templates/DEBUG.md +164 -164
  193. package/kit/framework/templates/UAT.md +265 -265
  194. package/kit/framework/templates/UI-SPEC.md +100 -100
  195. package/kit/framework/templates/VALIDATION.md +76 -76
  196. package/kit/framework/templates/claude-md.md +122 -122
  197. package/kit/framework/templates/codebase/architecture.md +185 -185
  198. package/kit/framework/templates/codebase/concerns.md +205 -205
  199. package/kit/framework/templates/codebase/conventions.md +204 -204
  200. package/kit/framework/templates/codebase/integrations.md +192 -192
  201. package/kit/framework/templates/codebase/stack.md +158 -158
  202. package/kit/framework/templates/codebase/structure.md +199 -199
  203. package/kit/framework/templates/codebase/testing.md +301 -301
  204. package/kit/framework/templates/config.json +44 -44
  205. package/kit/framework/templates/context.md +352 -352
  206. package/kit/framework/templates/continue-here.md +78 -78
  207. package/kit/framework/templates/copilot-instructions.md +7 -7
  208. package/kit/framework/templates/debug-subagent-prompt.md +91 -91
  209. package/kit/framework/templates/dev-preferences.md +20 -20
  210. package/kit/framework/templates/discovery.md +146 -146
  211. package/kit/framework/templates/discussion-log.md +63 -63
  212. package/kit/framework/templates/milestone-archive.md +123 -123
  213. package/kit/framework/templates/milestone.md +115 -115
  214. package/kit/framework/templates/phase-prompt.md +610 -610
  215. package/kit/framework/templates/planner-subagent-prompt.md +117 -117
  216. package/kit/framework/templates/project.md +186 -186
  217. package/kit/framework/templates/requirements.md +231 -231
  218. package/kit/framework/templates/research-project/ARCHITECTURE.md +204 -204
  219. package/kit/framework/templates/research-project/FEATURES.md +147 -147
  220. package/kit/framework/templates/research-project/PITFALLS.md +200 -200
  221. package/kit/framework/templates/research-project/STACK.md +120 -120
  222. package/kit/framework/templates/research-project/SUMMARY.md +170 -170
  223. package/kit/framework/templates/research.md +419 -419
  224. package/kit/framework/templates/retrospective.md +54 -54
  225. package/kit/framework/templates/roadmap.md +202 -202
  226. package/kit/framework/templates/state.md +176 -176
  227. package/kit/framework/templates/summary-complex.md +59 -59
  228. package/kit/framework/templates/summary-minimal.md +41 -41
  229. package/kit/framework/templates/summary-standard.md +48 -48
  230. package/kit/framework/templates/summary.md +209 -209
  231. package/kit/framework/templates/user-profile.md +146 -146
  232. package/kit/framework/templates/user-setup.md +256 -256
  233. package/kit/framework/templates/verification-report.md +258 -258
  234. package/kit/framework/workflows/add-phase.md +112 -112
  235. package/kit/framework/workflows/add-tests.md +351 -351
  236. package/kit/framework/workflows/add-todo.md +158 -158
  237. package/kit/framework/workflows/audit-milestone.md +340 -340
  238. package/kit/framework/workflows/audit-uat.md +109 -109
  239. package/kit/framework/workflows/autonomous.md +891 -891
  240. package/kit/framework/workflows/check-todos.md +177 -177
  241. package/kit/framework/workflows/cleanup.md +152 -152
  242. package/kit/framework/workflows/complete-milestone.md +696 -696
  243. package/kit/framework/workflows/diagnose-issues.md +231 -231
  244. package/kit/framework/workflows/discovery-phase.md +289 -289
  245. package/kit/framework/workflows/discuss-phase-assumptions.md +653 -653
  246. package/kit/framework/workflows/discuss-phase.md +784 -784
  247. package/kit/framework/workflows/do.md +104 -104
  248. package/kit/framework/workflows/execute-phase.md +838 -838
  249. package/kit/framework/workflows/execute-plan.md +510 -510
  250. package/kit/framework/workflows/fast.md +102 -102
  251. package/kit/framework/workflows/forensics.md +265 -265
  252. package/kit/framework/workflows/health.md +181 -181
  253. package/kit/framework/workflows/help.md +619 -619
  254. package/kit/framework/workflows/insert-phase.md +130 -130
  255. package/kit/framework/workflows/list-phase-assumptions.md +178 -178
  256. package/kit/framework/workflows/list-workspaces.md +56 -56
  257. package/kit/framework/workflows/manager.md +362 -362
  258. package/kit/framework/workflows/map-codebase.md +377 -377
  259. package/kit/framework/workflows/milestone-summary.md +223 -223
  260. package/kit/framework/workflows/new-milestone.md +486 -486
  261. package/kit/framework/workflows/new-project.md +1159 -1159
  262. package/kit/framework/workflows/new-workspace.md +237 -237
  263. package/kit/framework/workflows/next.md +97 -97
  264. package/kit/framework/workflows/node-repair.md +92 -92
  265. package/kit/framework/workflows/note.md +156 -156
  266. package/kit/framework/workflows/pause-work.md +176 -176
  267. package/kit/framework/workflows/plan-milestone-gaps.md +273 -273
  268. package/kit/framework/workflows/plan-phase.md +765 -765
  269. package/kit/framework/workflows/plant-seed.md +169 -169
  270. package/kit/framework/workflows/pr-branch.md +129 -129
  271. package/kit/framework/workflows/profile-user.md +450 -450
  272. package/kit/framework/workflows/progress.md +507 -507
  273. package/kit/framework/workflows/quick.md +757 -757
  274. package/kit/framework/workflows/remove-phase.md +155 -155
  275. package/kit/framework/workflows/remove-workspace.md +90 -90
  276. package/kit/framework/workflows/research-phase.md +82 -82
  277. package/kit/framework/workflows/resume-project.md +326 -326
  278. package/kit/framework/workflows/review.md +228 -228
  279. package/kit/framework/workflows/session-report.md +146 -146
  280. package/kit/framework/workflows/settings.md +283 -283
  281. package/kit/framework/workflows/ship.md +228 -228
  282. package/kit/framework/workflows/stats.md +60 -60
  283. package/kit/framework/workflows/transition.md +671 -671
  284. package/kit/framework/workflows/ui-phase.md +302 -302
  285. package/kit/framework/workflows/ui-review.md +165 -165
  286. package/kit/framework/workflows/update.md +323 -323
  287. package/kit/framework/workflows/validate-phase.md +174 -174
  288. package/kit/framework/workflows/verify-phase.md +252 -252
  289. package/kit/framework/workflows/verify-work.md +637 -637
  290. package/kit/hooks/check-update.js +118 -118
  291. package/kit/hooks/context-monitor.js +163 -163
  292. package/kit/hooks/kit-attribution-reminder.cjs +92 -92
  293. package/kit/hooks/kit-router.cjs +137 -137
  294. package/kit/hooks/prompt-guard.js +103 -103
  295. package/kit/hooks/statusline.js +125 -125
  296. package/kit/hooks/workflow-guard.js +101 -101
  297. package/kit/settings.json +45 -45
  298. package/kit/skills/ai-prompt-characterization/SKILL.md +335 -335
  299. package/kit/skills/armadilhas-sistemas-distribuidos/SKILL.md +447 -447
  300. package/kit/skills/audit-log-multi-tenant/SKILL.md +340 -340
  301. package/kit/skills/b2b-saas-architecture/SKILL.md +300 -300
  302. package/kit/skills/consistencia-leitura-replica/SKILL.md +385 -385
  303. package/kit/skills/crm-lead-pipeline-patterns/SKILL.md +343 -343
  304. package/kit/skills/escolha-modelo-consistencia/SKILL.md +494 -494
  305. package/kit/skills/evolucao-schema-compativel/SKILL.md +448 -448
  306. package/kit/skills/evolution-go-whatsapp-integration/SKILL.md +322 -322
  307. package/kit/skills/example-skill/SKILL.md +42 -42
  308. package/kit/skills/legacy-api-only-applications/SKILL.md +358 -358
  309. package/kit/skills/legacy-characterization-tests/SKILL.md +330 -330
  310. package/kit/skills/legacy-effect-analysis/SKILL.md +331 -331
  311. package/kit/skills/legacy-extract-class/SKILL.md +203 -203
  312. package/kit/skills/legacy-programming-by-difference/SKILL.md +252 -252
  313. package/kit/skills/legacy-seams-and-test-harness/SKILL.md +460 -460
  314. package/kit/skills/legacy-shotgun-surgery/SKILL.md +286 -286
  315. package/kit/skills/legacy-sprout-wrap-techniques/SKILL.md +434 -434
  316. package/kit/skills/legacy-storytelling-naked-crc/SKILL.md +270 -270
  317. package/kit/skills/lgpd-multi-tenant-compliance/SKILL.md +340 -340
  318. package/kit/skills/member-invite-flow/SKILL.md +305 -305
  319. package/kit/skills/member-management-react-shadcn/SKILL.md +328 -328
  320. package/kit/skills/multi-tenant-performance-scaling/SKILL.md +316 -316
  321. package/kit/skills/multi-tenant-rls-hierarchy/SKILL.md +342 -342
  322. package/kit/skills/org-onboarding-flow/SKILL.md +257 -257
  323. package/kit/skills/org-switcher-react-pattern/SKILL.md +349 -349
  324. package/kit/skills/permission-gate-react-pattern/SKILL.md +271 -271
  325. package/kit/skills/postgres-isolamento-concorrencia/SKILL.md +552 -552
  326. package/kit/skills/pre-refactor-characterization/SKILL.md +421 -421
  327. package/kit/skills/rbac-permissions-matrix-supabase/SKILL.md +338 -338
  328. package/kit/skills/streams-eventos-cdc/SKILL.md +711 -711
  329. package/kit/skills/supabase-auth-hardening/SKILL.md +674 -674
  330. package/kit/skills/supabase-auth-hooks/SKILL.md +875 -875
  331. package/kit/skills/supabase-auth-methods/SKILL.md +486 -486
  332. package/kit/skills/supabase-auth-sessions/SKILL.md +579 -579
  333. package/kit/skills/supabase-auth-ssr/SKILL.md +306 -306
  334. package/kit/skills/supabase-branching-workflow/SKILL.md +544 -544
  335. package/kit/skills/supabase-ci-cd-github-actions/SKILL.md +880 -880
  336. package/kit/skills/supabase-column-level-security/SKILL.md +426 -426
  337. package/kit/skills/supabase-config-toml-remotes/SKILL.md +807 -807
  338. package/kit/skills/supabase-custom-claims-rbac/SKILL.md +472 -472
  339. package/kit/skills/supabase-edge-functions/SKILL.md +330 -330
  340. package/kit/skills/supabase-edge-functions-auth/SKILL.md +309 -309
  341. package/kit/skills/supabase-edge-functions-limits/SKILL.md +302 -302
  342. package/kit/skills/supabase-edge-functions-mcp-server/SKILL.md +279 -279
  343. package/kit/skills/supabase-edge-functions-testing/SKILL.md +277 -277
  344. package/kit/skills/supabase-edge-runtime-builtins/SKILL.md +357 -357
  345. package/kit/skills/supabase-enterprise-sso-saml/SKILL.md +545 -545
  346. package/kit/skills/supabase-jwt-signing-keys/SKILL.md +399 -399
  347. package/kit/skills/supabase-mfa/SKILL.md +488 -488
  348. package/kit/skills/supabase-migration-repair/SKILL.md +823 -823
  349. package/kit/skills/supabase-migrations/SKILL.md +297 -297
  350. package/kit/skills/supabase-oauth-server/SKILL.md +537 -537
  351. package/kit/skills/supabase-pgtap-testing/SKILL.md +1053 -1053
  352. package/kit/skills/supabase-postgres-roles/SKILL.md +392 -392
  353. package/kit/skills/supabase-realtime/SKILL.md +460 -460
  354. package/kit/skills/supabase-rls-defense-in-depth/SKILL.md +418 -418
  355. package/kit/skills/supabase-rls-policies/SKILL.md +635 -635
  356. package/kit/skills/supabase-social-oauth/SKILL.md +480 -480
  357. package/kit/skills/supabase-third-party-auth/SKILL.md +450 -450
  358. package/kit/skills/super-admin-platform-pattern/SKILL.md +326 -326
  359. package/kit/skills/tenant-quente-mitigacao/SKILL.md +605 -605
  360. package/kit/skills/ui-anti-padroes-ia/SKILL.md +261 -261
  361. package/kit/skills/ui-contexto-produto/SKILL.md +248 -248
  362. package/kit/skills/ui-cor-estrategia/SKILL.md +213 -213
  363. package/kit/skills/ui-critica-auditoria/SKILL.md +260 -260
  364. package/kit/skills/ui-motion-funcional/SKILL.md +264 -264
  365. package/kit/skills/ui-ritmo-espacial/SKILL.md +259 -259
  366. package/kit/skills/ui-tipografia/SKILL.md +211 -211
  367. package/kit/skills/whatsapp-conversation-state-machine/SKILL.md +287 -287
  368. package/kit/workflows/auditar-observabilidade-cobertura.workflow.js +250 -0
  369. package/package.json +65 -63
  370. package/src/core/kit.js +333 -216
  371. package/src/core/reflect.js +247 -247
  372. package/src/core/registry.js +123 -112
  373. package/src/core/reverse-sync.js +448 -372
  374. package/src/core/sync.js +477 -437
  375. package/src/core/watch.js +121 -121
  376. 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