@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,141 @@
1
+ ---
2
+ tags: [seedgrid, library, commons, exemplos]
3
+ fonte: java/seedgrid-quarkus-lib-commons
4
+ branch: main
5
+ commit: fa49c344db
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # SeedGrid Commons — Exemplos
10
+
11
+ Voltar: [[SeedGrid/Extensions/commons/Visao-geral|Visão geral do commons]] · [[SeedGrid/Extensions/commons/Configuracao|Configuração do commons]]
12
+
13
+ Não há projeto em `java/examples` para o commons; os exemplos abaixo seguem o `README.md` e as assinaturas reais do código.
14
+
15
+ ## Dependência
16
+
17
+ ```xml
18
+ <dependency>
19
+ <groupId>br.com.seedgrid</groupId>
20
+ <artifactId>seedgrid-commons</artifactId>
21
+ <version>2026.10.08</version>
22
+ </dependency>
23
+ ```
24
+
25
+ ## Entidade base com auditoria de usuário
26
+
27
+ ```java
28
+ @Entity
29
+ public class Product extends BaseEntity {
30
+ private String name;
31
+ }
32
+ // @PrePersist gera publicId (UUIDv7) e garante active=true;
33
+ // createdAt/updatedAt (Instant) via @CreationTimestamp/@UpdateTimestamp;
34
+ // createUserPublicId/updateUserPublicId preenchidos pelo BaseEntityAuditListener.
35
+ ```
36
+
37
+ Fornecendo o usuário corrente (substitui o `DefaultCurrentUserProvider`, que é `@DefaultBean`):
38
+
39
+ ```java
40
+ @ApplicationScoped
41
+ public class MyCurrentUserProvider implements CurrentUserProvider {
42
+ @Override public String getCurrentUserPublicId() { return /* publicId do usuário autenticado */ null; }
43
+ @Override public String getCurrentUserEmail() { return null; }
44
+ @Override public String getCurrentUserName() { return null; }
45
+ @Override public String getCurrentUserWhatsapp() { return null; }
46
+ }
47
+ ```
48
+
49
+ ## Validadores
50
+
51
+ ```java
52
+ public class SignupRequest {
53
+ @ValidName(quantidadePalavras = 2) // atributo obrigatório (sem default)
54
+ String fullName;
55
+
56
+ @ValidEmail // bloqueia domínios descartáveis só em prod
57
+ String email;
58
+
59
+ @ValidPhone
60
+ String phone;
61
+
62
+ @ValidBirthDate(minAge = 18)
63
+ LocalDate birthDate;
64
+
65
+ // Defaults reais: minSize=8 e TODAS as regras true
66
+ @ValidPassword(prohibitsRepeatedCharactersInSequence = false)
67
+ String password;
68
+ }
69
+ ```
70
+
71
+ ## Exceções de negócio → Problem Details
72
+
73
+ ```java
74
+ throw new BusinessException("Nao foi possivel concluir", "detalhe tecnico para devMessage");
75
+ // -> 400, type https://seedgrid.com.br/erro-negocio, application/problem+json
76
+ ```
77
+
78
+ `EntityNotFoundException`/`EntityInUseException` também resultam em **400** (estendem `BusinessException`). Para outro status, use `ApiExceptionExtension`:
79
+
80
+ ```java
81
+ @ApplicationScoped
82
+ public class MyCustomExceptionExtension implements ApiExceptionExtension {
83
+ @Override
84
+ public Response tryHandle(Throwable ex) {
85
+ // atenção: BusinessException e subclasses são tratadas ANTES das extensions,
86
+ // então este ponto só recebe exceções que o handler não reconhece.
87
+ if (ex instanceof MyCustomException) {
88
+ return Response.status(422)
89
+ .entity(ProblemDetails.builder()
90
+ .type(ProblemType.MENSAGEM_INCOMPREENSIVEL.getUri())
91
+ .title("Unprocessable Entity")
92
+ .status(422)
93
+ .detail("Revise os dados enviados e tente novamente.")
94
+ .devMessage(ex.getMessage())
95
+ .instance("")
96
+ .build())
97
+ .type("application/problem+json")
98
+ .build();
99
+ }
100
+ return null;
101
+ }
102
+ }
103
+ ```
104
+
105
+ Fonte: `README.md` (exemplo de extensão) + ordem de tratamento em `ApiExceptionHandler#toResponse`.
106
+
107
+ ## Fuso de negócio
108
+
109
+ ```java
110
+ @Inject BusinessTimeZone businessTimeZone;
111
+
112
+ LocalDate dataDeNegocio = instante.atZone(businessTimeZone.zoneId()).toLocalDate();
113
+ ```
114
+
115
+ ## Evento para o usuário (`SgUserEvent`)
116
+
117
+ ```java
118
+ @Inject Event<SgUserEvent> userEvents;
119
+
120
+ @Transactional
121
+ public void finish(Export export) {
122
+ // ... grava o resultado
123
+ userEvents.fire(new SgUserEvent(userPublicId, "backup", "backup.finished.success",
124
+ Map.of("exportPublicId", export.getPublicId())));
125
+ }
126
+
127
+ // Quem escuta (ex.: realtime) usa:
128
+ void on(@Observes(during = TransactionPhase.AFTER_SUCCESS) SgUserEvent e) { /* ... */ }
129
+ ```
130
+
131
+ Fonte: Javadoc de `SgUserEvent` (dispare dentro da transação; `data` só com identificadores).
132
+
133
+ ## Configuração típica
134
+
135
+ ```properties
136
+ seedgrid.web.cors.allow-origins=https://<app.seudominio>
137
+ seedgrid.show-dev-message=false
138
+ app.build.version=${APP_VERSION:dev}
139
+ ```
140
+
141
+ Ver [[SeedGrid/Extensions/commons/Configuracao|Configuração do commons]].
@@ -0,0 +1,99 @@
1
+ ---
2
+ tags: [seedgrid, library, commons]
3
+ fonte: java/seedgrid-quarkus-lib-commons
4
+ branch: main
5
+ commit: fa49c344db
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # SeedGrid Commons — Visão geral
10
+
11
+ > [!info] Library, não extension Quarkus
12
+ > `seedgrid-quarkus-lib-commons` é uma **library Java** (um único jar com índice Jandex), **não** uma extension Quarkus com `runtime`/`deployment`. Não há `@ConfigRoot`, build steps nem processors. Documentada nesta estrutura por uniformidade. Não existe porte Rust desta lib.
13
+
14
+ Configuração: [[SeedGrid/Extensions/commons/Configuracao|Configuração do commons]] · Enums: [[SeedGrid/Extensions/commons/Enums|Enums do commons]] · Exemplos: [[SeedGrid/Extensions/commons/Exemplos|Exemplos do commons]]
15
+
16
+ ## Objetivo
17
+
18
+ Biblioteca compartilhada pelo ecossistema SeedGrid com utilitários, validadores Bean Validation, entidades JPA base com auditoria de usuário, SPIs de tenant/usuário/contato, evento CDI de aviso ao usuário, filtro CORS e mapeamento global de exceções em Problem Details (`application/problem+json`). **Confirmado** (`README.md`, código).
19
+
20
+ ## Coordenadas e dependências
21
+
22
+ | Item | Valor |
23
+ |---|---|
24
+ | groupId:artifactId | `br.com.seedgrid:seedgrid-commons` |
25
+ | Versão (pom) | `2026.10.08` |
26
+ | Parent | `br.com.seedgrid:seedgrid-parent:2026.07.02`; importa `quarkus-bom` 3.30.8 |
27
+ | Packaging | `jar` (com `jandex-maven-plugin`) |
28
+ | Dependências Quarkus | `quarkus-arc`, `quarkus-hibernate-orm`, `quarkus-hibernate-orm-panache`, `quarkus-hibernate-validator`, `quarkus-rest-jackson` (**optional**) |
29
+ | Dependência SeedGrid | `br.com.seedgrid:seedgrid-privacy:2026.07.27` — ver [[SeedGrid/Extensions/privacy/Visao-geral|Visão geral do privacy]] |
30
+ | Outras | Lombok (provided) |
31
+
32
+ Fonte: `java/seedgrid-quarkus-lib-commons/pom.xml`. **Confirmado.**
33
+
34
+ ## Componentes e APIs públicas
35
+
36
+ ### Core (`br.com.seedgrid.commons.core`)
37
+
38
+ | Símbolo | Tipo | Resumo |
39
+ |---|---|---|
40
+ | `time.BusinessTimeZone` | bean `@ApplicationScoped` | `zoneId()`; lê `seedgrid.app.business-timezone` (padrão `America/Sao_Paulo`) |
41
+ | `startup.StartupBannerLogger` | bean `@ApplicationScoped`, observa `StartupEvent` | imprime `banner.txt` (do classpath do host) e `app.build.version` em `System.out` |
42
+ | `utils.UUIDv7` | utilitário | `UUID generate()` (time-ordered) |
43
+ | `utils.HashUtils` | utilitário | `sha256Hex(String)` |
44
+ | `utils.JsonAttributeLimits` / `JsonAttributeLimitsSpec` | utilitário + record | `findViolation(Map<String, JsonNode>, spec)` — limites de tamanho (bytes), profundidade e nº de chaves |
45
+ | `utils.JsonAttributeMerger` | utilitário | `merge(target, patch)`, `copyWithoutNulls(source)` |
46
+ | `enums.StateEnum` | enum | UFs com `sigla`, `nome`, `regiao`, `ibge`; `fromSigla`, `fromNome`, `fromJson` |
47
+ | `exceptions.BusinessException` | `RuntimeException` | `userMessage` + `devMessage` |
48
+ | `exceptions.EntityNotFoundException`, `EntityInUseException` | estendem `BusinessException` | — |
49
+ | `exceptions.ThrowableUtils` | utilitário | `hasException(Throwable, Class)` |
50
+ | `pagination.PageReq` (record), `PageResult<T>` | DTOs | paginação simples |
51
+ | `validators.@ValidBirthDate(minAge, maxAge)` | Bean Validation | `-1` desabilita cada limite |
52
+ | `validators.@ValidName(quantidadePalavras)` | Bean Validation | `quantidadePalavras` **sem default** (obrigatório na anotação) |
53
+ | `validators.@ValidPassword(...)` | Bean Validation | defaults no código: `minSize=8` e **todas** as regras `true` (`upper/lower/number/specialCharacterRequired`, `prohibitsRepeatedCharactersInSequence`) |
54
+ | `validators.@ValidEmail` | Bean Validation | regex + bloqueio de domínios descartáveis em produção (ver config) |
55
+ | `validators.@ValidPhone` | Bean Validation | aceita só dígitos ou formato mascarado |
56
+
57
+ ### Persistência (`br.com.seedgrid.commons.persistence`)
58
+
59
+ | Símbolo | Resumo |
60
+ |---|---|
61
+ | `BaseEntity` (`@MappedSuperclass`) | `id` (IDENTITY), `publicId` (UUIDv7 no `@PrePersist`), `active`, `createdAt`/`updatedAt` (`Instant` → `timestamptz`), `createUserPublicId`, `updateUserPublicId`; `@EntityListeners(BaseEntityAuditListener)` |
62
+ | `BaseEntityPanache` | idem estendendo `PanacheEntityBase` (sem `active`) |
63
+ | `BaseEntityAuditListener` / `BaseEntityPanacheAuditListener` | preenchem `create/updateUserPublicId` via `CurrentUserProvider`; em erro (sem contexto) gravam `null` |
64
+ | `spi.CurrentUserProvider` + `spi.impl.DefaultCurrentUserProvider` (`@DefaultBean`) | default devolve publicId zero (`00000000-...`), e-mail/nome placeholders |
65
+ | `embeddables.Address`, `embeddables.Contact` (`@Embeddable`) | campos com `@PersonalData` e, em `phone`/`cpf`/`whatsapp`/`email`, `@EncryptedField` + `@Convert(EncryptedFieldAttributeConverter)` com campo `*Hash` irmão (lib privacy) |
66
+ | `SchemaUtils.schemaReady(EntityManager, historyTable)` | verifica se a última migração Flyway registrada teve sucesso (`to_regclass('public.<tabela>')`) |
67
+
68
+ Colunas usadas por `BaseEntity`: `public_id`, `active`, `created_at`, `updated_at`, `create_user_public_id`, `update_user_public_id`. A lib **não** traz migrations; cada host/extension cria as colunas. **Confirmado.**
69
+
70
+ ### SPIs gerais (`br.com.seedgrid.commons.spi`) e eventos
71
+
72
+ | Símbolo | Resumo |
73
+ |---|---|
74
+ | `TenantProvider` + `SingleTenantProvider` (`@DefaultBean`) | default single-tenant: tenant `"default"`, set/clear no-op |
75
+ | `UserContactProvider` (+ record `UserContact`) + `DefaultUserContactProvider` (`@DefaultBean`) | default devolve `UserContact.empty()` |
76
+ | `events.SgUserEvent(userPublicId, channel, event, data)` | evento CDI neutro "algo aconteceu para um usuário" (consumido p.ex. pela extension realtime — ver [[SeedGrid/Extensions/realtime/Visao-geral|Visão geral do realtime]]) |
77
+
78
+ ### Web (`br.com.seedgrid.commons.web`)
79
+
80
+ | Símbolo | Resumo |
81
+ |---|---|
82
+ | `cors.CorsFilter` (`@Provider @PreMatching`, prioridade `AUTHENTICATION - 100`) + `cors.CorsConfig` | responde preflight `OPTIONS` (200 com headers, ou 403 para origem não permitida); origem `"null"` → 403; adiciona `Access-Control-*` nas respostas para origens permitidas; `Allow-Credentials: true`, `Allow-Headers: Accept,Authorization,Content-Type,X-Requested-With`, `Expose-Headers: Location,Link`, `Max-Age: 0` |
83
+ | `exceptions.ApiExceptionHandler` (`ExceptionMapper<Throwable>`) | Problem Details: `NotFoundException`→404; `WebApplicationException`→status da exceção; `ConstraintViolationException`→400 com `violations[]`; `BusinessException` (inclui `EntityNotFoundException`/`EntityInUseException`)→**400** `ERRO_NEGOCIO`; senão tenta `ApiExceptionExtension`s; fallback 500 |
84
+ | `exceptions.ConstraintViolationExceptionMapper` (`@Priority(1)`) | sobrepõe o mapper built-in do Quarkus e delega ao handler |
85
+ | `exceptions.spi.ApiExceptionExtension` + `DefaultApiExceptionExtension` | ponto de extensão (`tryHandle` devolve `Response` ou `null`) |
86
+ | `exceptions.ProblemType` | URIs `https://seedgrid.com.br/<path>` |
87
+
88
+ Não há endpoints REST próprios.
89
+
90
+ ## Testes existentes (não executados)
91
+
92
+ `src/test/java/...`: `StateEnumTest`, `BusinessTimeZoneTest`, `HashUtilsTest`, `JsonAttributeLimitsTest`, `JsonAttributeMergerTest`, `UUIDv7Test`, `Valid{BirthDate,Email,Name,Password,Phone}ValidatorTest`, `CorsConfigTest`, `CorsFilterTest`, `ApiExceptionHandlerTest` — todos unitários (nenhum `@QuarkusTest`; ~115 anotações `@Test` por grep). **Não executados.**
93
+
94
+ ## Limitações
95
+
96
+ - `EntityNotFoundException` e `EntityInUseException` resultam em **400** (caem no ramo `BusinessException`); para 404/409 é preciso lançar `WebApplicationException`/`NotFoundException`. **Confirmado** (`ApiExceptionHandler#toResponse`).
97
+ - `@ValidBirthDate` tem mensagem default `{br.com.seedgrid.subdomaintenancy.validation.BirthDateIsValid.message}` — chave de bundle de outra extension; não há `ValidationMessages.properties` nesta lib. **Confirmado** (busca de resources vazia).
98
+ - `Address`/`Contact` dependem do modo de criptografia da lib privacy (`seedgrid.privacy.*`) — ver [[SeedGrid/Extensions/privacy/Configuracao|Configuração do privacy]].
99
+ - `CorsFilter` é próprio e convive com o CORS nativo do Quarkus (`quarkus.http.cors.*`); interação não documentada — **Não confirmado**.
@@ -0,0 +1,122 @@
1
+ ---
2
+ tags: [seedgrid, extension, exchange, quarkus, configuracao]
3
+ fonte: java/seedgrid-quarkus-ext-exchange
4
+ branch: main
5
+ commit: 30f1fd6005
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Exchange (Quarkus): configuração
10
+
11
+ Voltar para [[SeedGrid/Extensions/exchange/Visao-geral|Visão geral do exchange]] · [[SeedGrid/Extensions/exchange/Exemplos|Exemplos]]
12
+
13
+ ## 1. Cabeçalho
14
+
15
+ | Item | Valor |
16
+ |---|---|
17
+ | Prefixos | `seedgrid.exchange.*` e `seedgrid.app.business-timezone` (chave compartilhada) |
18
+ | Mecanismo | só `@ConfigProperty`. Não há `@ConfigMapping`, `@ConfigRoot` nem `microprofile-config.properties` no runtime. |
19
+ | Classes | `ExchangeEntityManager`, `ExchangeTimeZone` |
20
+ | Fase | runtime |
21
+ | Configuração em banco | tabela `currencies`, uma linha por moeda. Fonte, cron, fuso, retry e caminhos JSON são **cadastro**, não propriedades (seção 2.2). |
22
+
23
+ Abreviação usada na coluna Origem: `rt/` = `java/seedgrid-quarkus-ext-exchange/runtime/src/main/java/br/com/seedgrid/exchange/`.
24
+
25
+ Variáveis de ambiente pela regra MP, sem ambiguidade:
26
+ - `seedgrid.exchange.persistence-unit` → `SEEDGRID_EXCHANGE_PERSISTENCE_UNIT`
27
+ - `seedgrid.app.business-timezone` → `SEEDGRID_APP_BUSINESS_TIMEZONE`
28
+
29
+ ## 2. Propriedades
30
+
31
+ ### 2.1 Propriedades lidas pela extension
32
+
33
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
34
+ |---|---|---|---|---|---|---|---|---|---|
35
+ | `seedgrid.exchange.persistence-unit` | Optional\<String\> | nome de PU; vazio ou `<default>` = PU default | — (PU default) | Não | Escolhe o `EntityManager` das tabelas `currencies` e `currency_exchange_rates`. | `ExchangeEntityManager` → `CurrencyEntityRepository`, `CurrencyExchangeRateEntityRepository` | O subdomain-tenancy define `master` (**Confirmado** no microprofile-config dele). As entidades `br.com.seedgrid.exchange.entities` devem estar mapeadas nessa PU. | runtime | `rt/repositories/ExchangeEntityManager.java` (construtor) |
36
+ | `seedgrid.app.business-timezone` | String (ZoneId) | `ZoneId` válido | `America/Sao_Paulo` | Não | Fuso usado para **apresentar** o horário do próximo retry nos avisos (`exchange.rate-fetch-failed`). Valor vazio ou inválido cai silenciosamente em `America/Sao_Paulo`, sem log. **Não** afeta o cron das moedas, que usa `currencies.time_zone`. | `ExchangeTimeZone#zoneId` → `CurrencyRateFetchService` | **Chave compartilhada**: declarada também em `seedgrid-quarkus-lib-commons` (`commons/core/time/BusinessTimeZone`). Ver [[SeedGrid/Extensions/commons/Configuracao|Configuração do commons]]. | runtime | `rt/config/ExchangeTimeZone.java` (construtor) |
37
+
38
+ ### 2.2 Configuração em banco (`currencies`, por moeda)
39
+
40
+ | Coluna | Default (entidade/DDL) | Efeito |
41
+ |---|---|---|
42
+ | `code` | — (único, ex.: `USD-BRL`) | Identifica a moeda. O job se chama `currency-rate-<code>`. |
43
+ | `source_url` | — (obrigatória) | URL da cotação do dia. Aceita `{date:FMT}` e `{date-Nd:FMT}`. |
44
+ | `fetch_cron` | — (obrigatória) | Cron Quartz do job da moeda. Se for inválido, o admin recebe erro ao salvar. |
45
+ | `time_zone` | `America/Sao_Paulo` | Fuso do cron e dos marcadores de data. |
46
+ | `retry_offsets_hours` | `4,5,3` | Horas entre tentativas após falha. Vazio desliga o retry. Entradas inválidas são ignoradas. |
47
+ | `rate_json_path` | — | Caminho do valor (ex.: `value[0].cotacaoVenda`). Vazio usa a convenção AwesomeAPI (`bid`). |
48
+ | `quoted_at_json_path` | — | Caminho da data/hora da cotação. |
49
+ | `history_url` | — | URL da série histórica (`{rangeStart:FMT}`, `{date:FMT}`). Vazio faz o gráfico usar só as coletas diárias. |
50
+ | `active` | `true` | Moeda inativa não é agendada nem buscada. |
51
+
52
+ Origem: `rt/entities/CurrencyEntity.java`, `rt/dtos/CurrencyUpsertRequest.java`, `runtime/src/main/resources/db/migration/exchange/V802__seed_currencies.sql`. A seed V802 cria `USD-BRL` com a fonte PTAX/BCB, `cotacaoVenda`, cron às 7h e fuso `America/Sao_Paulo`.
53
+
54
+ ### 2.3 Propriedades de outras extensions que governam o exchange
55
+
56
+ | Propriedade | Dona | Padrão | Efeito |
57
+ |---|---|---|---|
58
+ | `seedgrid.exchange.migration.enabled` | login-tenancy (`LoginTenancyMigrationService`) e subdomain-tenancy (`flyway/MigrationService`) | `false` | Aplica `classpath:db/migration/exchange` com a tabela `flyway_schema_history_exchange`. Não é lida pela extension. |
59
+
60
+ ## 3. Propriedades de frameworks
61
+
62
+ A extension não define nenhuma. Recomendações extraídas do `integration-tests` e do README:
63
+
64
+ | Propriedade | Recomendação |
65
+ |---|---|
66
+ | `quarkus.flyway.locations` / `quarkus.flyway.table` | `db/migration/exchange` / `flyway_schema_history_exchange` (Flyway nativo). Nos tenancies, use `seedgrid.exchange.migration.enabled`. |
67
+ | `quarkus.hibernate-orm.physical-naming-strategy` | `org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy` |
68
+ | `quarkus.hibernate-orm.<pu>.packages` | Incluir `br.com.seedgrid.exchange.entities` na PU configurada (no subdomain-tenancy, só master). |
69
+ | `quarkus.scheduler.enabled` | Os testes usam `false` para controlar os disparos. Em produção, deixe ligado. |
70
+
71
+ ## 4. Propriedades usadas só em testes
72
+
73
+ Arquivo `integration-tests/src/test/resources/application.properties`:
74
+ - `quarkus.devservices.enabled=false`
75
+ - `quarkus.flyway.migrate-at-start=true`
76
+ - `quarkus.flyway.locations=db/migration/exchange,db/migration/exchange-test`
77
+ - `quarkus.flyway.table=flyway_schema_history_exchange`
78
+ - `quarkus.flyway.baseline-on-migrate=true`
79
+ - naming strategy
80
+ - `quarkus.hibernate-orm.schema-management.strategy=none`
81
+ - `quarkus.scheduler.enabled=false`
82
+ - `quarkus.http.test-port=0`
83
+ - `app.build.version=test`: exigido pelo `StartupBannerLogger` do commons. No host, o valor vem do build.
84
+
85
+ ## 5. Aliases, obsoletas e renomeações
86
+ Não encontradas. Atenção: `seedgrid.app.business-timezone` é diferente de `seedgrid.billing.business-timezone` (ver [[SeedGrid/Extensions/billing/Configuracao|Configuração do billing]]).
87
+
88
+ ## 6. Configuração mínima
89
+ Nenhuma propriedade é obrigatória. Nos tenancies:
90
+
91
+ ```properties
92
+ seedgrid.exchange.migration.enabled=true
93
+ ```
94
+
95
+ ## 7. Configuração completa comentada
96
+
97
+ ```properties
98
+ # PU das tabelas de câmbio. Sem valor ou <default> = PU default. subdomain-tenancy: master.
99
+ #seedgrid.exchange.persistence-unit=master
100
+
101
+ # Fuso de exibição do horário do próximo retry nos avisos (compartilhado com o commons).
102
+ # Default America/Sao_Paulo.
103
+ seedgrid.app.business-timezone=America/Sao_Paulo
104
+
105
+ # (tenancies) aplicar V800-V804. Default false.
106
+ seedgrid.exchange.migration.enabled=true
107
+ ```
108
+
109
+ ## 8. Receitas
110
+
111
+ | Caso | Como |
112
+ |---|---|
113
+ | Produto sem câmbio | Não aplicar a faixa 8xx. A app sobe com WARN "Módulo de câmbio inativo". |
114
+ | Trocar a fonte de cotação | `PUT /admin/currencies/{id}` com novos `sourceUrl` e `rateJsonPath`. Reagenda sem deploy. |
115
+ | Mudar a grade de retry | `retryOffsetsHours: "2,2,4"`. Com `""`, o retry automático fica desligado. |
116
+ | Corrigir a cotação de um dia | `PUT /admin/currency-exchange-rates/{id}` com `{ "rate": 5.4321 }`, ou `POST .../{id}/retry`. |
117
+ | subdomain-tenancy | `seedgrid.exchange.persistence-unit=master` (já definido pela extension de tenancy). |
118
+
119
+ ## 9. Dúvidas e lacunas
120
+ - O intervalo do drain (`every = "10m"`) e os timeouts HTTP (10s/15s) estão fixos em código.
121
+ - `history_url` não faz parte de `CurrencyUpsertRequest`: só a seed ou SQL direto definem esse valor.
122
+ - `ExchangeTimeZone` engole o fuso inválido sem log, ao contrário do `BusinessTimeZone` do billing, que registra WARN.
@@ -0,0 +1,29 @@
1
+ ---
2
+ tags: [seedgrid, extension, exchange, quarkus, enum]
3
+ fonte: java/seedgrid-quarkus-ext-exchange
4
+ branch: main
5
+ commit: 30f1fd6005
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Exchange (Quarkus): enums
10
+
11
+ Voltar para [[SeedGrid/Extensions/exchange/Visao-geral|Visão geral]] · [[SeedGrid/Extensions/exchange/Configuracao|Configuração]].
12
+
13
+ | Enum | Arquivo | Usado em | Público? |
14
+ |---|---|---|---|
15
+ | `CurrencyExchangeRateStatus` | `runtime/src/main/java/br/com/seedgrid/exchange/entities/CurrencyExchangeRateStatus.java` | coluna `currency_exchange_rates.status`; respostas de `/admin/currency-exchange-rates` | sim |
16
+
17
+ ## CurrencyExchangeRateStatus
18
+ FQN `br.com.seedgrid.exchange.entities.CurrencyExchangeRateStatus`. Sem campos nem métodos. Persistido com `@Enumerated(EnumType.STRING)` em `status varchar(16) not null` (V800), **sem CHECK constraint**. Não é tipo de propriedade de configuração. No JSON aparece pelo nome da constante (sem `@JsonValue`).
19
+
20
+ | Valor | Significado | Efeito / onde é tratado | Observações |
21
+ |---|---|---|---|
22
+ | `SUCCESS` | Cotação obtida da fonte. | `CurrencyRateFetchService` grava ao aplicar uma busca bem-sucedida. A importação de histórico (`insertImportedIfMissing`) também insere com `SUCCESS`. | Confirmado. |
23
+ | `FAILED` | Busca falhou. | Gravado em falha, com `errorMessage`, `attemptCount` incrementado e `next_retry_at` pela grade `retryOffsetsHours` da moeda. Elegível ao retry automático e manual. | Confirmado. |
24
+ | `MANUAL` | Valor digitado pelo admin. | `PUT /admin/currency-exchange-rates/{id}`. | Confirmado. |
25
+
26
+ A cotação "mais recente válida" (`latestGoodFor`, usada por `/admin/exchange-rate`) **não filtra por status**: seleciona a linha de maior `reference_date` com `rate` não nulo. Como `FAILED` não tem `rate`, fica de fora, e `MANUAL` conta. **Confirmado** em `CurrencyExchangeRateEntityRepository#latestGoodFor`.
27
+
28
+ ## Internos
29
+ Nenhum.
@@ -0,0 +1,82 @@
1
+ ---
2
+ tags: [seedgrid, extension, exchange, quarkus, exemplos]
3
+ fonte: java/seedgrid-quarkus-ext-exchange
4
+ branch: main
5
+ commit: 30f1fd6005
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Exchange (Quarkus): exemplos
10
+
11
+ Ver [[SeedGrid/Extensions/exchange/Visao-geral|Visão geral]] e [[SeedGrid/Extensions/exchange/Configuracao|Configuração]].
12
+
13
+ ## 1. Dependência
14
+
15
+ Fonte: README.
16
+
17
+ ```xml
18
+ <dependency>
19
+ <groupId>br.com.seedgrid</groupId>
20
+ <artifactId>seedgrid-exchange</artifactId>
21
+ <version>2026.10.14</version>
22
+ </dependency>
23
+ ```
24
+
25
+ Security e audit-core vêm do host. Nos tenancies, ligue também `seedgrid.exchange.migration.enabled=true`.
26
+
27
+ ## 2. Cadastrar uma moeda com fonte PTAX
28
+
29
+ Fontes: `CurrencyUpsertRequest` e seed `V802__seed_currencies.sql`. Requer `CURRENCY_CREATE`.
30
+
31
+ ```http
32
+ POST /admin/currencies
33
+ Content-Type: application/json
34
+
35
+ {
36
+ "code": "USD-BRL",
37
+ "name": "Dolar americano / Real",
38
+ "sourceUrl": "https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/odata/CotacaoDolarPeriodo(dataInicial=@dataInicial,dataFinalCotacao=@dataFinalCotacao)?@dataInicial='{date-10d:MM-dd-yyyy}'&@dataFinalCotacao='{date:MM-dd-yyyy}'&$format=json&$orderby=dataHoraCotacao%20desc&$top=1",
39
+ "fetchCron": "0 0 7 * * ?",
40
+ "timeZone": "America/Sao_Paulo",
41
+ "retryOffsetsHours": "4,5,3",
42
+ "rateJsonPath": "value[0].cotacaoVenda",
43
+ "quotedAtJsonPath": "value[0].dataHoraCotacao",
44
+ "active": true
45
+ }
46
+ ```
47
+
48
+ Os valores acima são os mesmos da seed V802. A seed também grava `history_url`, mas `CurrencyUpsertRequest` **não tem** esse campo: pela API REST não dá para definir `historyUrl`. **Confirmado** pela leitura do record.
49
+
50
+ - `code`, `name`, `sourceUrl` e `fetchCron` são obrigatórios (`@NotBlank`).
51
+ - No `PUT`, `retryOffsetsHours`, `rateJsonPath` e `quotedAtJsonPath` com `null` mantêm o valor gravado.
52
+
53
+ ## 3. Consultar cotações
54
+
55
+ Fonte: `AdminCurrencyExchangeRateResource`, `AdminExchangeRateResource`.
56
+
57
+ ```http
58
+ GET /admin/currency-exchange-rates?currencyCode=USD-BRL&from=2026-10-01&to=2026-10-14&page=0&size=30
59
+ GET /admin/currency-exchange-rates/series?currencyCode=USD-BRL&days=30
60
+ GET /admin/exchange-rate # { "rate": ..., "updatedAt": ..., "source": ... } (última USD-BRL válida)
61
+ ```
62
+
63
+ ## 4. Corrigir manualmente ou reprocessar
64
+
65
+ Fonte: `ManualRateRequest(@NotNull @Positive BigDecimal rate)`. Requer `CURRENCY_RATE_UPDATE`.
66
+
67
+ ```http
68
+ PUT /admin/currency-exchange-rates/{publicId}
69
+ Content-Type: application/json
70
+
71
+ { "rate": 5.4321 }
72
+
73
+ POST /admin/currency-exchange-rates/{publicId}/retry
74
+ ```
75
+
76
+ ## 5. Configuração (properties)
77
+
78
+ ```properties
79
+ seedgrid.exchange.migration.enabled=true # tenancies
80
+ #seedgrid.exchange.persistence-unit=master # subdomain-tenancy já define
81
+ seedgrid.app.business-timezone=America/Sao_Paulo # fuso dos avisos
82
+ ```
@@ -0,0 +1,118 @@
1
+ ---
2
+ tags: [seedgrid, extension, exchange, quarkus]
3
+ fonte: java/seedgrid-quarkus-ext-exchange
4
+ branch: main
5
+ commit: 30f1fd6005
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Exchange (Quarkus): visão geral
10
+
11
+ Câmbio para hosts Quarkus. Mantém moedas e cotações diárias, com histórico e série para gráfico. As fontes de cotação são configuráveis por cadastro (URL com marcadores de data e caminho JSON do valor). Há retry automático (grade de horas por moeda) e manual. A seed padrão é USD-BRL via PTAX do Banco Central. Não há crate Rust equivalente.
12
+
13
+ - Configuração: [[SeedGrid/Extensions/exchange/Configuracao|Configuração do exchange]]
14
+ - Exemplos: [[SeedGrid/Extensions/exchange/Exemplos|Exemplos do exchange]]
15
+ - Enums: [[SeedGrid/Extensions/exchange/Enums|Enums do exchange]]
16
+
17
+ ## Módulos e coordenadas
18
+
19
+ | Módulo | Artefato |
20
+ |---|---|
21
+ | parent | `br.com.seedgrid:seedgrid-exchange-parent:2026.10.14` (parent `seedgrid-parent:2026.07.02`) |
22
+ | runtime | `br.com.seedgrid:seedgrid-exchange` |
23
+ | deployment | `br.com.seedgrid:seedgrid-exchange-deployment` |
24
+ | integration-tests | não publicado |
25
+
26
+ A feature Quarkus é `seedgrid-exchange` (`SeedgridExchangeProcessor`). O processor registra services, scheduler, resources e `NoOpExchangeAuditSink` como *unremovable*.
27
+
28
+ > Usa Java 21 e Quarkus **3.30.6**: o `pom.xml` do módulo sobrescreve `quarkus.platform.version` (o `seedgrid-parent` usa 3.30.8). O `runtime/src/main/resources/META-INF/quarkus-extension.properties` declara `deployment-artifact=...:1.0.0-SNAPSHOT` como valor fixo. **Confirmado** nos arquivos.
29
+
30
+ ### Dependências
31
+ - SeedGrid: `seedgrid-commons` 2026.10.08, `seedgrid-security` 2026.10.09, `seedgrid-audit-core` 2026.09.25 e `seedgrid-notification-api`.
32
+ - Quarkus: `arc`, `rest-jackson`, `hibernate-orm` (JPA puro), `scheduler`, `security` e `hibernate-validator`.
33
+
34
+ ## Arquitetura
35
+
36
+ ```mermaid
37
+ flowchart LR
38
+ BOOT[StartupEvent] --> SCH[CurrencyRateScheduler]
39
+ SCH -->|1 job por moeda ativa: cron + fuso da linha| FETCH[CurrencyRateFetchService.fetchToday]
40
+ SCH -->|every 10m| DRAIN[drainPendingRetries]
41
+ DRAIN --> FETCH
42
+ FETCH -->|HttpClient, URL resolvida| SRC((fonte: PTAX/AwesomeAPI...))
43
+ FETCH --> DB[(currency_exchange_rates)]
44
+ FETCH -. exchange.rate-fetch-failed .-> NOTIF[notification-api]
45
+ ```
46
+
47
+ ### Scheduler
48
+
49
+ Componente: `CurrencyRateScheduler`.
50
+
51
+ - Cria **um job por moeda ativa** (`currency-rate-<code>`), com `fetch_cron` e `time_zone` da própria linha em `currencies`.
52
+ - No startup, para cada moeda ativa sem cotação do dia, dispara a busca na hora.
53
+ - Se a tabela não existir, registra WARN e sai sem derrubar o boot (`ModuloDesligadoTest`).
54
+ - `@Scheduled(every = "10m")` drena os retries vencidos. O estado do retry fica no banco (`next_retry_at`).
55
+ - Retry vencido de um dia anterior é descartado, nunca gravado com a cotação de hoje.
56
+ - Ao criar, editar, renomear ou excluir uma moeda, o job é reagendado sem restart.
57
+
58
+ ### Resolução da fonte
59
+
60
+ Componente: `CurrencySourceResolver`.
61
+
62
+ - Marcadores aceitos na URL: `{date:FMT}`, `{date-Nd:FMT}` e `{rangeStart:FMT}`.
63
+ - O caminho JSON do valor segue o formato `value[0].cotacaoVenda`.
64
+ - Com o caminho vazio, vale a convenção AwesomeAPI: campo `bid` do único objeto raiz.
65
+
66
+ ### Busca HTTP
67
+
68
+ Componente: `CurrencyRateFetchService`. Usa connect timeout de 10s e request de 15s.
69
+
70
+ ## APIs públicas
71
+
72
+ ### SPI
73
+ | SPI | Default | Assinatura |
74
+ |---|---|---|
75
+ | `ExchangeAuditSink` | `NoOpExchangeAuditSink` | `record(String actionType, String targetType, String targetId, String summary, Map<String,Object> details)`. O README o chama de legado: a auditoria é feita via `@Audit`. |
76
+
77
+ ### Endpoints REST (`RestControllerPath`)
78
+ Todos os resources são `@MonoCompany @Authenticated`.
79
+
80
+ | Método | Caminho | Permissão |
81
+ |---|---|---|
82
+ | GET | `/admin/currencies` | `CURRENCY_READ` |
83
+ | GET | `/admin/currencies/{id}` | `CURRENCY_READ` |
84
+ | POST | `/admin/currencies` | `CURRENCY_CREATE` |
85
+ | PUT | `/admin/currencies/{id}` | `CURRENCY_UPDATE` |
86
+ | DELETE | `/admin/currencies/{id}` | `CURRENCY_DELETE` |
87
+ | GET | `/admin/currency-exchange-rates?currencyCode&from&to&page=0&size=30` | `CURRENCY_RATE_READ` |
88
+ | GET | `/admin/currency-exchange-rates/series?currencyCode&days=30` | `CURRENCY_RATE_READ` |
89
+ | POST | `/admin/currency-exchange-rates/{id}/retry` | `CURRENCY_RATE_UPDATE` |
90
+ | PUT | `/admin/currency-exchange-rates/{id}` (`{rate}`, edição manual) | `CURRENCY_RATE_UPDATE` |
91
+ | GET | `/admin/exchange-rate` (última USD-BRL válida: `rate`, `updatedAt`, `source`) | só autenticado |
92
+
93
+ Os `{id}` são `publicId`. **Confirmado** nos resources.
94
+
95
+ ### Evento de notificação
96
+ `exchange.rate-fetch-failed` (`ExchangeNotificationCatalog`), publicado após o commit da tentativa. O evento inclui a variável `reason`, com o horário do próximo retry no fuso `seedgrid.app.business-timezone`.
97
+
98
+ ## Migrations
99
+ `db/migration/exchange`, de **V800 a V804**. Histórico em `flyway_schema_history_exchange`.
100
+
101
+ | Versão | Conteúdo |
102
+ |---|---|
103
+ | V800 | tabelas |
104
+ | V801 | permissões `CURRENCY_*`, audience `platform`, vinculadas a `ADMIN` |
105
+ | V802 | seed USD-BRL: PTAX, cron às 7h, São Paulo |
106
+ | V803 | histórico PTAX sem `$select` |
107
+ | V804 | `currency_exchange_rates.active` |
108
+
109
+ Nos tenancies, o runner só aplica essas migrations com `seedgrid.exchange.migration.enabled=true` (default `false`).
110
+
111
+ ## Testes (não executados)
112
+ - `runtime/src/test`: `CurrencyRateNotificationTest`, `CurrencySourceResolverTest` e `ExchangeNotificationCatalogTest`.
113
+ - `integration-tests`: `ExchangePermissionMigrationTest`, `ExchangeSchemaAndPersistenceTest`, `ModuloDesligadoTest`, `CurrencyRateSchedulerTest`, `CurrencyRateFetchServiceTest` e `CurrencyRateHistoryTest`. Usam a migration de teste `V899__test_remove_moeda_semeada`.
114
+
115
+ ## Limitações
116
+ - `/admin/exchange-rate` é um atalho fixo para `USD-BRL`.
117
+ - O drain de retry é fixo em 10 minutos, sem propriedade para mudar.
118
+ - O fuso padrão `America/Sao_Paulo` está repetido em código: em `ExchangeTimeZone`, como default do `applySchedule` e como default da coluna.