@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,113 @@
1
+ ---
2
+ tags: [seedgrid, extension, notification]
3
+ fonte: java/seedgrid-quarkus-ext-notification
4
+ branch: main
5
+ commit: b989a6248a
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Notification (Quarkus) — visão geral
10
+
11
+ Notificações administrativas da plataforma por **e-mail, WhatsApp ou ambos**, escolhidos por evento. Extensões produtoras declaram eventos (catálogo dinâmico) e os publicam por evento CDI síncrono; o motor grava uma **outbox transacional** e um worker agendado entrega com retry, lease e deduplicação. Não há crate Rust equivalente.
12
+
13
+ - Configuração: [[SeedGrid/Extensions/notification/Configuracao|Configuração do notification]]
14
+ - Exemplos: [[SeedGrid/Extensions/notification/Exemplos|Exemplos do notification]]
15
+ - Enums: [[SeedGrid/Extensions/notification/Enums|Enums do notification]]
16
+
17
+ ## Módulos Maven e coordenadas (Confirmado — `pom.xml`)
18
+
19
+ | Módulo | groupId | artifactId | Versão | Papel |
20
+ |---|---|---|---|---|
21
+ | parent | `br.com.seedgrid` | `seedgrid-notification-parent` | `2026.10.15` | — |
22
+ | `api` | `br.com.seedgrid` | `seedgrid-notification-api` | `2026.10.15` | Contrato leve para extensões **produtoras**: `EventDefinition`, `NotificationEvent`, `NotificationCatalogContributor`, `NotificationEventEnricher`, `RoutingAttribute`, `NotificationPublisher`. Só depende de `quarkus-arc`; tem `beans.xml`. |
23
+ | `runtime` | `br.com.seedgrid` | `seedgrid-notification` | `2026.10.15` | Motor (subscriber): catálogo, regras, outbox, scheduler, transportes, REST, migrations |
24
+ | `deployment` | `br.com.seedgrid` | `seedgrid-notification-deployment` | `2026.10.15` | Feature `seedgrid-notification`, beans unremovable, registro das entidades JPA na PU |
25
+ | `integration-tests` | `br.com.seedgrid` | `seedgrid-notification-integration-tests` | `2026.10.15` | Testcontainers (PostgreSQL 16, MailHog) — perfil `-Pit` |
26
+
27
+ Parent: `br.com.seedgrid:seedgrid-parent:2026.07.02`. Status: `stable` (`quarkus-extension.yaml`). O pom da notification sobrescreve `quarkus.platform.version` para `3.30.6` (o parent declara 3.30.8).
28
+
29
+ ## Dependências
30
+
31
+ | Dependência | Versão | Uso |
32
+ |---|---|---|
33
+ | `seedgrid-notification-api` | `${project.version}` | contratos |
34
+ | `br.com.seedgrid:seedgrid-whatsapp-core` (+ `-deployment`) | `2026.07.27` | `WhatsAppApi#sendTextMessage` — o provider (Evolution/Cloud) é escolhido pela extensão WhatsApp; ver [[SeedGrid/Extensions/whatsapp/Visao-geral|whatsapp]] |
35
+ | `seedgrid-commons` | `2026.10.08` (dependencyManagement) | — |
36
+ | `quarkus-mailer` | BOM | `@MailerName("security") Mailer` — o mesmo mailer nomeado do `seedgrid-security` |
37
+ | `quarkus-hibernate-orm`, `quarkus-agroal`, `quarkus-flyway`, `quarkus-scheduler`, `quarkus-security`, `quarkus-hibernate-validator`, `quarkus-rest-jackson` | BOM | — |
38
+
39
+ Integra como produtores (segundo o README): ai-pricing, billing e exchange — cada um depende só do `seedgrid-notification-api`. O `security` também só depende da `notification-api` (publica a falha de entrega de e-mail). Já `login-tenancy` e `subdomain-tenancy` dependem da extension completa (`seedgrid-notification` + `-deployment`): quem usa um tenancy recebe catálogo, regras, outbox e API administrativa sem declarar nada além do tenancy.
40
+
41
+ ## Arquitetura e fluxo
42
+
43
+ ```mermaid
44
+ flowchart LR
45
+ C[NotificationCatalogContributor<br/>beans das produtoras] --> K[NotificationCatalog]
46
+ P["NotificationPublisher.publish()<br/>(evento CDI síncrono)"] --> S[NotificationSubscriber @Transactional]
47
+ K --> S
48
+ R[NotificationRules<br/>regra por evento e scope] --> S
49
+ E[NotificationEventEnricher<br/>atributos de roteamento] -.-> S
50
+ S --> O[(sg_notification_event<br/>+ entregas PENDING)]
51
+ D["NotificationDispatcher<br/>@Scheduled every poll-interval"] --> Q["NotificationQueue.claim()<br/>FOR UPDATE SKIP LOCKED + lease"]
52
+ O --> Q
53
+ Q --> T[NotificationTransport]
54
+ T --> M[Mailer 'security']
55
+ T --> W[WhatsAppApi]
56
+ T --> X["NotificationQueue.complete()<br/>SENT / PENDING com backoff / FAILED"]
57
+ ```
58
+
59
+ Garantias e comportamento (Confirmado no código e em `docs/ARCHITECTURE.md`):
60
+ - Publicação síncrona dentro da transação de negócio; rollback desfaz marcador e entregas. Deduplicação por `(scope, event_code, event_id)`.
61
+ - Snapshot por canal/destinatário (texto, instância e destinatários congelados).
62
+ - Estados: `PENDING → SENDING → SENT`, ou volta a `PENDING` com backoff `retry-delay × 2^min(tentativas-1, 10)`, terminando em `FAILED` ao atingir `max-attempts`. Entrega **ao menos uma vez**.
63
+ - Templates em texto puro com `{variavel}` (substituição literal); assunto ≤ 300 caracteres sem CR/LF; corpo ≤ 16 000.
64
+ - WhatsApp sem `messageId` na resposta é falha (o provider no-op nunca conta como sucesso).
65
+ - Startup (`NotificationStartup`, `@Priority(APPLICATION + 1)`): valida a config, escolhe datasource (`datasource-name` → `master` → default) e roda Flyway próprio (`classpath:db/migration/notification`, tabela `flyway_schema_history_notification`, `baselineOnMigrate=true`). O dispatcher só trabalha depois disso (`isReady()`).
66
+ - Persistence unit escolhida **no build** (`NotificationProcessor#registerEntities`): `master` se existir datasource com esse nome, senão a PU default (`<default>`).
67
+ - Evento embutido: `platform.email-delivery-failed` (`OperationalNotificationCatalog`).
68
+
69
+ ## API pública
70
+
71
+ ### REST (Confirmado — `NotificationResource`, base `/admin/notifications`, `@Authenticated`)
72
+
73
+ | Método | Path | Permissão | Resultado |
74
+ |---|---|---|---|
75
+ | `GET` | `/admin/notifications/events` | `NOTIFICATION_READ` | `channels`, eventos instalados com a configuração atual, `routingAttributes` |
76
+ | `PUT` | `/admin/notifications/events/{code}` | `NOTIFICATION_UPDATE` | Substitui a regra (`NotificationRule`); `400` em regra inválida |
77
+ | `GET` | `/admin/notifications/deliveries?page=0&size=30` | `NOTIFICATION_READ` | Histórico paginado sem corpo/destinatário (`size` 1–200, `page` 0–100000) |
78
+
79
+ ### Contratos Java (módulo `api`)
80
+
81
+ | Símbolo | Papel |
82
+ |---|---|
83
+ | `EventDefinition(code, group, label, description, variables, subjectTemplate, bodyTemplate)` | Código `[a-z][a-z0-9-]*[.][a-z][a-z0-9.-]*` (≤ 120); variáveis `[a-zA-Z][a-zA-Z0-9_]*` |
84
+ | `NotificationCatalogContributor#events()` | Bean CDI da produtora; códigos duplicados ou variáveis não declaradas impedem o startup |
85
+ | `NotificationEvent(id, code, variables)` | `id` estável (≤ 160) para deduplicar |
86
+ | `NotificationPublisher#publish(NotificationEvent)` | Dispara evento CDI síncrono; sem o runtime instalado, nada acontece |
87
+ | `NotificationEventEnricher#attributes(event)` / `#describe()` | Host fornece atributos de roteamento para destinatários condicionais |
88
+ | `RoutingAttribute(key, label, options)` / `RoutingAttribute.Option(value, label)` | Descrição para a tela |
89
+
90
+ Modelo de regra (runtime): `NotificationRule(enabled, channels, emails, phones, whatsappChannelId, conditionalRecipients)` com `Channel {EMAIL, WHATSAPP}` e `ConditionalRecipient(channel, address, attribute, value)`.
91
+
92
+ ## Migrations
93
+
94
+ `runtime/src/main/resources/db/migration/notification/V1000__notification.sql` e `V1001__notification_permissions.sql`. Faixa reservada **1000–1099** (README). V1001 insere `NOTIFICATION_READ`/`NOTIFICATION_UPDATE` com `audience='platform'` (se a tabela `permissions` existir) e as vincula à role `ADMIN` (se `roles`/`role_permissions` existirem).
95
+
96
+ ## Testes existentes (não executados)
97
+
98
+ | Teste | Cobertura |
99
+ |---|---|
100
+ | `api/src/test/.../NotificationPublisherTest` | publicação síncrona por `Event` |
101
+ | `runtime/src/test/.../NotificationRulesTest` | catálogo, duplicidade, variáveis, templates, normalização de e-mail/telefone E.164, instância WhatsApp, condicionais, limite de 50, JSON legado |
102
+ | `runtime/src/test/.../NotificationRoutingTest` | condicionais, `value=null`, enricher não sobrescreve variáveis, enricher com exceção ignorado, `describe` |
103
+ | `runtime/src/test/.../NotificationTransportTest` | WhatsApp no-op não marca `SENT` |
104
+ | `runtime/src/test/.../NotificationEntityManagerTest` | seleção da PU default/nomeada |
105
+ | `integration-tests/.../NotificationIT` | fluxo completo com PostgreSQL, MailHog e Evolution simulada (perfil `-Pit`) |
106
+
107
+ ## Limitações
108
+
109
+ - `scope` **não** é resolução de company/tenant; a primeira versão atende alertas da plataforma.
110
+ - Sem UI, sem templates HTML, sem webhook de entrega, sem expurgo, sem reenvio manual, sem transação distribuída.
111
+ - Dados (destinatários e texto) ficam em claro no banco.
112
+ - `seedgrid.notification.datasource-name` afeta só o datasource das migrations; a PU das entidades é decidida no build (`master`/default). Configurar um datasource diferente pode separar schema e acesso JPA (Inferência — ver [[SeedGrid/Extensions/notification/Configuracao|Configuração]]).
113
+ - E-mail usa obrigatoriamente o mailer nomeado `security`; um host que substituiu o `EmailServiceInterface` do security por outro transporte precisa avaliar.
@@ -0,0 +1,67 @@
1
+ ---
2
+ tags: [seedgrid, extension, privacy, rust, configuracao]
3
+ fonte: rust/seedgrid-rust-crate-privacy
4
+ branch: main
5
+ commit: be738a2d1e
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # privacy — Configuração Rust
10
+
11
+ Visão do crate: [[SeedGrid/Extensions/privacy/Rust|Porte Rust do privacy]] · Java: [[SeedGrid/Extensions/privacy/Configuracao|Configuração do privacy (Java)]].
12
+
13
+ ## Cabeçalho
14
+ | Item | Valor |
15
+ |---|---|
16
+ | Mecanismo | estado global `CryptoProvider` (`rust/seedgrid-rust-crate-privacy/src/field.rs`); propriedades lidas do ambiente por `config_env(property)` |
17
+ | Conversão de nome | `env_of`: maiúsculas e `.`/`-` → `_` (`seedgrid.privacy.crypto.key` → `SEEDGRID_PRIVACY_CRYPTO_KEY`) |
18
+ | Prefixo Java | `seedgrid.privacy` (constantes em `CryptoProvider.java`) |
19
+ | Precedência | configuração programática (`CryptoProvider::configure*`, `set_encryption_enabled_for_tests`) > variável de ambiente > padrão |
20
+ | Leitura | `ENCRYPTION_ENABLED` a **cada** chamada de `is_encryption_enabled()` (sem cache); chaves na primeira chamada de `get_*_service()` e depois em cache |
21
+ | Struct de config | não há |
22
+
23
+ `config_env` trata valor vazio/brancos como ausente (não faz `trim` no valor retornado).
24
+
25
+ ## Variáveis de ambiente
26
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
27
+ |---|---|---|---|---|---|---|---|---|---|
28
+ | `SEEDGRID_PRIVACY_ENCRYPTION_ENABLED` (Java `seedgrid.privacy.encryption.enabled`) | bool | `true`, `1`, `yes`, `on` (case-insensitive) = ligado; qualquer outro = desligado | `false` | Não | ligado: `EncryptedFieldConverter::from_provider` cifra na escrita e o listener gera hash; desligado: grava cru e não gera hash | `CryptoProvider::is_encryption_enabled` → `EncryptedFieldConverter::resolve_for_write`, `apply_search_hashes_via_provider` | exige as duas chaves quando ligado | a cada chamada | `field.rs` → `ENCRYPTION_ENABLED_PROPERTY`, `parse_bool` |
29
+ | 🔒 `SEEDGRID_PRIVACY_CRYPTO_KEY` (Java `seedgrid.privacy.crypto.key`) | String | Base64 (com ou sem prefixo `base64:`) que decodifica para **exatamente 32 bytes** | — | Condicional: com cripto ligada e para **ler** valores `v1:...` | cria `AesGcmCryptoService`; ausente/inválida → serviço `None` (ver nota) | `CryptoProvider::get_crypto_service` | ignorada se `configure`/`configure_with_key` foi chamado | 1ª chamada, depois cache | `field.rs`; `crypto.rs` → `from_key_spec`, `decode_key`, `from_raw_key` |
30
+ | 🔒 `SEEDGRID_PRIVACY_SEARCH_KEY` (Java `seedgrid.privacy.search.key`) | String | Base64 (com ou sem `base64:`) com **≥ 32 bytes** | — | Condicional: para gerar/consultar hash de busca | cria `HmacSha256SearchHashService` | `get_search_hash_service`, `get_secure_search`, listener | ignorada se `configure_search_*` foi chamado | 1ª chamada, depois cache | `field.rs`; `search.rs` → `from_key_spec` |
31
+
32
+ Nota sobre chave ausente/inválida: com cripto ligada e sem serviço de cifra válido, `EncryptedFieldConverter::convert_to_database_column` devolve `Err(CryptoError::InvalidKey("seedgrid.privacy.crypto.key"))` (fail-closed, como o Java): o valor **não** é gravado em claro. Com cripto desligada o valor é gravado cru e nenhuma chave é exigida. Da mesma forma, `apply_search_hashes_via_provider` devolve erro (`seedgrid.privacy.search.key`) quando a cifra está ligada, a entidade tem campo com hash de busca e não há chave de busca. A leitura de um valor `v1:...` sem chave falha com `CryptoError::InvalidKey`. (**Confirmado** em `field.rs`: `resolve_for_write`, `apply_search_hashes_via_provider`, testes `cifra_ligada_sem_chave_falha_em_vez_de_gravar_em_claro` e `cifra_desligada_sem_chave_grava_cru`.)
33
+
34
+ Mapeamento Java ↔ env: **Confirmado** — mesmos nomes de propriedade em `java/seedgrid-quarkus-lib-privacy/src/main/java/br/com/seedgrid/privacy/CryptoProvider.java`; a conversão é a regra MicroProfile sem ambiguidade.
35
+
36
+ ## Configuração programática (sem env)
37
+ | API | Efeito |
38
+ |---|---|
39
+ | `CryptoProvider::configure(Arc<dyn CryptoService>)` / `configure_with_key(&str)` | define o serviço de cifra (vence a env) |
40
+ | `CryptoProvider::configure_search_hash_service(..)` / `configure_search_with_key(&str)` | define o serviço de hash (vence a env) |
41
+ | `CryptoProvider::configure_normalizer(..)` | troca o normalizador (padrão `DefaultValueNormalizer`) |
42
+ | `CryptoProvider::set_encryption_enabled_for_tests(bool)` | override do flag (vence a env) |
43
+ | `CryptoProvider::reset_for_tests()` | limpa tudo |
44
+ | `#[personal_data(search = "...", normalize = "none\|canonical\|email")]` | por campo, via derive; `normalize` padrão `canonical` (comentário do teste) |
45
+
46
+ ## Features Cargo
47
+ Nenhuma.
48
+
49
+ ## Somente testes
50
+ Nenhuma variável de ambiente lida em `tests/`.
51
+
52
+ ## Aliases / obsoletos
53
+
54
+ ## Configuração mínima (cripto ligada)
55
+ ```dotenv
56
+ SEEDGRID_PRIVACY_ENCRYPTION_ENABLED=true
57
+ SEEDGRID_PRIVACY_CRYPTO_KEY=base64:<SEGREDO:privacy-aes-256-key-32-bytes>
58
+ SEEDGRID_PRIVACY_SEARCH_KEY=base64:<SEGREDO:privacy-hmac-key-32-bytes>
59
+ ```
60
+
61
+ ## Receitas
62
+ - **Só mascaramento**: nenhuma configuração.
63
+ - **Cifra at-rest**: as três variáveis acima, ou `CryptoProvider::configure_with_key(...)` + `configure_search_with_key(...)` no boot.
64
+ - **Dados legados em claro**: podem coexistir; a leitura segue o dado (`v1:` decifra, cru volta cru).
65
+
66
+ ## Dúvidas e lacunas
67
+ - **Chave ausente ou inválida com a cifra ligada**: a gravação falha com erro (fail-closed), igual ao Java; nada é gravado em claro. A chave só é lida no primeiro uso — para falhar mais cedo, chame `CryptoProvider::configure_with_key` no boot do host e trate o erro.
@@ -0,0 +1,94 @@
1
+ ---
2
+ tags: [seedgrid, library, privacy, configuracao]
3
+ fonte: java/seedgrid-quarkus-lib-privacy
4
+ branch: main
5
+ commit: 79f8b03eeb
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # SeedGrid Privacy — Configuração
10
+
11
+ Voltar: [[SeedGrid/Extensions/privacy/Visao-geral|Visão geral do privacy]] · [[SeedGrid/Extensions/privacy/Exemplos|Exemplos do privacy]] · [[SeedGrid/Extensions/privacy/Rust|Porte Rust]]
12
+
13
+ ## 1. Cabeçalho
14
+
15
+ | Item | Valor |
16
+ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
+ | Prefixo | `seedgrid.privacy.*` |
18
+ | Classes de config | Nenhuma `@ConfigMapping`/`@ConfigRoot`/`@ConfigProperty`. Nomes como constantes em `CryptoProvider` (`ENCRYPTION_ENABLED_PROPERTY`, `CRYPTO_KEY_PROPERTY`, `SEARCH_KEY_PROPERTY`); leitura via `ConfigProvider.getConfig().getOptionalValue(...)`; POJO `CryptoProperties` só transporta as chaves |
19
+ | Arquivos de config da lib | Nenhum (`src/main/resources` inexistente) |
20
+ | Fase | Runtime. `encryption.enabled` é relido **a cada** escrita/hash (`isEncryptionEnabled()` sem cache). As chaves são lidas no startup (`CryptoBootstrap`, `@Singleton @Startup`) e/ou lazy no primeiro uso; depois ficam em campos estáticos (mudança posterior não tem efeito sem restart) |
21
+ | Masking | Não tem configuração (não usa chave) |
22
+
23
+ Investigado: `@ConfigMapping`, `@ConfigRoot`, `@ConfigProperty`, `ConfigProvider`, `System.getenv`, resources, testes. Fora de contexto MicroProfile (`IllegalStateException` do `ConfigProvider`), `isEncryptionEnabled()` → `false` e `loadConfiguredProperties()` → vazio.
24
+
25
+ ## 2. Propriedades próprias
26
+
27
+ ### 2.1 Secure Fields
28
+
29
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
30
+ | ------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
31
+ | `seedgrid.privacy.encryption.enabled` | `Boolean` | `true`/`false` | `false` | Não | `false`: `@EncryptedField` grava valor cru e o campo de hash fica sem preencher; `true`: cifra na escrita e preenche o hash | `EncryptedFieldAttributeConverter#resolveForWrite`, `EncryptedFieldListener#applyEncryptedField`; exposto em `CryptoProvider.isEncryptionEnabled()` para queries bimodais | Ligado exige `crypto.key` e `search.key`. A **leitura** não depende do flag (valor `v1:` sempre exige `crypto.key`). Override programático: `CryptoProvider.setEncryptionEnabledForTests` | Runtime (relido a cada chamada) | Declaração: `java/seedgrid-quarkus-lib-privacy/src/main/java/br/com/seedgrid/privacy/CryptoProvider.java` → `ENCRYPTION_ENABLED_PROPERTY`, `isEncryptionEnabled()` |
32
+ | `seedgrid.privacy.crypto.key` 🔒 | `String` (Base64, prefixo `base64:` opcional) | Base64 válido que decodifique para **32 bytes** (mínimo validado: 32; AES aceita 16/24/32 — use 32) | — | Condicional: obrigatória com `encryption.enabled=true` **e** para ler qualquer valor já cifrado (`v1:...`) mesmo com o flag desligado | Ausente quando necessária → `IllegalStateException("Propriedade obrigatoria ausente para secure fields: ...")` no 1º uso; inválida → `IllegalArgumentException` (no startup, se presente) | `AesGcmCryptoService` (AES/GCM/NoPadding, IV 12 bytes, tag 128 bits) | Deve ser diferente de `search.key` (README) | Runtime: startup (`CryptoBootstrap`) se presente; senão lazy em `CryptoProvider#getCryptoService()` | `CryptoProvider` → `CRYPTO_KEY_PROPERTY`, `loadConfiguredProperties()`, `getRequiredConfig()`; `KeyDecoder#decode(..., 32, ...)`; `AesGcmCryptoService(String)` |
33
+ | `seedgrid.privacy.search.key` 🔒 | `String` (Base64, prefixo `base64:` opcional) | Base64 válido com **≥ 32 bytes** | — | Condicional: obrigatória com `encryption.enabled=true` (listener com `searchField`) e sempre que se usar `EncryptedFieldSearch()`/`CryptoProvider.getSecureSearch()` (independe do flag) | Ausente quando necessária → `IllegalStateException`; inválida → `IllegalArgumentException` (no startup, se presente) | `HmacSha256SearchHashService` (hash hex lowercase) | Trocar a chave invalida todos os hashes já gravados (**Inferência**) | Runtime: startup se presente; senão lazy em `getSearchHashService()` | `CryptoProvider` → `SEARCH_KEY_PROPERTY`; `HmacSha256SearchHashService(String)` |
34
+
35
+ Variáveis de ambiente pela regra MP (**Inferência**, leitura por nome exato): `SEEDGRID_PRIVACY_ENCRYPTION_ENABLED`, `SEEDGRID_PRIVACY_CRYPTO_KEY`, `SEEDGRID_PRIVACY_SEARCH_KEY`. O exemplo e o README usam **outras** env vars via expansão no `application.properties` (`SEEDGRID_CRYPTO_KEY`, `SEEDGRID_SEARCH_KEY`, `SEEDGRID_PRIVACY_ENCRYPTION_ENABLED`) — convenção do host, não lida pela lib.
36
+
37
+ ## 3. Propriedades de frameworks recomendadas
38
+
39
+ | Propriedade | Situação | Origem |
40
+ |---|---|---|
41
+ | `quarkus.hibernate-orm.packages` incluindo `br.com.seedgrid.privacy` | Usada no exemplo, com o comentário de que o pacote da lib contém o converter e o listener referenciados por `@Convert`/`@EntityListeners`. Necessidade só quando o host restringe `packages` — **Inferência** | `java/examples/seedgrid-privacy-example/src/main/resources/application.properties` |
42
+ | `quarkus.datasource.*`, `quarkus.flyway.*` | Do host (a lib não traz migrations; colunas cifradas precisam comportar `v1:iv:ciphertext`, o exemplo usa `length = 512`; hash `length = 64`) | exemplo `Customer` + `V1000__create_customers.sql` |
43
+
44
+ ## 4. Propriedades só de testes/exemplos
45
+
46
+ | Propriedade | Onde | Observação |
47
+ |---|---|---|
48
+ | `seedgrid.privacy.encryption.enabled=true`, `seedgrid.privacy.crypto.key`, `seedgrid.privacy.search.key` | `java/examples/seedgrid-privacy-example/src/{main,test}/resources/application.properties` | O exemplo define as três propriedades (com valores default fictícios na expansão `${SEEDGRID_CRYPTO_KEY:...}`) |
49
+ | (nenhuma) | testes da própria lib | usam `CryptoProvider.setEncryptionEnabledForTests`/`resetForTests` e construtores package-private com serviços injetados |
50
+
51
+ ## 5. Aliases, obsoletas, renomeações
52
+
53
+ Nenhuma propriedade renomeada. Renomeações de API (não de config): `@PersonalData` ← antiga `@AuditSensitive`; `@MaskRule` ← `@AuditFieldRule`; `PersonalDataSanitizer` ← `AuditSanitizerService`; `PersonalDataResolver` ← `AuditSensitiveRuleResolverService` (Javadocs).
54
+
55
+ ## 6. Configuração mínima
56
+
57
+ Modo agnóstico (padrão): **nenhuma** propriedade. Para cifrar:
58
+
59
+ ```properties
60
+ seedgrid.privacy.encryption.enabled=true
61
+ seedgrid.privacy.crypto.key=${SEEDGRID_PRIVACY_CRYPTO_KEY}
62
+ seedgrid.privacy.search.key=${SEEDGRID_PRIVACY_SEARCH_KEY}
63
+ ```
64
+
65
+ ## 7. Configuração completa comentada
66
+
67
+ ```properties
68
+ # Liga a cifra at-rest dos @EncryptedField (padrão false = grava cru, sem exigir chave)
69
+ seedgrid.privacy.encryption.enabled=true
70
+
71
+ # AES-256-GCM: Base64 (ou "base64:<...>") de exatamente 32 bytes. Guardar em secret.
72
+ seedgrid.privacy.crypto.key=<SEGREDO:privacy-crypto-key>
73
+
74
+ # HMAC-SHA256 do hash de busca: Base64 de >= 32 bytes, DIFERENTE da crypto.key.
75
+ seedgrid.privacy.search.key=<SEGREDO:privacy-search-key>
76
+
77
+ # Se o host restringe os pacotes do Hibernate, inclua o da lib (converter/listener):
78
+ quarkus.hibernate-orm.packages=<pacote.das.suas.entidades>,br.com.seedgrid.privacy
79
+ ```
80
+
81
+ Gerar uma chave de 32 bytes (ex.): `openssl rand -base64 32`.
82
+
83
+ ## 8. Receitas
84
+
85
+ - **App sem gestão de chaves**: não configure nada; `@EncryptedField` grava cru e a busca usa o campo normal (`if (CryptoProvider.isEncryptionEnabled()) ... else ...`). O masking continua ativo.
86
+ - **App com cifra e busca por CPF/e-mail**: ligue o flag + as duas chaves; anote `@EncryptedField(searchField="cpfHash", normalize=CANONICAL)` e `@EncryptedField(searchField="emailHash", normalize=EMAIL)`; busque com `hashForSearch(valor, mesmaNormalização)`.
87
+ - **Banco legado em claro → cifrado**: ligar o flag não recifra registros antigos (sem backfill automático); planeje migração.
88
+ - **Desligar com dados cifrados**: mantenha `crypto.key` configurada, senão a leitura de valores `v1:` falha.
89
+
90
+ ## 9. Dúvidas e lacunas
91
+
92
+ - A falha "fail-closed" com flag ligado e chave ausente ocorre no **primeiro uso**, não no boot.
93
+ - Não há rotação de chave nem versionamento de chave além do prefixo `v1`.
94
+ - Mapeamento com o crate Rust: [[SeedGrid/Extensions/privacy/Configuracao-Rust|Configuração Rust do privacy]].
@@ -0,0 +1,79 @@
1
+ ---
2
+ tags: [seedgrid, library, privacy, enum]
3
+ fonte: java/seedgrid-quarkus-lib-privacy
4
+ branch: main
5
+ commit: 79f8b03eeb
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # SeedGrid Privacy — Enums
10
+
11
+ Voltar: [[SeedGrid/Extensions/privacy/Visao-geral|Visão geral do privacy]] · [[SeedGrid/Extensions/privacy/Configuracao|Configuração do privacy]] · [[SeedGrid/Extensions/privacy/Rust|Porte Rust]]
12
+
13
+ Nenhum destes enums é tipo de propriedade de configuração nem é persistido: são atributos de anotações públicas e parâmetros de API.
14
+
15
+ | Enum | Pacote/arquivo | Usado em | Público? |
16
+ |---|---|---|---|
17
+ | `MaskingStrategy` | `br.com.seedgrid.privacy.masking.MaskingStrategy` | `@PersonalData.type`, `@MaskRule.type`, `PersonalDataMasker.mask`, `PersonalDataSanitizer` | Sim |
18
+ | `SearchNormalization` | `br.com.seedgrid.privacy.SearchNormalization` | `@EncryptedField.normalize`, `EncryptedFieldSearch.hashForSearch` | Sim |
19
+ | `CryptoAlgorithm` | `br.com.seedgrid.privacy.CryptoAlgorithm` | `@EncryptedField.cryptoAlgorithm` | Sim |
20
+ | `SearchAlgorithm` | `br.com.seedgrid.privacy.SearchAlgorithm` | `@EncryptedField.searchAlgorithm` | Sim |
21
+
22
+ ## MaskingStrategy
23
+
24
+ Arquivo: `java/seedgrid-quarkus-lib-privacy/src/main/java/br/com/seedgrid/privacy/masking/MaskingStrategy.java`.
25
+
26
+ Cada constante implementa `String maskValue(String value, String param)`; `param` vem de `@PersonalData.maskWith` / `@MaskRule.maskWith` (padrão da anotação: `"***"`).
27
+
28
+ | Valor | Significado | Efeito / onde é tratado | Observações |
29
+ |---|---|---|---|
30
+ | `FULL` | Substitui todo o valor por um texto fixo | `param` não vazio → `param`; senão `"***"` | Padrão de `@PersonalData.type` e `@MaskRule.type`. **Confirmado.** |
31
+ | `FORMAT` | Máscara pronta que preserva o formato | `param` não vazio → `param`; senão `"***"` | Comportamento idêntico a `FULL`; a diferença é só semântica (`param` é a máscara completa). O valor original é ignorado. |
32
+ | `PARTIAL` | Revela só os últimos N caracteres | `param` = N (inteiro; ausente ou inválido → 2). Valor mais curto ou igual a N volta inteiro, sem máscara; valor `null` → `null` | Ex.: `"12345678900"`, N=3 → `"********900"`. |
33
+ | `HASH` | SHA-256 hexadecimal minúsculo | `Sha256.hex(value)`; `null` é tratado como string vazia | Irreversível; `param` ignorado. |
34
+ | `TEMPLATE` | Gabarito posicional | `#` revela o caractere da mesma posição (espaço se o valor for menor), `*` mascara, outro caractere é literal; valor ou `param` `null` → `"***"` | O tamanho do resultado é o do gabarito, não o do valor. |
35
+ | `REMOVE` | Remove o campo | `maskValue` devolve `null`; `isRemoval()` é `true`. `PersonalDataSanitizer` remove a chave do JSON; `PersonalDataMasker.mask` devolve `null` | Também usado quando `@MaskRule.remove=true`, que sobrepõe o `type`. |
36
+
37
+ **Atributos/métodos:** sem campos; `abstract maskValue(String, String)`, `isRemoval()`.
38
+
39
+ **Serialização:** não é serializado nem persistido; só aparece em anotações (valor da constante em tempo de compilação). Um `strategy` `null` em `PersonalDataMasker.mask` devolve o valor inalterado.
40
+
41
+ **Onde é usado:** `@PersonalData` / `@MaskRule` (resolvidos por `PersonalDataResolver`, aplicados por `PersonalDataSanitizer`, com precedência override › payload › modelo); `PersonalDataMasker.mask`; embeddables `Address` e `Contact` do commons — ver [[SeedGrid/Extensions/commons/Visao-geral|Visão geral do commons]]. O masking não tem propriedades de configuração.
42
+
43
+ ## SearchNormalization
44
+
45
+ Arquivo: `java/seedgrid-quarkus-lib-privacy/src/main/java/br/com/seedgrid/privacy/SearchNormalization.java`.
46
+
47
+ | Valor | Significado | Efeito / onde é tratado | Observações |
48
+ |---|---|---|---|
49
+ | `NONE` | Sem normalização: hash do valor exato | `apply` devolve o valor como está | Padrão de `@EncryptedField.normalize`. Case-sensitive. |
50
+ | `CANONICAL` | Forma canônica: `trim`, remove acentos (NFD), minúsculas, mantém só `[a-z0-9]` | `apply` delega ao `ValueNormalizer` (`DefaultValueNormalizer`, substituível via `CryptoProvider.configureNormalizer`) | Para CPF, CNPJ, telefone e CEP. `hashForSearch(valor)` sem 2º argumento usa este modo. |
51
+ | `EMAIL` | `trim` + minúsculas, preservando `@ . - _` | `apply` faz `value.trim().toLowerCase(Locale.ROOT)` | Para e-mail; `CANONICAL` faria e-mails diferentes colidirem. |
52
+
53
+ **Métodos:** `String apply(String value, ValueNormalizer canonicalNormalizer)` — `null` → `null`; o normalizador só é usado por `CANONICAL`.
54
+
55
+ **Regra importante:** a mesma normalização deve ser usada na gravação (`EncryptedFieldListener`, a partir de `@EncryptedField.normalize`) e na consulta (`EncryptedFieldSearch.hashForSearch(valor, normalização)`); senão a busca não encontra o registro. A normalização só afeta o hash de busca, nunca o valor cifrado.
56
+
57
+ **Serialização/persistência:** nenhuma (só atributo de anotação e parâmetro de método).
58
+
59
+ **Onde é usado:** `@EncryptedField.normalize`; `EncryptedFieldListener`; `EncryptedFieldSearch`; embeddables `Address` (telefone) e `Contact` (cpf, telefone, whatsapp: `CANONICAL`; email: `EMAIL`). Só tem efeito com `seedgrid.privacy.encryption.enabled=true` — ver [[SeedGrid/Extensions/privacy/Configuracao|Configuração do privacy]].
60
+
61
+ ## CryptoAlgorithm
62
+
63
+ Arquivo: `java/seedgrid-quarkus-lib-privacy/src/main/java/br/com/seedgrid/privacy/CryptoAlgorithm.java`.
64
+
65
+ | Valor | Significado | Efeito / onde é tratado | Observações |
66
+ |---|---|---|---|
67
+ | `AES_256_GCM` | Cifra AES-256 em modo GCM | **Nenhum código lê** `@EncryptedField.cryptoAlgorithm()`; a cifra é sempre `AesGcmCryptoService` (AES/GCM/NoPadding) | Único valor e padrão do atributo. Escolher outro algoritmo não é possível. |
68
+
69
+ ## SearchAlgorithm
70
+
71
+ Arquivo: `java/seedgrid-quarkus-lib-privacy/src/main/java/br/com/seedgrid/privacy/SearchAlgorithm.java`.
72
+
73
+ | Valor | Significado | Efeito / onde é tratado | Observações |
74
+ |---|---|---|---|
75
+ | `HMAC_SHA256` | HMAC-SHA256 para o hash de busca | **Nenhum código lê** `@EncryptedField.searchAlgorithm()`; o hash é sempre `HmacSha256SearchHashService` | Único valor e padrão do atributo. |
76
+
77
+ ## Internos
78
+
79
+ Nenhum.
@@ -0,0 +1,172 @@
1
+ ---
2
+ tags: [seedgrid, library, privacy, exemplos]
3
+ fonte: java/seedgrid-quarkus-lib-privacy, java/examples/seedgrid-privacy-example
4
+ branch: main
5
+ commit: 79f8b03eeb
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # SeedGrid Privacy — Exemplos
10
+
11
+ Voltar: [[SeedGrid/Extensions/privacy/Visao-geral|Visão geral do privacy]] · [[SeedGrid/Extensions/privacy/Configuracao|Configuração do privacy]]
12
+
13
+ ## Dependência
14
+
15
+ ```xml
16
+ <dependency>
17
+ <groupId>br.com.seedgrid</groupId>
18
+ <artifactId>seedgrid-privacy</artifactId>
19
+ <version>2026.07.27</version>
20
+ </dependency>
21
+ ```
22
+
23
+ ## Entidade com campos cifrados e pesquisáveis (exemplo real)
24
+
25
+ Fonte: `java/examples/seedgrid-privacy-example/src/main/java/br/com/seedgrid/privacyexample/entity/Customer.java` (Lombok `@Getter/@Setter/@NoArgsConstructor` omitidos).
26
+
27
+ ```java
28
+ @Entity
29
+ @Table(name = "customers")
30
+ @EntityListeners(EncryptedFieldListener.class)
31
+ public class Customer {
32
+
33
+ @Id
34
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
35
+ private Long id;
36
+
37
+ // cifrado, NÃO pesquisável (sem searchField)
38
+ @Convert(converter = EncryptedFieldAttributeConverter.class)
39
+ @EncryptedField
40
+ @Column(nullable = false, length = 512)
41
+ private String name;
42
+
43
+ @Convert(converter = EncryptedFieldAttributeConverter.class)
44
+ @EncryptedField(searchField = "emailHash", normalize = SearchNormalization.EMAIL)
45
+ @Column(nullable = false, length = 512)
46
+ private String email;
47
+
48
+ @Column(name = "email_hash", length = 64)
49
+ private String emailHash;
50
+
51
+ @Convert(converter = EncryptedFieldAttributeConverter.class)
52
+ @EncryptedField(searchField = "cpfHash", normalize = SearchNormalization.CANONICAL)
53
+ @Column(nullable = false, length = 512)
54
+ private String cpf;
55
+
56
+ @Column(name = "cpf_hash", length = 64)
57
+ private String cpfHash;
58
+
59
+ @Convert(converter = EncryptedFieldAttributeConverter.class)
60
+ @EncryptedField
61
+ @Column(length = 512)
62
+ private String phone;
63
+ }
64
+ ```
65
+
66
+ ## Busca por hash e mascaramento (exemplo real)
67
+
68
+ Fonte: `.../privacyexample/service/CustomerService.java` (trecho).
69
+
70
+ ```java
71
+ public Optional<Customer> findByEmail(String email) {
72
+ EncryptedFieldSearch search = CryptoProvider.getSecureSearch();
73
+ String hash = search.hashForSearch(email, SearchNormalization.EMAIL);
74
+ return repository.findByEmailHash(hash); // find("emailHash", hash).firstResultOptional()
75
+ }
76
+
77
+ public Optional<Customer> findByCpf(String cpf) {
78
+ EncryptedFieldSearch search = CryptoProvider.getSecureSearch();
79
+ String hash = search.hashForSearch(cpf, SearchNormalization.CANONICAL);
80
+ return repository.findByCpfHash(hash);
81
+ }
82
+
83
+ public CustomerResponse mask(CustomerResponse response) {
84
+ return sanitizer.sanitize(response, CustomerResponse.class); // PersonalDataSanitizer injetado
85
+ }
86
+ ```
87
+
88
+ DTO de saída com regras de masking (fonte: `.../dto/CustomerResponse.java`):
89
+
90
+ ```java
91
+ public class CustomerResponse {
92
+ public Long id;
93
+
94
+ @PersonalData(type = MaskingStrategy.PARTIAL, maskWith = "4")
95
+ public String name;
96
+
97
+ @PersonalData(type = MaskingStrategy.FULL)
98
+ public String email;
99
+
100
+ @PersonalData(type = MaskingStrategy.FORMAT, maskWith = "***.***.***-**")
101
+ public String cpf;
102
+
103
+ @PersonalData(type = MaskingStrategy.PARTIAL, maskWith = "4")
104
+ public String phone;
105
+ }
106
+ ```
107
+
108
+ ## Busca bimodal (cifra opcional)
109
+
110
+ Fonte: `README.md`.
111
+
112
+ ```java
113
+ if (CryptoProvider.isEncryptionEnabled()) {
114
+ String hash = new EncryptedFieldSearch().hashForSearch(cpf); // CANONICAL por padrão
115
+ return repository.find("cpfHash", hash).firstResult();
116
+ }
117
+ return repository.find("cpf", cpf).firstResult();
118
+ ```
119
+
120
+ > `new EncryptedFieldSearch()` exige `seedgrid.privacy.search.key` — por isso fica dentro do `if`.
121
+
122
+ ## Campo cifrado dentro de `@Embeddable`
123
+
124
+ Fonte: `README.md` (comportamento confirmado em `EncryptedFieldListener#applyTo`).
125
+
126
+ ```java
127
+ @Embeddable
128
+ public class Contato {
129
+ @EncryptedField(searchField = "cpfHash", normalize = SearchNormalization.CANONICAL)
130
+ @Convert(converter = EncryptedFieldAttributeConverter.class)
131
+ private String cpf;
132
+
133
+ private String cpfHash; // irmão, no MESMO embeddable
134
+ }
135
+
136
+ @Entity
137
+ @EntityListeners(EncryptedFieldListener.class)
138
+ public class Empresa {
139
+ @Embedded
140
+ private Contato representante;
141
+ }
142
+ ```
143
+
144
+ Os embeddables `Address`/`Contact` do commons seguem esse padrão — ver [[SeedGrid/Extensions/commons/Visao-geral|Visão geral do commons]].
145
+
146
+ ## Masking de valores soltos
147
+
148
+ Fonte: `README.md` + assinaturas de `PersonalDataMasker`.
149
+
150
+ ```java
151
+ String cpf = PersonalDataMasker.cpf("12345678900"); // ***.***.***-00
152
+ String cnpj = PersonalDataMasker.cnpj("12345678000190");
153
+ String cep = PersonalDataMasker.cep("01310100"); // 01310-***
154
+ String x = PersonalDataMasker.mask("12345678900", MaskingStrategy.PARTIAL, "3"); // ********900
155
+
156
+ @Override
157
+ public String toString() {
158
+ return "Contact [cpf=" + PersonalDataMasker.cpf(cpf)
159
+ + ", email=" + PersonalDataMasker.mask(email, MaskingStrategy.FULL, null) + "]";
160
+ }
161
+ ```
162
+
163
+ ## Configuração
164
+
165
+ ```properties
166
+ seedgrid.privacy.encryption.enabled=true
167
+ seedgrid.privacy.crypto.key=<SEGREDO:privacy-crypto-key>
168
+ seedgrid.privacy.search.key=<SEGREDO:privacy-search-key>
169
+ quarkus.hibernate-orm.packages=<pacote.das.entidades>,br.com.seedgrid.privacy
170
+ ```
171
+
172
+ Detalhes: [[SeedGrid/Extensions/privacy/Configuracao|Configuração do privacy]].