@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.
- package/LICENSE +21 -0
- package/README.md +151 -2
- package/dist/adapters/claude.js +114 -0
- package/dist/adapters/codex.js +108 -0
- package/dist/adapters/index.js +17 -0
- package/dist/adapters/shared.js +142 -0
- package/dist/adapters/types.js +1 -0
- package/dist/cli.js +203 -0
- package/dist/commands/common.js +98 -0
- package/dist/commands/doctor.js +290 -0
- package/dist/commands/init.js +9 -0
- package/dist/commands/install.js +107 -0
- package/dist/commands/remove.js +54 -0
- package/dist/commands/review.js +127 -0
- package/dist/commands/status.js +73 -0
- package/dist/commands/update.js +8 -0
- package/dist/commands/validate.js +27 -0
- package/dist/core/apply.js +181 -0
- package/dist/core/blocks.js +64 -0
- package/dist/core/content.js +528 -0
- package/dist/core/env.js +40 -0
- package/dist/core/frontmatter.js +29 -0
- package/dist/core/hash.js +14 -0
- package/dist/core/inspect.js +51 -0
- package/dist/core/lock.js +124 -0
- package/dist/core/paths.js +65 -0
- package/dist/core/plan.js +242 -0
- package/dist/core/tools.js +62 -0
- package/dist/core/types.js +11 -0
- package/dist/core/updates.js +121 -0
- package/docs/arquitetura.md +80 -0
- package/docs/compatibilidade.md +50 -0
- package/docs/formato.md +155 -0
- package/docs/instalacao.md +105 -0
- package/docs/manutencao.md +115 -0
- package/package.json +43 -4
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
- package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
- package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
- package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
- package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
- package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
- package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
- package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
- package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
- package/seedgridKB/SeedGrid/Versoes.md +64 -0
- package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
- 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.
|