@seedgrid/ai-toolkit 0.0.0-stage → 0.3.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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -2
  3. package/dist/adapters/claude.js +114 -0
  4. package/dist/adapters/codex.js +108 -0
  5. package/dist/adapters/index.js +17 -0
  6. package/dist/adapters/shared.js +142 -0
  7. package/dist/adapters/types.js +1 -0
  8. package/dist/cli.js +203 -0
  9. package/dist/commands/common.js +98 -0
  10. package/dist/commands/doctor.js +290 -0
  11. package/dist/commands/init.js +9 -0
  12. package/dist/commands/install.js +107 -0
  13. package/dist/commands/remove.js +54 -0
  14. package/dist/commands/review.js +127 -0
  15. package/dist/commands/status.js +73 -0
  16. package/dist/commands/update.js +8 -0
  17. package/dist/commands/validate.js +27 -0
  18. package/dist/core/apply.js +181 -0
  19. package/dist/core/blocks.js +64 -0
  20. package/dist/core/content.js +528 -0
  21. package/dist/core/env.js +40 -0
  22. package/dist/core/frontmatter.js +29 -0
  23. package/dist/core/hash.js +14 -0
  24. package/dist/core/inspect.js +51 -0
  25. package/dist/core/lock.js +124 -0
  26. package/dist/core/paths.js +65 -0
  27. package/dist/core/plan.js +242 -0
  28. package/dist/core/tools.js +62 -0
  29. package/dist/core/types.js +11 -0
  30. package/dist/core/updates.js +121 -0
  31. package/docs/arquitetura.md +80 -0
  32. package/docs/compatibilidade.md +50 -0
  33. package/docs/formato.md +155 -0
  34. package/docs/instalacao.md +105 -0
  35. package/docs/manutencao.md +115 -0
  36. package/package.json +43 -4
  37. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
  38. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
  39. package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
  40. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
  41. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
  42. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
  43. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
  44. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
  45. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
  46. package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
  47. package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
  48. package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
  49. package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
  50. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
  51. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
  52. package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
  53. package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
  54. package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
  55. package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
  56. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
  57. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
  58. package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
  59. package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
  60. package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
  61. package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
  62. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
  63. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
  64. package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
  65. package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
  66. package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
  67. package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
  68. package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
  69. package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
  70. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
  71. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
  72. package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
  73. package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
  74. package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
  75. package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
  76. package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
  77. package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
  78. package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
  79. package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
  80. package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
  81. package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
  82. package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
  83. package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
  84. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
  85. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
  86. package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
  87. package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
  88. package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
  89. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
  90. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
  91. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
  92. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
  93. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
  94. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
  95. package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
  96. package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
  97. package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
  98. package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
  99. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
  100. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
  101. package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
  102. package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
  103. package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
  104. package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
  105. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
  106. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
  107. package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
  108. package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
  109. package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
  110. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
  111. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
  112. package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
  113. package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
  114. package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
  115. package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
  116. package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
  117. package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
  118. package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
  119. package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
  120. package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
  121. package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
  122. package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
  123. package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
  124. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
  125. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
  126. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
  127. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
  128. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
  129. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
  130. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
  131. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
  132. package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
  133. package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
  134. package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
  135. package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
  136. package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
  137. package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
  138. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
  139. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
  140. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
  141. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
  142. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
  143. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
  144. package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
  145. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
  146. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
  147. package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
  148. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
  149. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
  150. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
  151. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
  152. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
  153. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
  154. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
  155. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
  156. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
  157. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
  158. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
  159. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
  160. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
  161. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
  162. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
  163. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
  164. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
  165. package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
  166. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
  167. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
  168. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
  169. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
  170. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
  171. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
  172. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
  173. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
  174. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
  175. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
  176. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
  177. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
  178. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
  179. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
  180. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
  181. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
  182. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
  183. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
  184. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
  185. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
  186. package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
  187. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
  188. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
  189. package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
  190. package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
  191. package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
  192. package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
  193. package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
  194. package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
  195. package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
  196. package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
  197. package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
  198. package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
  199. package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
  200. package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
  201. package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
  202. package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
  203. package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
  204. package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
  205. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
  206. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
  207. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
  208. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
  209. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
  210. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
  211. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
  212. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
  213. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
  214. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
  215. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
  216. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
  217. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
  218. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
  219. package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
  220. package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
  221. package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
  222. package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
  223. package/seedgridKB/SeedGrid/Versoes.md +64 -0
  224. package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
  225. package/seedgridKB/manifest.json +142 -0
@@ -0,0 +1,105 @@
1
+ ---
2
+ tags: [seedgrid, extension, realtime]
3
+ fonte: java/seedgrid-quarkus-ext-realtime
4
+ branch: main
5
+ commit: 8f13639b3c
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Realtime (Quarkus) — visão geral
10
+
11
+ Avisos em tempo real para o **usuário logado** através do **SeedGrid Pulse** (serviço externo de publish/subscribe). A extension entrega ao front um token curto de conexão ao Pulse e repassa ao Pulse todo `SgUserEvent` da plataforma, sem código de negócio no host.
12
+
13
+ - Configuração: [[SeedGrid/Extensions/realtime/Configuracao|Configuração do realtime]]
14
+ - Exemplos: [[SeedGrid/Extensions/realtime/Exemplos|Exemplos do realtime]]
15
+ - Enums: a extension não define enums (nem Java nem de contrato com o Pulse).
16
+ - Porte Rust (crate `seedgrid-rust-crate-realtime`): [[SeedGrid/Extensions/realtime/Rust|Porte Rust]]
17
+
18
+ ## Funcionalidades (Confirmado)
19
+
20
+ | Funcionalidade | Onde |
21
+ |---|---|
22
+ | `POST /realtime/connect` (autenticado): emite o token de conexão do usuário **da sessão** (nunca do corpo do request) | `RealtimeController#connect()` |
23
+ | Bean injetável `RealtimePublisher` (`publishToUser`, `issueConnectToken`, `isEnabled`) | `RealtimePublisher` |
24
+ | Observer de `SgUserEvent` (`seedgrid-commons`) em `TransactionPhase.AFTER_SUCCESS` → publica para o usuário | `SgUserEventObserver#onUserEvent` |
25
+ | Rate limit de emissão de token por usuário (janela fixa de 1 min, em memória, por instância) | `ConnectRateLimiter#tryAcquire` |
26
+ | "Nunca derruba quem chama": desligado = no-op; Pulse fora do ar = log WARN e segue | `RealtimePublisher#publishToUser` |
27
+
28
+ ## Módulos Maven e coordenadas (Confirmado — `pom.xml`)
29
+
30
+ | Módulo | groupId | artifactId | Versão |
31
+ |---|---|---|---|
32
+ | parent | `br.com.seedgrid` | `seedgrid-realtime-parent` | `2026.10.08` |
33
+ | runtime | `br.com.seedgrid` | `seedgrid-realtime` | `2026.10.08` |
34
+ | deployment | `br.com.seedgrid` | `seedgrid-realtime-deployment` | `2026.10.08` |
35
+
36
+ Parent: `br.com.seedgrid:seedgrid-parent:2026.07.02`. `quarkus-extension.properties` exige Quarkus `[3.30,)`. Status no `quarkus-extension.yaml`: `preview`.
37
+
38
+ ## Dependências
39
+
40
+ | Dependência | Versão | Observação |
41
+ |---|---|---|
42
+ | `br.com.seedgrid:seedgrid-commons` | `2026.10.08` | Só `SgUserEvent` e `CurrentUserProvider`; exclui `quarkus-hibernate-orm` e `quarkus-hibernate-orm-panache` (a extension não tem banco). |
43
+ | `br.com.seedgrid:seedgrid-pulse-publisher` | `2026.10.0` | SDK do Pulse (`PulsePublisher`, `ConnectToken`, `IssueConnectTokenInput`, `PublishMessageInput`). |
44
+ | `quarkus-arc`, `quarkus-rest-jackson`, `quarkus-security` | BOM | — |
45
+
46
+ Requisito implícito (Inferência, pelo uso de `CurrentUserProvider` e `@Authenticated`): o host precisa de um mecanismo de autenticação e de um `CurrentUserProvider` que devolva o `publicId` do usuário (no ecossistema SeedGrid, o `JwtCurrentUserProvider` do `seedgrid-security`, segundo o javadoc de `TestCurrentUserProvider`).
47
+
48
+ ## Arquitetura e fluxo
49
+
50
+ ```mermaid
51
+ flowchart LR
52
+ P[Processo do host / outra extension] -- "Event&lt;SgUserEvent&gt;.fire()" --> O[SgUserEventObserver<br/>AFTER_SUCCESS]
53
+ O --> RP[RealtimePublisher.publishToUser]
54
+ RP -- "publishAsync (x-api-key = project key)" --> PULSE[(SeedGrid Pulse)]
55
+ F[Front logado] -- "POST /realtime/connect" --> C[RealtimeController]
56
+ C --> RL[ConnectRateLimiter]
57
+ C --> RP2[RealtimePublisher.issueConnectToken]
58
+ RP2 --> PULSE
59
+ C -- "token pct_..., expiresAt, connectUrl, channels" --> F
60
+ F -- "WebSocket com o token" --> PULSE
61
+ ```
62
+
63
+ - O `RealtimePublisher` monta o `PulsePublisher` uma vez, no construtor: só se `seedgrid.realtime.enabled=true` **e** houver `pulse.base-url` e `pulse.project-key` não vazios. Caso contrário fica desligado (com log ERROR se estava ligado mas incompleto). (Confirmado — `RealtimePublisher#connect`)
64
+ - `SgUserEventObserver` só publica depois do commit; se a transação desfizer, não publica. (Confirmado)
65
+ - O Pulse fingido nos testes expõe `POST /api/v1/connect-tokens` e `POST /api/v1/messages`, e o header usado é `x-api-key`. (Confirmado em `RealtimeEnabledTest`; são detalhes do SDK do Pulse, não desta extension.)
66
+
67
+ ## API pública e pontos de integração
68
+
69
+ ### Endpoint REST
70
+
71
+ | Método | Path | Segurança | Respostas |
72
+ |---|---|---|---|
73
+ | `POST` | `/realtime/connect` (sob o root path REST do host, se houver) | `@Authenticated` | `200 {enabled:false}` (desligado); `200 {enabled:true, token, expiresAt, connectUrl, channels}`; `401` sem usuário (inclusive o UUID zerado `00000000-0000-0000-0000-000000000000` do provider padrão); `429` com `Retry-After` (segundos); `503` se o Pulse falhar |
74
+
75
+ `RealtimeConnectResponse` usa `@JsonInclude(NON_NULL)`; `expiresAt` é epoch em **segundos**; `channels` ausente = todos os da conta. (Confirmado)
76
+
77
+ ### Beans / eventos
78
+
79
+ | Símbolo | Tipo | Uso |
80
+ |---|---|---|
81
+ | `br.com.seedgrid.realtime.services.RealtimePublisher` | `@ApplicationScoped`, unremovable | `publishToUser(String channel, String event, String userPublicId, Map<String,Object> data)`; `issueConnectToken(String userPublicId)` (lança `IllegalStateException` se desligado); `isEnabled()` |
82
+ | `br.com.seedgrid.commons.events.SgUserEvent` | evento CDI (do commons) | `new SgUserEvent(userPublicId, channel, event, data)` — observado pela extension |
83
+ | `br.com.seedgrid.realtime.configs.RealtimeConfig` | `@ConfigMapping` | ver [[SeedGrid/Extensions/realtime/Configuracao|Configuração]] |
84
+
85
+ O deployment (`SeedgridRealtimeProcessor`) registra a feature `seedgrid-realtime`, o `ConfigMappingBuildItem` e torna `RealtimePublisher`, `ConnectRateLimiter` e `SgUserEventObserver` unremovable.
86
+
87
+ ## Migrations
88
+
89
+ Nenhuma (a extension não tem banco). (Confirmado)
90
+
91
+ ## Testes existentes (não executados)
92
+
93
+ | Teste | O que cobre |
94
+ |---|---|
95
+ | `runtime/src/test/.../RealtimeEnabledTest` | 401 sem sessão; token do usuário da sessão com a project key; `subject` do request ignorado; 503 com Pulse fora; `SgUserEvent` vira publicação; erro do Pulse não chega a quem disparou |
96
+ | `runtime/src/test/.../RealtimeDisabledTest` | desligado: `{enabled:false}` e nenhuma chamada ao Pulse |
97
+ | `runtime/src/test/.../services/ConnectRateLimiterTest` | limite por usuário, reabertura da janela, `0` desliga |
98
+ | `FakePulse` (WireMock) / `TestCurrentUserProvider` | infraestrutura de teste |
99
+
100
+ ## Limitações
101
+
102
+ - O rate limit é **em memória e por instância**: com N réplicas o limite efetivo por usuário é até N × `connect-rate-per-minute` (Inferência a partir de `ConnectRateLimiter`, que usa `ConcurrentHashMap` local). As janelas antigas não são removidas do mapa (Inferência: não há limpeza no código).
103
+ - A configuração é lida uma vez na construção do `RealtimePublisher` (bean `@ApplicationScoped`); mudar config exige reinício (Inferência).
104
+ - `data` deve carregar apenas identificadores, nunca conteúdo (recomendação do README; não há validação no código).
105
+ - O `NO_USER` (UUID zerado) é uma convenção do `DefaultCurrentUserProvider` do commons; outros providers que devolvam outro sentinela não são tratados (Inferência).
@@ -0,0 +1,68 @@
1
+ ---
2
+ tags: [seedgrid, extension, resilience, rust, configuracao]
3
+ fonte: rust/seedgrid-rust-crate-resilience
4
+ branch: main
5
+ commit: be738a2d1e
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # resilience — Configuração Rust
10
+
11
+ Visão do crate: [[SeedGrid/Extensions/resilience/Rust|Porte Rust do resilience]] · Java: [[SeedGrid/Extensions/resilience/Configuracao|Configuração do resilience (Java)]].
12
+
13
+ ## Cabeçalho
14
+ | Item | Valor |
15
+ |---|---|
16
+ | Mecanismo | (1) structs-"anotação" `SeedGridCircuitBreaker` e `SeedGridRateLimit` com `Default` (= defaults das anotações Java); (2) overrides por nome lidos de uma `ConfigSource` injetada (`src/config.rs`) |
17
+ | Variáveis de ambiente | **nenhuma** — `grep` por `env::var` em `src/` não encontra nada (**Confirmado**) |
18
+ | `ConfigSource` disponíveis | `EmptyConfigSource` (nenhuma chave) e `MapConfigSource` (mapa tipado). **Não existe** implementação baseada em ambiente no workspace |
19
+ | Uso real no workspace | security (`src/ratelimit.rs`) e `seedgrid-runtime` (exemplo/teste) usam `EmptyConfigSource` → os overrides abaixo **não têm efeito** a menos que o host implemente `ConfigSource` |
20
+ | Leitura | a cada `try_acquire` / `resolve` (sem cache) |
21
+ | Equivalente Java | `Config#getOptionalValue` em `RateLimitService.java` e `CircuitBreakerConfigResolver.java`; mesmas chaves |
22
+
23
+ Os overrides só são consultados quando a "anotação" tem `config_key` (rate limit) ou `name` (circuit breaker) não vazio.
24
+
25
+ ## Overrides de rate limit — `seedgrid.ratelimit.{configKey}.*`
26
+ | Propriedade | Tipo (`ConfigValue`) | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
27
+ |---|---|---|---|---|---|---|---|---|---|
28
+ | `seedgrid.ratelimit.{configKey}.enabled` | `Bool` | `true`/`false` | `true` | Não | `false` libera sem tocar o cache (kill switch) | `RateLimitService::try_acquire` | — | por chamada | `src/ratelimiter/service.rs` → `is_enabled` |
29
+ | `seedgrid.ratelimit.{configKey}.permits` | `Long` | > 0 | `SeedGridRateLimit.permits` (5) | Não | permits por janela; ≤ 0 → panic | `resolve_permits` | `burst-capacity` | por chamada | idem |
30
+ | `seedgrid.ratelimit.{configKey}.window` | `Duration` | > 0 | `window` × `window_unit` (30 s) | Não | tamanho da janela | `resolve_window_ms` | — | por chamada | idem |
31
+ | `seedgrid.ratelimit.{configKey}.min-spacing` | `Duration` | ≥ 0 | `min_spacing` × `min_spacing_unit` (0) | Não | espaçamento mínimo entre chamadas | `resolve_min_spacing_ms` | — | por chamada | idem |
32
+ | `seedgrid.ratelimit.{configKey}.burst-capacity` | `Long` | ≥ 0 (0 = usa `permits`) | `burst_capacity` (0) | Não | capacidade do token bucket | `resolve_burst_capacity` | `algorithm` | por chamada | idem |
33
+ | `seedgrid.ratelimit.{configKey}.algorithm` | `Str` | `FIXED_WINDOW`, `SLIDING_WINDOW`, `TOKEN_BUCKET` (`trim`, maiúsculas, `-`→`_`); outro → **panic** | `algorithm` (`FIXED_WINDOW`) | Não | escolhe a estratégia | `resolve_algorithm` / `parse_algorithm` | — | por chamada | idem |
34
+
35
+ `configKey`s usados no workspace (fixos em código): `export-create` (backup, 10/hora), `billing-checkout` (30/min), `billing-portal` (30/min), `billing-webhook` (300/min); a security define os seus em `rust/seedgrid-rust-crate-security/src/ratelimit.rs` (fora deste escopo).
36
+
37
+ ## Overrides de circuit breaker — `seedgrid.circuitbreaker.{name}.*`
38
+ | Propriedade | Tipo | Valores aceitos | Padrão (`SeedGridCircuitBreaker::default`) | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
39
+ |---|---|---|---|---|---|---|---|---|---|
40
+ | `seedgrid.circuitbreaker.{name}.enabled` | `Bool` | bool | `true` | Não | `false` desliga o circuito | `CircuitBreakerConfigResolver::is_enabled` | — | por chamada | `src/circuitbreaker/config_resolver.rs` |
41
+ | `.sliding-window-size` | `Int` | inteiro | `100` | Não | slots da janela (em `TIME_BASED`, segundos) | `resolve` | `window-type` | idem | idem |
42
+ | `.window-type` | `Str` | `COUNT_BASED`, `TIME_BASED` (normalizado); outro → **panic** | `COUNT_BASED` | Não | tipo de janela | `resolve` / `parse_window_type` | — | idem | idem |
43
+ | `.failure-rate-threshold` | `Double` | % | `50.0` | Não | abre ao atingir a taxa de falha | `resolve` | `minimum-number-of-calls` | idem | idem |
44
+ | `.slow-call-duration` | `Duration` | duração (→ ms) | `0` (desligado) | Não | limiar de chamada lenta | `resolve` | `slow-call-rate-threshold` | idem | idem |
45
+ | `.slow-call-rate-threshold` | `Double` | % | `100.0` | Não | abre pela taxa de lentidão | `resolve` | — | idem | idem |
46
+ | `.minimum-number-of-calls` | `Int` | inteiro | `20` | Não | mínimo antes de avaliar | `resolve` | — | idem | idem |
47
+ | `.open-state-duration` | `Duration` | duração (→ ms) | `30000` ms | Não | tempo em OPEN antes de HALF_OPEN | `resolve` | — | idem | idem |
48
+ | `.permitted-calls-in-half-open` | `Int` | inteiro | `10` | Não | sondagens em HALF_OPEN | `resolve` | — | idem | idem |
49
+
50
+ `record_exceptions` (padrão `["Exception"]`), `ignore_exceptions` e `fallback_method` existem só na struct (referências de código).
51
+
52
+ ## Defaults de `SeedGridRateLimit`
53
+ `permits=5`, `window=30`, `window_unit=Seconds`, `algorithm=FixedWindow`, `burst_capacity=0`, `min_spacing=0`, `min_spacing_unit=Millis`, `identity=IpIdentityResolver`, `group=""`, `scope=Method`, `emit_headers=true`, `config_key=""` (`src/ratelimiter/config.rs`).
54
+
55
+ ## Features Cargo
56
+ Nenhuma.
57
+
58
+ ## Configuração mínima (programática)
59
+ ```rust
60
+ let source = MapConfigSource::new()
61
+ .with("seedgrid.ratelimit.billing-checkout.permits", ConfigValue::Long(60))
62
+ .with("seedgrid.ratelimit.billing-checkout.window", ConfigValue::Duration(Duration::from_secs(60)));
63
+ let service = RateLimitService::new(cache, Arc::new(source));
64
+ ```
65
+
66
+ ## Receitas
67
+ - **Desligar um rate limit em produção**: `seedgrid.ratelimit.<configKey>.enabled = Bool(false)` numa `ConfigSource` do host.
68
+ - **Ler overrides do ambiente**: implementar `ConfigSource` no host (ex.: mapear `SEEDGRID_RATELIMIT_<KEY>_PERMITS`) — não fornecido pela crate.
@@ -0,0 +1,186 @@
1
+ ---
2
+ tags: [seedgrid, extension, resilience, configuracao]
3
+ fonte: java/seedgrid-quarkus-ext-resilience
4
+ branch: main
5
+ commit: eff41304f8
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Configuração — SeedGrid Resilience (Quarkus)
10
+
11
+ Voltar: [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral do resilience]] · [[SeedGrid/Extensions/resilience/Exemplos|Exemplos]] · [[SeedGrid/Extensions/resilience/Rust|Porte Rust]]
12
+
13
+ ## 1. Cabeçalho
14
+
15
+ | Item | Valor |
16
+ |---|---|
17
+ | Prefixos | `seedgrid.ratelimit.{configKey}.*` e `seedgrid.circuitbreaker.{name}.*` (segmento dinâmico vindo da anotação) |
18
+ | Classes que leem config | `runtime/.../ratelimiter/services/RateLimitService.java` (`CONFIG_PREFIX = "seedgrid.ratelimit."`) e `runtime/.../circuitbreaker/configs/CircuitBreakerConfigResolver.java` (`CONFIG_PREFIX = "seedgrid.circuitbreaker."`) |
19
+ | Mecanismo | `org.eclipse.microprofile.config.Config` injetado por construtor + `config.getOptionalValue(prefixo + chave, Tipo.class)` com chave montada por concatenação. **Não há** `@ConfigMapping`, `@ConfigRoot`, `@ConfigProperty`, `ConfigProvider.getConfig()`, `META-INF/microprofile-config.properties` nem `application.properties` em `src/main` do runtime. O deployment (`SeedgridResilienceCoreProcessor`) só registra a feature; não há `*BuildTimeConfig`/`*RuntimeConfig` nem `@IfBuildProperty`/`@LookupIfProperty`. **Confirmado** (grep + leitura de todos os `.java`). |
20
+ | Fase | **Runtime**. Lidas **a cada invocação** do método anotado (sem cache local). **Inferência**: alterações em uma fonte de config dinâmica seriam percebidas sem reinício; com `application.properties` estático, valem do boot em diante. |
21
+ | Precedência | Atributo da anotação = padrão; property (quando a anotação tem `configKey`/`name` não vazio) = override. Sem `configKey`/`name`, **nenhuma** property é lida. |
22
+ | MicroProfile Fault Tolerance | Não usado; chaves `<classe>/<método>/<Anotação>/<param>` não têm efeito nesta extension. |
23
+
24
+ **Variáveis de ambiente (Inferência)**: as leituras são por nome exato via `Config#getOptionalValue`; a fonte de env do SmallRye procura o nome exato, depois com não alfanuméricos trocados por `_`, depois em maiúsculas. Logo `seedgrid.ratelimit.login.permits` ↔ `SEEDGRID_RATELIMIT_LOGIN_PERMITS` e `seedgrid.ratelimit.forgot-password.enabled` ↔ `SEEDGRID_RATELIMIT_FORGOT_PASSWORD_ENABLED`. Como a busca parte do nome (não da env), não há ambiguidade na leitura; mas `configKey` `forgot-password` e `forgot.password` colidiriam na mesma env. Não testado no repositório.
25
+
26
+ Legenda da coluna *Padrão*: "atributo X da anotação" significa que, sem a property, vale o valor informado na anotação; entre parênteses o default declarado na própria anotação.
27
+
28
+ ## 2. Propriedades da extension
29
+
30
+ ### 2.1 Rate limit — `seedgrid.ratelimit.{configKey}.*`
31
+
32
+ `{configKey}` = `SeedGridRateLimit#configKey()` (texto livre; cada valor é um limiter independente no que diz respeito à config — o contador no cache é definido pela chave `rl:...`, ver [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral]]).
33
+
34
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
35
+ |---|---|---|---|---|---|---|---|---|---|
36
+ | `seedgrid.ratelimit.{configKey}.enabled` | `Boolean` | `true` \| `false` | `true` (fixo no código) | Não | `false` desliga o limiter: `tryAcquire` retorna `allow` sem tocar no cache (headers ainda emitidos com `permits`/janela da anotação se `emitHeaders=true`) | Kill switch por limiter | Só lida se `configKey` não vazio | Runtime (por chamada) | Declaração/consumo: `RateLimitService#isEnabled(String)` chamado em `#tryAcquire` |
37
+ | `seedgrid.ratelimit.{configKey}.permits` | `Long` | inteiro `> 0` (senão `IllegalArgumentException("permits must be > 0")` na chamada) | atributo `permits` da anotação (`5`) | Não | Requisições permitidas por janela; no token bucket é a taxa de reposição por janela e a capacidade quando `burst-capacity` = 0 | Ajustar limite sem recompilar | `window`; `burst-capacity` | Runtime | `RateLimitService#resolvePermits` / `#validateConfig` |
38
+ | `seedgrid.ratelimit.{configKey}.window` | `java.time.Duration` | ISO-8601 (`PT30S`, `PT1M`, `PT1H`) — confirmado pelo README e teste; outros formatos (ex.: `30s`) **não confirmado**. Deve resultar em `> 0` ms | atributo `window` × `windowUnit` (`30` × `SECONDS`) | Não | Tamanho da janela (substitui `window`+`windowUnit`); também TTL das chaves no cache | Ajustar janela | `permits` | Runtime | `RateLimitService#resolveWindowMs` |
39
+ | `seedgrid.ratelimit.{configKey}.algorithm` | `String` → `RateLimitAlgorithm` | `fixed-window`, `sliding-window`, `token-bucket` ou os nomes do enum (`FIXED_WINDOW`, `SLIDING_WINDOW`, `TOKEN_BUCKET`) — [[SeedGrid/Extensions/resilience/Enums#RateLimitAlgorithm|RateLimitAlgorithm]]; case-insensitive, `-`→`_`. Valor inválido → `IllegalArgumentException` na chamada | atributo `algorithm` (`FIXED_WINDOW`) | Não | Seleciona estratégia `FixedWindowAlgorithm` / `SlidingWindowAlgorithm` / `TokenBucketAlgorithm` | Trocar algoritmo em produção | `burst-capacity` só afeta token bucket; `min-spacing` não afeta fixed window | Runtime | `RateLimitService#resolveAlgorithm` / `#resolveStrategy` |
40
+ | `seedgrid.ratelimit.{configKey}.burst-capacity` | `Long` | `>= 0` (negativo → `IllegalArgumentException`) | atributo `burstCapacity` (`0`) | Não | Capacidade do bucket; `0` = usa `permits` | Permitir rajadas | Efetivo só com `token-bucket` | Runtime | `RateLimitService#resolveBurstCapacity`; consumo em `TokenBucketAlgorithm#doAcquire` |
41
+ | `seedgrid.ratelimit.{configKey}.min-spacing` | `java.time.Duration` | ISO-8601 (`PT1S`, `PT0.2S`); `>= 0` | atributo `minSpacing` × `minSpacingUnit` (`0` × `MILLIS`; se `minSpacing>0` mas < 1 ms, vira 1 ms) | Não | Intervalo mínimo entre chamadas permitidas da mesma chave | Anti-martelada | **Ignorado** por `FIXED_WINDOW`; aplicado por `SLIDING_WINDOW` e `TOKEN_BUCKET` | Runtime | `RateLimitService#resolveMinSpacingMs`; consumo em `SlidingWindowAlgorithm`/`TokenBucketAlgorithm` |
42
+
43
+ Atributos **somente na anotação** (sem property): `identity`, `group`, `scope`, `emitHeaders`, `configKey`, `windowUnit`, `minSpacingUnit`. **Confirmado** (`RateLimitService` não lê outras chaves).
44
+
45
+ ### 2.2 Circuit breaker — `seedgrid.circuitbreaker.{name}.*`
46
+
47
+ `{name}` = `SeedGridCircuitBreaker#name()`. Sem `name`, o circuito usa a assinatura do método como nome e **nenhuma** property é lida.
48
+
49
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
50
+ |---|---|---|---|---|---|---|---|---|---|
51
+ | `seedgrid.circuitbreaker.{name}.enabled` | `Boolean` | `true` \| `false` | `true` (fixo no código) | Não | `false`: interceptor chama o método direto, sem estado nem fallback | Kill switch por circuito | Só lida se `name` não vazio | Runtime (por chamada) | `CircuitBreakerConfigResolver#isEnabled`; consumo `CircuitBreakerInterceptor#around` |
52
+ | `seedgrid.circuitbreaker.{name}.sliding-window-size` | `Integer` | inteiro `> 0` (**Inferência**: 0/negativo quebraria o ring buffer; sem validação explícita) | atributo `slidingWindowSize` (`100`) | Não | Tamanho do ring buffer; em `TIME_BASED` também é a duração da janela **em segundos**. Mudar o valor descarta o estado salvo | Ajustar janela de métricas | `window-type`, `minimum-number-of-calls` | Runtime | `CircuitBreakerConfigResolver#resolve`; consumo `CacheBackedCircuitBreakerStore#addToRing/#evaluateThresholds/#deserialize` |
53
+ | `seedgrid.circuitbreaker.{name}.window-type` | `String` → `SlidingWindowType` | `count-based`, `time-based` (ou `COUNT_BASED`/`TIME_BASED`) — [[SeedGrid/Extensions/resilience/Enums#SlidingWindowType|SlidingWindowType]]; case-insensitive, `-`→`_` | atributo `windowType` (`COUNT_BASED`) | Não | Janela por contagem ou por tempo | Escolher semântica da janela | `sliding-window-size` | Runtime | `CircuitBreakerConfigResolver#resolve`; consumo `CacheBackedCircuitBreakerStore#evaluateThresholds` |
54
+ | `seedgrid.circuitbreaker.{name}.failure-rate-threshold` | `Double` | percentual (0–100; sem validação) | atributo `failureRateThreshold` (`50.0`) | Não | Abre quando `falhas*100/total >= valor` | Sensibilidade a falhas | `minimum-number-of-calls` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
55
+ | `seedgrid.circuitbreaker.{name}.slow-call-duration` | `java.time.Duration` | ISO-8601 (`PT2S`) | atributo `slowCallDurationThresholdMs` (`0` = desligado) | Não | Chamada com duração `>=` valor conta como lenta; `0` desativa a regra de lentidão | Detectar degradação | Necessária (>0) para `slow-call-rate-threshold` ter efeito | Runtime | `CircuitBreakerConfigResolver#resolve` (→ `slowCallDurationThresholdMs`); `CacheBackedCircuitBreakerStore#doRecord/#evaluateThresholds` |
56
+ | `seedgrid.circuitbreaker.{name}.slow-call-rate-threshold` | `Double` | percentual (0–100) | atributo `slowCallRateThreshold` (`100.0`) | Condicional (só tem efeito se `slow-call-duration` > 0) | Abre quando `lentas*100/total >= valor` | Abrir por lentidão | `slow-call-duration` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
57
+ | `seedgrid.circuitbreaker.{name}.minimum-number-of-calls` | `Integer` | inteiro `>= 0` | atributo `minimumNumberOfCalls` (`20`) | Não | Mínimo de chamadas na janela antes de avaliar thresholds | Evitar abrir com amostra pequena | Se > `sliding-window-size`, o circuito nunca abre (**Inferência**: `totalFilled` ≤ tamanho do buffer) | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
58
+ | `seedgrid.circuitbreaker.{name}.open-state-duration` | `java.time.Duration` | ISO-8601 (`PT30S`) | atributo `openStateDurationMs` (`30000` ms) | Não | Tempo em `OPEN` antes de ir a `HALF_OPEN`; base do `retryAfterMs`; TTL do estado = `max(2×valor, 1h)` | Tempo de recuperação | `permitted-calls-in-half-open` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#doAllowCall/#save` |
59
+ | `seedgrid.circuitbreaker.{name}.permitted-calls-in-half-open` | `Integer` | inteiro `> 0` | atributo `permittedCallsInHalfOpen` (`10`) | Não | Nº de sondas em `HALF_OPEN`; todas precisam ter sucesso para fechar | Recuperação gradual | `open-state-duration` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#doAllowCall/#doRecord` |
60
+
61
+ Atributos **somente na anotação**: `recordExceptions` (default `{Exception.class}`), `ignoreExceptions` (default `{}`), `fallbackMethod` (default `""`), `name`. **Confirmado** (Javadoc de `CircuitBreakerConfigResolver` e código).
62
+
63
+ Total de propriedades públicas da extension: **15** (6 rate limit + 9 circuit breaker), todas com segmento dinâmico.
64
+
65
+ ## 3. Propriedades de frameworks/bibliotecas
66
+
67
+ | Propriedade | Situação | Observação | Origem |
68
+ |---|---|---|---|
69
+ | `quarkus.redis.hosts` | Recomendada (quando usar `seedgrid-cache-redis`) | Conexão do Redis usado pelo provider de cache | `README.adoc` § "Configuração do Redis" |
70
+ | `quarkus.redis.password` 🔒 | Recomendada (se o Redis exigir) | Use `<SEGREDO:redis-password>` | `README.adoc` |
71
+ | `quarkus.redis.timeout` | Opcional | Exemplo no README: `PT5S` | `README.adoc` |
72
+ | `quarkus.redis.max-pool-size` | Opcional | Exemplo no README: `10` | `README.adoc` |
73
+
74
+ A extension não define nem exige nenhuma propriedade `quarkus.*`/`mp.*`/`smallrye.*` em código. A seleção/configuração do provider de cache (Redis/Valkey/Dragonfly) pertence à lib cache — ver [[SeedGrid/Extensions/cache/Configuracao|Configuração do cache]].
75
+
76
+ ## 4. Propriedades usadas só em testes
77
+
78
+ Nenhum `application.properties` com conteúdo (o de `integration-tests/src/main/resources` está vazio). Os testes unitários mockam `Config` com estas chaves (instâncias das propriedades da seção 2):
79
+
80
+ | Chave | Teste |
81
+ |---|---|
82
+ | `seedgrid.ratelimit.checkout.permits`, `.enabled`, `.window`, `.algorithm` (`token-bucket`), `.burst-capacity` | `runtime/src/test/.../RateLimitServiceConfigOverrideTest` |
83
+ | `seedgrid.circuitbreaker.payments.enabled`, `.sliding-window-size`, `.window-type` (`time-based`), `.failure-rate-threshold`, `.slow-call-duration`, `.slow-call-rate-threshold`, `.minimum-number-of-calls`, `.open-state-duration`, `.permitted-calls-in-half-open` | `runtime/src/test/.../CircuitBreakerConfigResolverTest` |
84
+
85
+ Os ITs (`RedisTestBase`) montam o Redis via Testcontainers programaticamente (sem properties).
86
+
87
+ ## 5. Aliases, obsoletas, renomeações
88
+
89
+ - `algorithm` e `window-type` aceitam tanto kebab-case quanto o nome do enum (normalização `trim().toUpperCase().replace('-', '_')`). **Confirmado**.
90
+ - `window`/`min-spacing`/`slow-call-duration`/`open-state-duration` substituem pares da anotação (`window`+`windowUnit`, `minSpacing`+`minSpacingUnit`, `slowCallDurationThresholdMs`, `openStateDurationMs`) — nomes diferentes entre anotação e property.
91
+ - Nenhuma propriedade obsoleta encontrada.
92
+
93
+ ## 6. Configuração mínima
94
+
95
+ Nenhuma property é obrigatória: as anotações já trazem os valores. Para estado compartilhado entre instâncias, adicione um provider de cache distribuído e sua conexão:
96
+
97
+ ```properties
98
+ # Provider seedgrid-cache-redis no classpath
99
+ quarkus.redis.hosts=redis://<host>:6379
100
+ quarkus.redis.password=<SEGREDO:redis-password>
101
+ ```
102
+
103
+ ## 7. Configuração completa comentada
104
+
105
+ ```properties
106
+ # ===== Rate limit: um bloco por configKey usado em @SeedGridRateLimit(configKey = "...") =====
107
+ # liga/desliga o limiter (padrão true)
108
+ seedgrid.ratelimit.<configKey>.enabled=true
109
+ # requisições por janela (> 0)
110
+ seedgrid.ratelimit.<configKey>.permits=<n>
111
+ # janela ISO-8601 (> 0), ex.: PT1M
112
+ seedgrid.ratelimit.<configKey>.window=<duration>
113
+ # fixed-window | sliding-window | token-bucket
114
+ seedgrid.ratelimit.<configKey>.algorithm=<algoritmo>
115
+ # capacidade do bucket (>= 0; 0 = usa permits) — só token-bucket
116
+ seedgrid.ratelimit.<configKey>.burst-capacity=<n>
117
+ # intervalo mínimo entre chamadas (ISO-8601) — ignorado em fixed-window
118
+ seedgrid.ratelimit.<configKey>.min-spacing=<duration>
119
+
120
+ # ===== Circuit breaker: um bloco por name usado em @SeedGridCircuitBreaker(name = "...") =====
121
+ # liga/desliga o circuito (padrão true)
122
+ seedgrid.circuitbreaker.<name>.enabled=true
123
+ # tamanho da janela (nº de chamadas; em time-based também = segundos)
124
+ seedgrid.circuitbreaker.<name>.sliding-window-size=<n>
125
+ # count-based | time-based
126
+ seedgrid.circuitbreaker.<name>.window-type=<tipo>
127
+ # % de falhas para abrir
128
+ seedgrid.circuitbreaker.<name>.failure-rate-threshold=<percentual>
129
+ # duração a partir da qual a chamada é lenta (ISO-8601); omitir/0 desliga
130
+ seedgrid.circuitbreaker.<name>.slow-call-duration=<duration>
131
+ # % de chamadas lentas para abrir (exige slow-call-duration > 0)
132
+ seedgrid.circuitbreaker.<name>.slow-call-rate-threshold=<percentual>
133
+ # mínimo de chamadas antes de avaliar
134
+ seedgrid.circuitbreaker.<name>.minimum-number-of-calls=<n>
135
+ # tempo aberto antes do half-open (ISO-8601)
136
+ seedgrid.circuitbreaker.<name>.open-state-duration=<duration>
137
+ # sondas no half-open
138
+ seedgrid.circuitbreaker.<name>.permitted-calls-in-half-open=<n>
139
+
140
+ # ===== Cache distribuído (lib seedgrid-cache-redis) =====
141
+ quarkus.redis.hosts=redis://<host>:6379
142
+ quarkus.redis.password=<SEGREDO:redis-password>
143
+ ```
144
+
145
+ ## 8. Receitas
146
+
147
+ **Desligar um limiter em produção** (método com `configKey = "forgot-password"`):
148
+ ```properties
149
+ seedgrid.ratelimit.forgot-password.enabled=false
150
+ ```
151
+
152
+ **Afrouxar o login temporariamente** (`configKey = "login"`):
153
+ ```properties
154
+ seedgrid.ratelimit.login.permits=200
155
+ seedgrid.ratelimit.login.window=PT30S
156
+ ```
157
+
158
+ **Trocar para token bucket com rajada e espaçamento** (`configKey = "export-create"`):
159
+ ```properties
160
+ seedgrid.ratelimit.export-create.algorithm=token-bucket
161
+ seedgrid.ratelimit.export-create.burst-capacity=3
162
+ seedgrid.ratelimit.export-create.min-spacing=PT1S
163
+ ```
164
+
165
+ **Circuito mais sensível, com detecção de lentidão** (`name = "payments"`):
166
+ ```properties
167
+ seedgrid.circuitbreaker.payments.failure-rate-threshold=25
168
+ seedgrid.circuitbreaker.payments.minimum-number-of-calls=5
169
+ seedgrid.circuitbreaker.payments.slow-call-duration=PT2S
170
+ seedgrid.circuitbreaker.payments.slow-call-rate-threshold=80
171
+ seedgrid.circuitbreaker.payments.open-state-duration=PT10S
172
+ ```
173
+
174
+ **Janela por tempo de 20 s**:
175
+ ```properties
176
+ seedgrid.circuitbreaker.payments.window-type=time-based
177
+ seedgrid.circuitbreaker.payments.sliding-window-size=20
178
+ ```
179
+
180
+ ## 9. Dúvidas e lacunas
181
+
182
+ - Formatos de `Duration` além de ISO-8601 (ex.: `30s`): dependem do conversor registrado no Quarkus; **não confirmado** nesta extension.
183
+ - Variáveis de ambiente: mapeamento descrito é **Inferência** (regra SmallRye), sem teste no repositório.
184
+ - Sem validação no boot: chaves com erro de digitação são silenciosamente ignoradas; valores inválidos (`algorithm`, `window-type`, `permits<=0`) só falham na chamada.
185
+ - `sliding-window-size` e `permitted-calls-in-half-open` não têm validação de positivo.
186
+ - Não há propriedade global (ex.: desligar todos os limiters ou escolher store) — apenas por `configKey`/`name`.
@@ -0,0 +1,96 @@
1
+ ---
2
+ tags: [seedgrid, extension, resilience, enum]
3
+ fonte: java/seedgrid-quarkus-ext-resilience
4
+ branch: main
5
+ commit: eff41304f8
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # SeedGrid Resilience — Enums
10
+
11
+ Todos os enums ficam em `runtime/src/main/java/br/com/seedgrid/resilience/core/runtime/`. Enums de teste não foram considerados. Visão geral: [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral]]; propriedades: [[SeedGrid/Extensions/resilience/Configuracao|Configuração]]; equivalentes Rust: [[SeedGrid/Extensions/resilience/Rust|Rust]].
12
+
13
+ ## Índice
14
+
15
+ | Enum | Pacote/arquivo | Usado em | Público? |
16
+ |---|---|---|---|
17
+ | [[#RateLimitAlgorithm]] | `ratelimiter.enums` | `@SeedGridRateLimit#algorithm`, propriedade `seedgrid.ratelimit.{configKey}.algorithm` | Sim |
18
+ | [[#KeyScope]] | `circuitbreaker.enums` (pacote do CB, mas só o rate limit usa) | `@SeedGridRateLimit#scope` | Sim |
19
+ | [[#SlidingWindowType]] | `circuitbreaker.enums` | `@SeedGridCircuitBreaker#windowType`, `CircuitBreakerConfig`, propriedade `seedgrid.circuitbreaker.{name}.window-type` | Sim |
20
+ | [[#CircuitState]] | `circuitbreaker.enums` | `CircuitDecision#state()` (retorno do SPI `CircuitBreakerStore#allowCall`), estado persistido no cache | Sim |
21
+
22
+ ## RateLimitAlgorithm
23
+
24
+ Arquivo: `ratelimiter/enums/RateLimitAlgorithm.java` — FQN `br.com.seedgrid.resilience.core.runtime.ratelimiter.enums.RateLimitAlgorithm`.
25
+
26
+ | Valor | Significado | Efeito / onde é tratado | Observações |
27
+ |---|---|---|---|
28
+ | `FIXED_WINDOW` | Janela fixa (default da anotação) | `RateLimitService#resolveStrategy` → `FixedWindowAlgorithm` | **Confirmado** |
29
+ | `TOKEN_BUCKET` | Balde de tokens | → `TokenBucketAlgorithm`; `burstCapacity` só tem efeito aqui | **Confirmado** |
30
+ | `SLIDING_WINDOW` | Janela deslizante | → `SlidingWindowAlgorithm` | **Confirmado** |
31
+
32
+ - Campos/métodos: nenhum (enum puro). `switch` exaustivo sem `default` em `resolveStrategy`.
33
+ - Serialização: não é persistido nem exposto em JSON. Na config é lido como `String` e convertido por `RateLimitAlgorithm.valueOf(v.trim().toUpperCase().replace('-', '_'))` — aceita `token-bucket`, `Token_Bucket` etc.; valor inválido lança `IllegalArgumentException` **na chamada** (não no boot). Só é lido quando a anotação tem `configKey`.
34
+ - Usado em: [[SeedGrid/Extensions/resilience/Configuracao|`seedgrid.ratelimit.{configKey}.algorithm`]]; anotação `@SeedGridRateLimit`.
35
+ - Todas as constantes são tratadas.
36
+
37
+ ## KeyScope
38
+
39
+ Arquivo: `circuitbreaker/enums/KeyScope.java` — FQN `br.com.seedgrid.resilience.core.runtime.circuitbreaker.enums.KeyScope`.
40
+
41
+ | Valor | Significado | Efeito / onde é tratado | Observações |
42
+ |---|---|---|---|
43
+ | `METHOD` | Limite por método (default) | `RateLimitService#buildKey`: `scopePart` = `methodSignature` (`Classe#metodo(tipos)`) | **Confirmado** |
44
+ | `CLASS` | Limite compartilhado por classe | `scopePart` = `invocation.getTarget().getClass().getName()` | **Confirmado**; é a classe do alvo (pode ser subclasse/proxy CDI — **Inferência**) |
45
+ | `GROUP` | Limite compartilhado por grupo lógico | `scopePart` = `ann.group()`; se vazio/blank cai em `methodSignature` | **Confirmado** |
46
+
47
+ - Campos/métodos: nenhum.
48
+ - Serialização: não é lido da config (só atributo da anotação); entra apenas na chave de cache `rl:{tenant}[:{operation}]:{scopePart}:{identity}`.
49
+ - Observação: o enum vive no pacote `circuitbreaker.enums`, mas o circuit breaker não o usa.
50
+
51
+ ## SlidingWindowType
52
+
53
+ Arquivo: `circuitbreaker/enums/SlidingWindowType.java` — FQN `br.com.seedgrid.resilience.core.runtime.circuitbreaker.enums.SlidingWindowType`.
54
+
55
+ | Valor | Significado | Efeito / onde é tratado | Observações |
56
+ |---|---|---|---|
57
+ | `COUNT_BASED` | Janela por contagem (default) | `CacheBackedCircuitBreakerStore#evaluateThresholds`: sem corte temporal (`windowStart = Long.MIN_VALUE`) | **Confirmado** |
58
+ | `TIME_BASED` | Janela por tempo | `windowStart = now - slidingWindowSize*1000`; `slidingWindowSize` vira **segundos**; entradas com timestamp `<= windowStart` são ignoradas | **Confirmado** |
59
+
60
+ - Campos/métodos: nenhum. O código só compara com `TIME_BASED`; qualquer outro valor se comportaria como `COUNT_BASED`.
61
+ - Serialização: não é persistido no estado do cache. Na config: `String` → `valueOf(v.trim().toUpperCase().replace('-', '_'))`; inválido → `IllegalArgumentException` na chamada. Só é lido quando a anotação tem `name` preenchido (`CircuitBreakerConfigResolver#resolve`).
62
+ - Usado em: [[SeedGrid/Extensions/resilience/Configuracao|`seedgrid.circuitbreaker.{name}.window-type`]]; `@SeedGridCircuitBreaker#windowType`; `CircuitBreakerConfig`.
63
+
64
+ ## CircuitState
65
+
66
+ Arquivo: `circuitbreaker/enums/CircuitState.java` — FQN `br.com.seedgrid.resilience.core.runtime.circuitbreaker.enums.CircuitState`.
67
+
68
+ | Valor | Significado | Efeito / onde é tratado | Observações |
69
+ |---|---|---|---|
70
+ | `CLOSED` (ordinal 0) | Chamadas passam; métricas gravadas | `doAllowCall` permite; `doRecord` grava no ring e avalia limiares | Estado inicial e fallback de ordinal inválido. **Confirmado** |
71
+ | `OPEN` (ordinal 1) | Chamadas negadas | `doAllowCall`: se `elapsed >= openStateDurationMs` → `HALF_OPEN`, senão `deny(restante)`; `doRecord` ignora resultados | **Confirmado** |
72
+ | `HALF_OPEN` (ordinal 2) | Sondagem com até `permittedCallsInHalfOpen` chamadas | permite até o limite, depois `deny(0)`; falha → `OPEN`; `permittedCallsInHalfOpen` sucessos → `CLOSED` (zera o ring) | **Confirmado** |
73
+
74
+ - Campos/métodos: nenhum.
75
+ - Persistência: **por ordinal** — `circuitState.ordinal()` (int de 4 bytes) no blob binário do cache (`serialize`/`deserialize`); ordinal fora de 0..2 → `CLOSED`. **Reordenar ou inserir constantes quebra estados já gravados e a compatibilidade com o Rust** (ver [[SeedGrid/Extensions/resilience/Rust|Rust]]). Sem JSON, sem tabela SQL/CHECK.
76
+ - Exposição: `CircuitDecision#state()` retorna `CLOSED`/`HALF_OPEN` em `allow` e sempre `OPEN` em `deny`; nenhum código do módulo lê `state()` (o interceptor usa só `allowed()` e `retryAfterMs()`).
77
+
78
+ ```mermaid
79
+ stateDiagram-v2
80
+ [*] --> CLOSED
81
+ CLOSED --> OPEN: limiar de falha/lentidão
82
+ OPEN --> HALF_OPEN: openStateDuration expirou (próxima chamada)
83
+ HALF_OPEN --> OPEN: qualquer falha
84
+ HALF_OPEN --> CLOSED: permittedCallsInHalfOpen sucessos
85
+ ```
86
+
87
+ A transição `CLOSED → OPEN` está em `CacheBackedCircuitBreakerStore` (`s.circuitState = CircuitState.OPEN` após `evaluateThresholds`).
88
+
89
+ ## Internos
90
+
91
+ Nenhum enum interno em `src/main`; os 4 acima são públicos. Enum do JDK no contrato: `java.time.temporal.ChronoUnit` em `@SeedGridRateLimit#windowUnit` (default `SECONDS`) e `#minSpacingUnit` (default `MILLIS`).
92
+
93
+ ## Notas Rust
94
+
95
+ - Grafia em PascalCase (`Closed`, `HalfOpen`, `CountBased`…); valor de string inválido causa `panic!`.
96
+ - `TimeUnit` aceita só `Millis`, `Seconds`, `Minutes`, `Hours`.