@seedgrid/ai-toolkit 0.3.2 → 0.3.4
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/README.md +2 -2
- package/dist/adapters/shared.js +1 -0
- package/docs/formato.md +1 -1
- package/package.json +1 -1
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +3 -2
- package/seedgridKB/SeedGrid/Extensions/Indice.md +1 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +11 -18
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +2 -2
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +2 -2
- package/seedgridKB/SeedGrid/Extensions/business-days/Configuracao.md +36 -0
- package/seedgridKB/SeedGrid/Extensions/business-days/Exemplos.md +37 -0
- package/seedgridKB/SeedGrid/Extensions/business-days/Visao-geral.md +48 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +10 -16
- package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +2 -2
- package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +2 -2
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +4 -5
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +1 -1
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +3 -2
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +2 -2
- package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +9 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Autenticacao-e-chaves.md +89 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Exemplos.md +44 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Protocolo-e-API.md +191 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/SDKs.md +287 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Configuracao.md +128 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Instalacao.md +105 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Operacao.md +86 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Providers.md +121 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/UI/Configuracao.md +61 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/UI/Visao-geral.md +74 -0
- package/seedgridKB/SeedGrid/Produtos/Pulse/Visao-geral.md +96 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +1 -1
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +1 -1
- package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +1 -1
- package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +38 -26
- package/seedgridKB/SeedGrid/Toolkit/rules/backend-seedgrid.md +45 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-code-review/SKILL.md +1 -1
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-back/SKILL.md +4 -4
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/SKILL.md +3 -3
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-screen/SKILL.md +2 -2
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-skill/SKILL.md +20 -5
- package/seedgridKB/SeedGrid/Toolkit/skills/sg-review/SKILL.md +3 -3
- package/seedgridKB/SeedGrid/Visao-geral.md +7 -0
- package/seedgridKB/manifest.json +8 -7
- /package/seedgridKB/SeedGrid/Toolkit/skills/sg-code-review/references/{checklist.md → code-review-checklist.md} +0 -0
- /package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/references/{checklist.md → crud-front-checklist.md} +0 -0
- /package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/references/{patterns.md → crud-front-patterns.md} +0 -0
- /package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/references/{routing.md → crud-front-routing.md} +0 -0
- /package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-screen/references/{checklist.md → new-screen-checklist.md} +0 -0
- /package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-screen/references/{steps.md → new-screen-steps.md} +0 -0
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Cada pasta de `.ai/` (`rules`, `agents`, `skills`, `templates`, `references`) te
|
|
|
23
23
|
| Destino | Conteúdo |
|
|
24
24
|
| --- | --- |
|
|
25
25
|
| `.ai/agents/` | Papéis (`arquiteto`, `backend-java`, `backend-rust`, `frontend-react`, `qa`, `revisor`) e `index.md` gerado |
|
|
26
|
-
| `.ai/rules/` | Coordenação, formato de entrega, personalização local e os **padrões SeedGrid obrigatórios** (`frontend-seedgrid`, `backend-java-seedgrid`) |
|
|
26
|
+
| `.ai/rules/` | Coordenação, formato de entrega, personalização local e os **padrões SeedGrid obrigatórios** (`frontend-seedgrid`, `backend-seedgrid`, `backend-java-seedgrid`) |
|
|
27
27
|
| `.ai/templates/` | Especificação de tarefa, decisão de arquitetura, relatório de validação |
|
|
28
28
|
| `.ai/references/` | Modos shared/native e glossário |
|
|
29
29
|
| `.ai/skills/index.md` | Índice gerado das skills (o que faz e quando usar) |
|
|
@@ -101,7 +101,7 @@ seedgrid-ai review back --tool codex # só o back-end, usando o Code
|
|
|
101
101
|
|
|
102
102
|
### `seedgrid-ai review`
|
|
103
103
|
|
|
104
|
-
Executa a skill `sg-review` na ferramenta de IA instalada, em modo não interativo e somente leitura (Claude Code: `claude -p` com ferramentas de leitura; Codex: `codex exec --sandbox read-only`). A skill confere o código contra as regras `FE-nn` e `BE-nn` (`.ai/rules/frontend-seedgrid.md` e `backend-java-seedgrid.md`) e o CLI mostra o relatório e devolve o código de saída.
|
|
104
|
+
Executa a skill `sg-review` na ferramenta de IA instalada, em modo não interativo e somente leitura (Claude Code: `claude -p` com ferramentas de leitura; Codex: `codex exec --sandbox read-only`). A skill confere o código contra as regras `FE-nn` e `BE-nn` (`.ai/rules/frontend-seedgrid.md`, `backend-seedgrid.md` e `backend-java-seedgrid.md`) e o CLI mostra o relatório e devolve o código de saída.
|
|
105
105
|
|
|
106
106
|
- **Escopo:** `front`, `back` ou nenhum (os dois). Por padrão revisa os arquivos alterados (diff); `--full` revisa o projeto inteiro.
|
|
107
107
|
- **Ferramenta:** `--tool claude|codex`. Sem a opção, usa a primeira disponível nesta ordem: Claude Code, Codex. Considera só os targets instalados no projeto que tenham a skill e o executável no `PATH`. O CLI não detecta em qual ferramenta você está trabalhando.
|
package/dist/adapters/shared.js
CHANGED
|
@@ -103,6 +103,7 @@ function brainLines(bundle) {
|
|
|
103
103
|
}
|
|
104
104
|
const STANDARD_RULES = [
|
|
105
105
|
['rules/frontend-seedgrid.md', 'front-end'],
|
|
106
|
+
['rules/backend-seedgrid.md', 'back-end, comum a todas as linguagens'],
|
|
106
107
|
['rules/backend-java-seedgrid.md', 'back-end Java'],
|
|
107
108
|
];
|
|
108
109
|
/** Padrões SeedGrid obrigatórios (front e back), quando o conteúdo os inclui. */
|
package/docs/formato.md
CHANGED
|
@@ -57,7 +57,7 @@ Arquivos e pastas que começam com ponto são ignorados.
|
|
|
57
57
|
```json
|
|
58
58
|
{
|
|
59
59
|
"schemaVersion": 2,
|
|
60
|
-
"contentVersion": "0.3.
|
|
60
|
+
"contentVersion": "0.3.4",
|
|
61
61
|
"toolkitBase": "SeedGrid/Toolkit",
|
|
62
62
|
"components": [
|
|
63
63
|
{ "id": "agents", "type": "agents", "files": ["agents/arquiteto.md"] },
|
package/package.json
CHANGED
|
@@ -249,8 +249,9 @@ Tabela geral de **todas as propriedades públicas** de configuração documentad
|
|
|
249
249
|
| `seedgrid.login-tenancy.modules.filemanagement.enabled` | Ativação lógica dos módulos | `boolean` | `true` | Runtime | Só afeta activeModules (status/log); filemanagement não tem migrations no baseline | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
250
250
|
| `seedgrid.audit.mongodb.database` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `Optional<String>` | — (deriva `<app.code>_audit_db`, ou `audit_db`) | audit]]) | Override do banco Mongo de auditoria produzido pela foundation (banco único) | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
251
251
|
| `seedgrid.audit.persistence.strategy` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `Optional<String>` | — | Runtime | Decide se as migrations db/migration/audit rodam | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
252
|
-
| `seedgrid.ai-pricing.
|
|
253
|
-
| `seedgrid.exchange.
|
|
252
|
+
| `seedgrid.login-tenancy.modules.ai-pricing.enabled` | Ativação lógica dos módulos | `boolean` | `true` | Runtime | false: não migra o ai-pricing e as rotas respondem 404 | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
253
|
+
| `seedgrid.login-tenancy.modules.exchange.enabled` | Ativação lógica dos módulos | `boolean` | `true` | Runtime | false: não migra o exchange e as rotas respondem 404 | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
254
|
+
| `seedgrid.login-tenancy.modules.business-days.enabled` | Ativação lógica dos módulos | `boolean` | `true` | Runtime | false: não migra o business-days e as rotas respondem 404 | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
254
255
|
| `seedgrid.security.first-admin-user.email` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `Optional<String>` | — | security]] | Só lida para decidir logs/WARN e firstAdminConfigured no status | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
255
256
|
| `seedgrid.security.jwt.issuer` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `Optional<String>` | — | Runtime | Exibido em security.jwtIssuer no status | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
256
257
|
| `seedgrid.show-dev-message` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `boolean` | `false` | Runtime | Inclui devMessage nos problem+json das exceções da login-tenancy | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
|
|
@@ -25,6 +25,7 @@ Contagens de propriedades por extension e plataforma: [[SeedGrid/Extensions/Cata
|
|
|
25
25
|
| billing | Assinaturas: planos, uso, checkout, portal, webhooks; provider Stripe. | [[SeedGrid/Extensions/billing/Visao-geral\|Visão geral]] · [[SeedGrid/Extensions/billing/Configuracao\|Config]] · [[SeedGrid/Extensions/billing/Exemplos\|Exemplos]] · [[SeedGrid/Extensions/billing/Enums|Enums]] | [[SeedGrid/Extensions/billing/Rust\|Rust]] · [[SeedGrid/Extensions/billing/Configuracao-Rust\|Config]] |
|
|
26
26
|
| ai-pricing | Catálogo de modelos LLM e histórico de preços por 1M tokens; robô agendado propõe mudanças com aprovação humana (só Java). | [[SeedGrid/Extensions/ai-pricing/Visao-geral\|Visão geral]] · [[SeedGrid/Extensions/ai-pricing/Configuracao\|Config]] · [[SeedGrid/Extensions/ai-pricing/Exemplos\|Exemplos]] · [[SeedGrid/Extensions/ai-pricing/Enums|Enums]] | — |
|
|
27
27
|
| exchange | Moedas e cotações diárias com histórico; fontes configuráveis por cadastro, retry; seed USD-BRL PTAX (só Java). | [[SeedGrid/Extensions/exchange/Visao-geral\|Visão geral]] · [[SeedGrid/Extensions/exchange/Configuracao\|Config]] · [[SeedGrid/Extensions/exchange/Exemplos\|Exemplos]] · [[SeedGrid/Extensions/exchange/Enums|Enums]] | — |
|
|
28
|
+
| business-days | Calendário de dias úteis: feriados (recorrentes ou de um ano), semana de trabalho (peso 0/0,5/1) e cálculo de dias úteis; escopo por empresa (JPA puro). | [[SeedGrid/Extensions/business-days/Visao-geral\|Visão geral]] · [[SeedGrid/Extensions/business-days/Configuracao\|Configuração]] · [[SeedGrid/Extensions/business-days/Exemplos\|Exemplos]] |
|
|
28
29
|
|
|
29
30
|
## Dados, auditoria e compliance
|
|
30
31
|
|
|
@@ -47,11 +47,14 @@ Variáveis de ambiente pela regra MP, sem ambiguidade:
|
|
|
47
47
|
|
|
48
48
|
Origem: `rt/entities/AiPricingConfigEntity.java`, `runtime/src/main/resources/db/migration/ai-pricing/V902__seed_ai_models_and_pricing_config.sql`, `rt/controllers/AdminAiPriceApprovalResource#saveConfig`.
|
|
49
49
|
|
|
50
|
-
### 2.3
|
|
50
|
+
### 2.3 Toggle do módulo
|
|
51
51
|
|
|
52
|
-
| Propriedade |
|
|
53
|
-
|
|
54
|
-
| `seedgrid.ai-pricing.
|
|
52
|
+
| Propriedade | Padrão | Efeito |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `seedgrid.ai-pricing.enabled` | `true` | `false`: sem migrations, sem robô e as rotas `/admin/ai/**` respondem 404. Nas tenancy o default vem de `seedgrid.<tenancy>.modules.ai-pricing.enabled`. |
|
|
55
|
+
| `seedgrid.migrations.host-managed` | `false` | `true` (definido pelas tenancy): o runner da extension não age; a tenancy migra cada banco. |
|
|
56
|
+
|
|
57
|
+
A extension **sempre migra** o datasource default na subida (`AiPricingMigrationRunner`, histórico `flyway_schema_history_ai_pricing`). Não existe mais `seedgrid.ai-pricing.migration.enabled`.
|
|
55
58
|
|
|
56
59
|
## 3. Propriedades de frameworks
|
|
57
60
|
|
|
@@ -59,8 +62,6 @@ A extension não define nenhuma propriedade de framework: não há `microprofile
|
|
|
59
62
|
|
|
60
63
|
| Propriedade | Recomendação |
|
|
61
64
|
|---|---|
|
|
62
|
-
| `quarkus.flyway.locations` | Incluir `db/migration/ai-pricing` no Flyway nativo, ou ligar `seedgrid.ai-pricing.migration.enabled` nos tenancies. |
|
|
63
|
-
| `quarkus.flyway.table` | Os testes usam `flyway_schema_history_ai_pricing` (o mesmo nome do runner dos tenancies). |
|
|
64
65
|
| `quarkus.hibernate-orm.physical-naming-strategy` | `org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy` (as entidades são camelCase e as colunas snake_case). |
|
|
65
66
|
| `quarkus.hibernate-orm.<pu>.packages` | Mapear `br.com.seedgrid.aipricing.entities` na PU configurada. No subdomain-tenancy, só em master (README). |
|
|
66
67
|
|
|
@@ -68,26 +69,18 @@ A extension não define nenhuma propriedade de framework: não há `microprofile
|
|
|
68
69
|
|
|
69
70
|
Arquivo `integration-tests/src/test/resources/application.properties`:
|
|
70
71
|
- `quarkus.devservices.enabled=false`
|
|
71
|
-
- `quarkus.flyway.migrate-at-start=true`
|
|
72
|
-
- `quarkus.flyway.locations=db/migration/ai-pricing`
|
|
73
|
-
- `quarkus.flyway.table=flyway_schema_history_ai_pricing`
|
|
74
|
-
- `quarkus.flyway.baseline-on-migrate=true`
|
|
75
72
|
- naming strategy
|
|
76
73
|
- `quarkus.hibernate-orm.schema-management.strategy=none`
|
|
77
74
|
- `quarkus.scheduler.enabled=false`
|
|
78
75
|
- `quarkus.http.test-port=0`
|
|
79
76
|
|
|
80
|
-
O `ModuloDesligadoTest`
|
|
77
|
+
Sem Flyway nativo: a própria extension migra. O `ModuloDesligadoTest` usa `seedgrid.ai-pricing.enabled=false` via `QuarkusTestProfile`.
|
|
81
78
|
|
|
82
79
|
## 5. Aliases, obsoletas e renomeações
|
|
83
80
|
Não encontradas. O prefixo duplo (`seedgrid.ai-pricing` contra `seedgrid.app.ai-pricing`) é uma inconsistência, não um alias.
|
|
84
81
|
|
|
85
82
|
## 6. Configuração mínima
|
|
86
|
-
Nenhuma propriedade é obrigatória
|
|
87
|
-
|
|
88
|
-
```properties
|
|
89
|
-
seedgrid.ai-pricing.migration.enabled=true
|
|
90
|
-
```
|
|
83
|
+
Nenhuma propriedade é obrigatória: colocou a extension, ela migra.
|
|
91
84
|
|
|
92
85
|
O robô só funciona com um bean `AiPriceExtractor` do host (ver [[SeedGrid/Extensions/ai-pricing/Exemplos|Exemplos]]).
|
|
93
86
|
|
|
@@ -104,8 +97,8 @@ seedgrid.app.ai-pricing.timezone=America/Sao_Paulo
|
|
|
104
97
|
# Default https://developers.openai.com/api/docs/pricing
|
|
105
98
|
#seedgrid.app.ai-pricing.source-url=https://<pagina-de-precos>
|
|
106
99
|
|
|
107
|
-
#
|
|
108
|
-
seedgrid.ai-pricing.
|
|
100
|
+
# Liga/desliga o módulo (migrations, robô e rotas). Default true.
|
|
101
|
+
#seedgrid.ai-pricing.enabled=true
|
|
109
102
|
```
|
|
110
103
|
|
|
111
104
|
## 8. Receitas
|
|
@@ -90,8 +90,8 @@ Para cadastrar um modelo, `POST /admin/ai/models` recebe `{ "provider": "openai"
|
|
|
90
90
|
## 5. Configuração por tenancy
|
|
91
91
|
|
|
92
92
|
```properties
|
|
93
|
-
# login-tenancy / subdomain-tenancy:
|
|
94
|
-
seedgrid.ai-pricing.
|
|
93
|
+
# login-tenancy / subdomain-tenancy: a tenancy migra (V900–V903); o toggle é do módulo, default true
|
|
94
|
+
#seedgrid.login-tenancy.modules.ai-pricing.enabled=true
|
|
95
95
|
# subdomain-tenancy já define:
|
|
96
96
|
# seedgrid.ai-pricing.persistence-unit=master
|
|
97
97
|
```
|
|
@@ -18,7 +18,7 @@ Mantém o catálogo de modelos de LLM e o histórico de preços por 1M de tokens
|
|
|
18
18
|
|
|
19
19
|
| Módulo | Artefato |
|
|
20
20
|
|---|---|
|
|
21
|
-
| parent | `br.com.seedgrid:seedgrid-ai-pricing-parent:2026.10.
|
|
21
|
+
| parent | `br.com.seedgrid:seedgrid-ai-pricing-parent:2026.10.16` (parent `seedgrid-parent:2026.07.02`) |
|
|
22
22
|
| runtime | `br.com.seedgrid:seedgrid-ai-pricing` |
|
|
23
23
|
| deployment | `br.com.seedgrid:seedgrid-ai-pricing-deployment` |
|
|
24
24
|
| integration-tests | não publicado |
|
|
@@ -94,7 +94,7 @@ Declarados em `AiPricingNotificationCatalog`:
|
|
|
94
94
|
| V902 | seed de modelos OpenAI (`gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-5.1`) e da config do robô (ligado, cron `0 0 6 * * ?`, `source_url` = página de preços da OpenAI) |
|
|
95
95
|
| V903 | coluna `active` |
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
A extension migra sozinha o datasource default na subida (sem flag). Nas tenancy, quem migra é a tenancy (master do subdomain-tenancy; banco único do login-tenancy), com o toggle `modules.ai-pricing.enabled` (default `true`). Ver [[SeedGrid/Extensions/ai-pricing/Configuracao|Configuração]].
|
|
98
98
|
|
|
99
99
|
## Testes (não executados)
|
|
100
100
|
- `runtime/src/test`:
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, business-days, quarkus]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-business-days
|
|
4
|
+
branch: (repositório ainda não criado)
|
|
5
|
+
commit: —
|
|
6
|
+
analisado-em: 2026-10-16
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Business days: configuração
|
|
10
|
+
|
|
11
|
+
| Propriedade | Padrão | Efeito |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `seedgrid.business-days.enabled` | `true` (env `SEEDGRID_BUSINESS_DAYS_ENABLED`) | Liga/desliga o módulo: desligado = sem migrations e rotas 404 (e fora do OpenAPI). |
|
|
14
|
+
| `seedgrid.business-days.persistence-unit` | PU default | PU das tabelas. Vazio ou `<default>` = default. |
|
|
15
|
+
| `seedgrid.business-days.max-range-days` | `36600` (env `SEEDGRID_BUSINESS_DAYS_MAX_RANGE_DAYS`) | Teto de dias nas consultas de intervalo. |
|
|
16
|
+
| `seedgrid.migrations.host-managed` | `false` | Definido pelas tenancy: o runner da extension não age, a tenancy migra cada banco. |
|
|
17
|
+
|
|
18
|
+
Mapear `br.com.seedgrid.businessdays.entities` na PU configurada (no subdomain-tenancy, na PU default; sem `packages` explícito o Quarkus já indexa).
|
|
19
|
+
|
|
20
|
+
## Nas tenancy
|
|
21
|
+
|
|
22
|
+
| Host | Toggle | Onde migra |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| login-tenancy | `seedgrid.login-tenancy.modules.business-days.enabled` (default `true`) | banco único, depois do security |
|
|
25
|
+
| subdomain-tenancy | `seedgrid.subdomain-tenancy.modules.business-days.enabled` (default `true`) | master e cada tenant. Tenants já `READY`: mudar `migration.target-version` para aplicar o schema novo |
|
|
26
|
+
|
|
27
|
+
Host que mantém calendário próprio (ex.: seedgrid-report) desliga: `seedgrid.login-tenancy.modules.business-days.enabled=false`.
|
|
28
|
+
|
|
29
|
+
## Mínima
|
|
30
|
+
|
|
31
|
+
Nenhuma propriedade é obrigatória: colocou a extension, ela migra.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Veja também
|
|
35
|
+
|
|
36
|
+
[[SeedGrid/Extensions/business-days/Visao-geral|Visão geral]] · [[SeedGrid/Extensions/Catalogo-de-propriedades|Catálogo de propriedades]] · [[SeedGrid/Extensions/Indice|Índice das extensions]]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, business-days, quarkus]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-business-days
|
|
4
|
+
branch: (repositório ainda não criado)
|
|
5
|
+
commit: —
|
|
6
|
+
analisado-em: 2026-10-16
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Business days: exemplos
|
|
10
|
+
|
|
11
|
+
## Usar o cálculo em código
|
|
12
|
+
|
|
13
|
+
```java
|
|
14
|
+
@Inject BusinessDayService service;
|
|
15
|
+
|
|
16
|
+
boolean util = service.isBusinessDay(LocalDate.of(2026, 12, 25));
|
|
17
|
+
LocalDate vencimento = service.addBusinessDays(LocalDate.of(2026, 10, 1), 5);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`BusinessCalendar` (pacote `utils`) é imutável e sem CDI/JPA: dá para montá-lo e testar sem Quarkus.
|
|
21
|
+
|
|
22
|
+
## Cadastrar um feriado da empresa
|
|
23
|
+
|
|
24
|
+
`POST /business-days/holidays` com `{ "name": "Aniversário da cidade", "month": 3, "day": 19, "year": null, "active": true }`. Com `year` preenchido o feriado vale só naquele ano (ex.: ponte).
|
|
25
|
+
|
|
26
|
+
## Semana de trabalho
|
|
27
|
+
|
|
28
|
+
`PUT /business-days/week-profile` com os sete dias, peso `1`, `0.5` ou `0`. `DELETE` volta ao padrão herdado (global ou segunda a sexta).
|
|
29
|
+
|
|
30
|
+
## Host sem tenancy
|
|
31
|
+
|
|
32
|
+
Basta a dependência `br.com.seedgrid:seedgrid-business-days`; a extension migra o datasource default e expõe as rotas.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Veja também
|
|
36
|
+
|
|
37
|
+
[[SeedGrid/Extensions/business-days/Visao-geral|Visão geral]] · [[SeedGrid/Extensions/Catalogo-de-propriedades|Catálogo de propriedades]] · [[SeedGrid/Extensions/Indice|Índice das extensions]]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, business-days, quarkus]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-business-days
|
|
4
|
+
branch: (repositório ainda não criado)
|
|
5
|
+
commit: —
|
|
6
|
+
analisado-em: 2026-10-16
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Business days (Quarkus): visão geral
|
|
10
|
+
|
|
11
|
+
Calendário de dias úteis para hosts Quarkus: **feriados** (recorrentes ou de um ano específico), **semana de trabalho** (peso 0 / 0,5 / 1 por dia da semana) e cálculo de dias úteis (é dia útil?, contar, somar pesos, andar N dias úteis). Tabelas próprias (`business_day_*`), JPA puro (sem Panache).
|
|
12
|
+
|
|
13
|
+
- Configuração: [[SeedGrid/Extensions/business-days/Configuracao|Configuração do business-days]]
|
|
14
|
+
- Exemplos: [[SeedGrid/Extensions/business-days/Exemplos|Exemplos do business-days]]
|
|
15
|
+
|
|
16
|
+
## Módulos e coordenadas
|
|
17
|
+
|
|
18
|
+
| Módulo | Artefato |
|
|
19
|
+
|---|---|
|
|
20
|
+
| parent | `br.com.seedgrid:seedgrid-business-days-parent:2026.10.15` (parent `seedgrid-parent:2026.07.02`) |
|
|
21
|
+
| runtime | `br.com.seedgrid:seedgrid-business-days` |
|
|
22
|
+
| deployment | `br.com.seedgrid:seedgrid-business-days-deployment` |
|
|
23
|
+
| integration-tests | não publicado (Testcontainers Postgres) |
|
|
24
|
+
|
|
25
|
+
`seedgrid-security` é dependência **`provided`**: a extension funciona sozinha. Com a security no classpath o escopo é a **empresa corrente do token** (`SecurityBusinessDaysScopeProvider`, registrado pelo deployment só nesse caso); sem ela vale um calendário **global** (`GlobalBusinessDaysScopeProvider`). Para outro escopo, o host fornece a sua `BusinessDaysScopeProvider`.
|
|
26
|
+
|
|
27
|
+
## Modelo
|
|
28
|
+
|
|
29
|
+
- Dia útil = peso do dia da semana > 0 e não ser feriado (feriado zera o dia).
|
|
30
|
+
- Feriado com `year` nulo repete todo ano; com `year` vale só naquele ano.
|
|
31
|
+
- `company_id` nulo = feriado/perfil **global** (não é FK, a extension não depende da security). A empresa vê globais + os dela, mas só altera os dela.
|
|
32
|
+
- Perfil da semana: COMPANY > GLOBAL > DEFAULT (segunda a sexta).
|
|
33
|
+
|
|
34
|
+
## Migrations
|
|
35
|
+
|
|
36
|
+
Faixa V1100–V1199, location `db/migration/business-days`, histórico `flyway_schema_history_business_days`.
|
|
37
|
+
|
|
38
|
+
- **Sozinha no host**: colocou a dependência, ela migra o datasource default na subida (`BusinessDaysMigrationRunner`). Sem flag.
|
|
39
|
+
- **Com login-tenancy / subdomain-tenancy**: a tenancy migra (`seedgrid.migrations.host-managed=true` faz o runner não agir). login-tenancy: banco único. subdomain-tenancy: **master e cada tenant**, cada um com o seu calendário (a PU default aponta para o master no domínio do admin e para o tenant nos demais).
|
|
40
|
+
- Toggle: `seedgrid.business-days.enabled` (default `true`); nas tenancy vem de `modules.business-days.enabled`. Desligado = não migra e `/business-days/**` responde 404.
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
`/business-days/holidays` (CRUD), `/business-days/week-profile` (GET/PUT/DELETE), `/business-days/calendar?year&month`, `/check?date`, `/count?from&to`, `/add?from&days`. Permissões `BUSINESS_DAY_READ/CREATE/UPDATE/DELETE` (sem audience, vinculadas ao ADMIN pela V1101).
|
|
45
|
+
|
|
46
|
+
## Front nos boilerplates
|
|
47
|
+
|
|
48
|
+
Menu **Dias úteis** (`/dias-uteis/*`): feriados (lista e edição), semana de trabalho e calendário; proxy em `app/api/business-days/[...path]`.
|
|
@@ -51,11 +51,14 @@ Variáveis de ambiente pela regra MP, sem ambiguidade:
|
|
|
51
51
|
|
|
52
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
53
|
|
|
54
|
-
### 2.3
|
|
54
|
+
### 2.3 Toggle do módulo
|
|
55
55
|
|
|
56
|
-
| Propriedade |
|
|
57
|
-
|
|
58
|
-
| `seedgrid.exchange.
|
|
56
|
+
| Propriedade | Padrão | Efeito |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `seedgrid.exchange.enabled` | `true` | `false`: sem migrations, sem scheduler e as rotas `/admin/exchange-rate`, `/admin/currencies` e `/admin/currency-exchange-rates` respondem 404. Nas tenancy o default vem de `seedgrid.<tenancy>.modules.exchange.enabled`. |
|
|
59
|
+
| `seedgrid.migrations.host-managed` | `false` | `true` (definido pelas tenancy): o runner da extension não age; a tenancy migra cada banco. |
|
|
60
|
+
|
|
61
|
+
A extension **sempre migra** o datasource default na subida (`ExchangeMigrationRunner`, histórico `flyway_schema_history_exchange`). Não existe mais `seedgrid.exchange.migration.enabled`.
|
|
59
62
|
|
|
60
63
|
## 3. Propriedades de frameworks
|
|
61
64
|
|
|
@@ -63,7 +66,6 @@ A extension não define nenhuma. Recomendações extraídas do `integration-test
|
|
|
63
66
|
|
|
64
67
|
| Propriedade | Recomendação |
|
|
65
68
|
|---|---|
|
|
66
|
-
| `quarkus.flyway.locations` / `quarkus.flyway.table` | `db/migration/exchange` / `flyway_schema_history_exchange` (Flyway nativo). Nos tenancies, use `seedgrid.exchange.migration.enabled`. |
|
|
67
69
|
| `quarkus.hibernate-orm.physical-naming-strategy` | `org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy` |
|
|
68
70
|
| `quarkus.hibernate-orm.<pu>.packages` | Incluir `br.com.seedgrid.exchange.entities` na PU configurada (no subdomain-tenancy, só master). |
|
|
69
71
|
| `quarkus.scheduler.enabled` | Os testes usam `false` para controlar os disparos. Em produção, deixe ligado. |
|
|
@@ -72,10 +74,6 @@ A extension não define nenhuma. Recomendações extraídas do `integration-test
|
|
|
72
74
|
|
|
73
75
|
Arquivo `integration-tests/src/test/resources/application.properties`:
|
|
74
76
|
- `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
77
|
- naming strategy
|
|
80
78
|
- `quarkus.hibernate-orm.schema-management.strategy=none`
|
|
81
79
|
- `quarkus.scheduler.enabled=false`
|
|
@@ -86,11 +84,7 @@ Arquivo `integration-tests/src/test/resources/application.properties`:
|
|
|
86
84
|
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
85
|
|
|
88
86
|
## 6. Configuração mínima
|
|
89
|
-
Nenhuma propriedade é obrigatória
|
|
90
|
-
|
|
91
|
-
```properties
|
|
92
|
-
seedgrid.exchange.migration.enabled=true
|
|
93
|
-
```
|
|
87
|
+
Nenhuma propriedade é obrigatória: colocou a extension, ela migra.
|
|
94
88
|
|
|
95
89
|
## 7. Configuração completa comentada
|
|
96
90
|
|
|
@@ -102,8 +96,8 @@ seedgrid.exchange.migration.enabled=true
|
|
|
102
96
|
# Default America/Sao_Paulo.
|
|
103
97
|
seedgrid.app.business-timezone=America/Sao_Paulo
|
|
104
98
|
|
|
105
|
-
# (
|
|
106
|
-
seedgrid.exchange.
|
|
99
|
+
# Liga/desliga o módulo (migrations, scheduler e rotas). Default true.
|
|
100
|
+
#seedgrid.exchange.enabled=true
|
|
107
101
|
```
|
|
108
102
|
|
|
109
103
|
## 8. Receitas
|
|
@@ -22,7 +22,7 @@ Fonte: README.
|
|
|
22
22
|
</dependency>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Security e audit-core vêm do host.
|
|
25
|
+
Security e audit-core vêm do host. A extension migra sozinha; nas tenancy o toggle é `modules.exchange.enabled` (default `true`).
|
|
26
26
|
|
|
27
27
|
## 2. Cadastrar uma moeda com fonte PTAX
|
|
28
28
|
|
|
@@ -76,7 +76,7 @@ POST /admin/currency-exchange-rates/{publicId}/retry
|
|
|
76
76
|
## 5. Configuração (properties)
|
|
77
77
|
|
|
78
78
|
```properties
|
|
79
|
-
seedgrid.exchange.
|
|
79
|
+
#seedgrid.login-tenancy.modules.exchange.enabled=true # tenancies (default true)
|
|
80
80
|
#seedgrid.exchange.persistence-unit=master # subdomain-tenancy já define
|
|
81
81
|
seedgrid.app.business-timezone=America/Sao_Paulo # fuso dos avisos
|
|
82
82
|
```
|
|
@@ -18,7 +18,7 @@ Câmbio para hosts Quarkus. Mantém moedas e cotações diárias, com histórico
|
|
|
18
18
|
|
|
19
19
|
| Módulo | Artefato |
|
|
20
20
|
|---|---|
|
|
21
|
-
| parent | `br.com.seedgrid:seedgrid-exchange-parent:2026.10.
|
|
21
|
+
| parent | `br.com.seedgrid:seedgrid-exchange-parent:2026.10.16` (parent `seedgrid-parent:2026.07.02`) |
|
|
22
22
|
| runtime | `br.com.seedgrid:seedgrid-exchange` |
|
|
23
23
|
| deployment | `br.com.seedgrid:seedgrid-exchange-deployment` |
|
|
24
24
|
| integration-tests | não publicado |
|
|
@@ -106,7 +106,7 @@ Os `{id}` são `publicId`. **Confirmado** nos resources.
|
|
|
106
106
|
| V803 | histórico PTAX sem `$select` |
|
|
107
107
|
| V804 | `currency_exchange_rates.active` |
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
A extension migra sozinha o datasource default na subida (sem flag). Nas tenancy, quem migra é a tenancy (master do subdomain-tenancy; banco único do login-tenancy), com o toggle `modules.exchange.enabled` (default `true`).
|
|
110
110
|
|
|
111
111
|
## Testes (não executados)
|
|
112
112
|
- `runtime/src/test`: `CurrencyRateNotificationTest`, `CurrencySourceResolverTest` e `ExchangeNotificationCatalogTest`.
|
|
@@ -70,8 +70,6 @@ Total `seedgrid.login-tenancy.*`: **13 propriedades**.
|
|
|
70
70
|
|---|---|---|---|---|---|---|---|---|---|
|
|
71
71
|
| `seedgrid.audit.mongodb.database` | `Optional<String>` | nome de banco Mongo | — (deriva `<app.code>_audit_db`, ou `audit_db`) | Não | Override do banco Mongo de auditoria produzido pela foundation (banco único). | Audit MongoDB | Só existe bean se o Mongo estiver no classpath; conexão via `seedgrid.audit.mongodb.connection-string` (módulo audit — ver [[SeedGrid/Extensions/audit/Configuracao|audit]]) | Runtime | `LoginTenancyMongoAuditDatabaseProducer#auditDatabase` |
|
|
72
72
|
| `seedgrid.audit.persistence.strategy` | `Optional<String>` | `jpa` (case-insensitive) habilita | — | Condicional (sem `jpa`, a migration de audit é pulada) | Decide se as migrations `db/migration/audit` rodam. | Orquestração | Chave do módulo audit | Runtime | `LoginTenancyMigrationService#isAuditJpa` |
|
|
73
|
-
| `seedgrid.ai-pricing.migration.enabled` | `boolean` | `true`/`false` | `false` | Não | Roda `classpath:db/migration/ai-pricing` com `flyway_schema_history_ai_pricing`. | Hosts com ai-pricing | Mesma chave lida pelo `MigrationService` do subdomain-tenancy | Runtime | `LoginTenancyMigrationService#aiPricingMigrationsEnabled` |
|
|
74
|
-
| `seedgrid.exchange.migration.enabled` | `boolean` | `true`/`false` | `false` | Não | Roda `classpath:db/migration/exchange` com `flyway_schema_history_exchange`. | Hosts com exchange | Idem | Runtime | `LoginTenancyMigrationService#exchangeMigrationsEnabled` |
|
|
75
73
|
| `seedgrid.security.first-admin-user.email` | `Optional<String>` | e-mail | — | Não | Só lida para decidir logs/WARN e `firstAdminConfigured` no status. | Coordenação | Ver [[SeedGrid/Extensions/security/Configuracao|security]] | Runtime | `LoginTenancyBootstrapService`, `LoginTenancySecurityBridge` |
|
|
76
74
|
| `seedgrid.security.jwt.issuer` | `Optional<String>` | URL/issuer | — | Não | Exibido em `security.jwtIssuer` no status. | Informativo | security | Runtime | `LoginTenancySecurityBridge` |
|
|
77
75
|
| `seedgrid.show-dev-message` | `boolean` | `true`/`false` | `false` | Não | Inclui `devMessage` nos problem+json das exceções da login-tenancy. | Depuração | Mesma chave usada por security e billing | Runtime | `LoginTenancyApiExceptionExtension` (construtor) |
|
|
@@ -171,9 +169,10 @@ seedgrid.login-tenancy.modules.billing.enabled=true
|
|
|
171
169
|
seedgrid.login-tenancy.modules.apikeys.enabled=true
|
|
172
170
|
seedgrid.login-tenancy.modules.backup.enabled=true
|
|
173
171
|
seedgrid.login-tenancy.modules.filemanagement.enabled=true
|
|
174
|
-
#
|
|
175
|
-
seedgrid.ai-pricing.
|
|
176
|
-
seedgrid.exchange.
|
|
172
|
+
# Modulos de produto (default true): desligado = nao migra e as rotas respondem 404
|
|
173
|
+
seedgrid.login-tenancy.modules.ai-pricing.enabled=true
|
|
174
|
+
seedgrid.login-tenancy.modules.exchange.enabled=true
|
|
175
|
+
seedgrid.login-tenancy.modules.business-days.enabled=true
|
|
177
176
|
# Auditoria
|
|
178
177
|
seedgrid.audit.persistence.strategy=jpa
|
|
179
178
|
#seedgrid.audit.mongodb.database=<banco-de-auditoria>
|
|
@@ -66,7 +66,7 @@ flowchart LR
|
|
|
66
66
|
BI -- on --> BL[billing] --> AK
|
|
67
67
|
BI -- off --> AK{modules.apikeys}
|
|
68
68
|
AK -- on --> AP[apikeys] --> X
|
|
69
|
-
AK -- off --> X{ai-pricing / exchange<br/>
|
|
69
|
+
AK -- off --> X{ai-pricing / exchange / business-days<br/>modules.*.enabled}
|
|
70
70
|
X --> LT[login-tenancy<br/>V700-V703] --> APP["app (database.locations)<br/>flyway_schema_history"]
|
|
71
71
|
```
|
|
72
72
|
|
|
@@ -176,8 +176,9 @@ As chaves têm efeito via ponte do `MPC` para o mailer nomeado `quarkus.mailer."
|
|
|
176
176
|
| Propriedade | Padrão no consumo | Efeito aqui | Origem |
|
|
177
177
|
|---|---|---|---|
|
|
178
178
|
| `seedgrid.audit.persistence.strategy` | `—` | Só com `jpa` (case-insensitive) roda `db/migration/audit` no master e nos tenants | `RT/flyway/Migrations#migrateAuditSchema` |
|
|
179
|
-
| `seedgrid.ai-pricing.
|
|
180
|
-
| `seedgrid.exchange.
|
|
179
|
+
| `seedgrid.subdomain-tenancy.modules.ai-pricing.enabled` | `true` | Migra `db/migration/ai-pricing` no master; desligado = não migra e as rotas respondem 404 | `RT/flyway/Migrations` |
|
|
180
|
+
| `seedgrid.subdomain-tenancy.modules.exchange.enabled` | `true` | Idem para `db/migration/exchange` (master) | `RT/flyway/Migrations` |
|
|
181
|
+
| `seedgrid.subdomain-tenancy.modules.business-days.enabled` | `true` | Migra `db/migration/business-days` no master **e em cada tenant** (cada um com o seu calendário) | `RT/flyway/Migrations` |
|
|
181
182
|
| `quarkus.mongodb.database` | `default_db` | Sufixo dos bancos Mongo por tenant no `MongoTenantResolverImpl` | `RT/mongodb/MongoTenantResolverImpl` |
|
|
182
183
|
| `seedgrid.ratelimit.{tenant-signup\|tenant-validate-email\|tenant-resend-email}.{permits\|window\|enabled}` | anotação: 100/1 min, 10/1 min, 5/1 h; `enabled=true` | Overrides do `@SeedGridRateLimit` nos endpoints públicos (resilience) | `RT/controllers/TenantSignupController`; `java/seedgrid-quarkus-ext-resilience/.../SeedGridRateLimit.java` (Javadoc) |
|
|
183
184
|
| `seedgrid.security.frontend.base-url` | (do security) | Base dos links de e-mail; `TenantSecurityLinks` insere `<tenant>.` no host em contexto de tenant | `RT/security/TenantSecurityLinks` (via `SecurityFrontendConfig`) |
|
|
@@ -72,8 +72,8 @@ flowchart LR
|
|
|
72
72
|
- **Resolução** (Confirmado): `TenantResolutionFilter` lê `X-Forwarded-Host` (prioritário) ou `Host`, extrai o tenant com `TenantHostExtractor` e grava no `TenantContext` e no MDC (`tenantId`); sem tenant → `master`. O Javadoc do filtro deixa explícito que o default para `master` **não** é fronteira de segurança: o isolamento vem do JWT/API key serem resolvidos no banco do próprio tenant.
|
|
73
73
|
- **JWT**: `SubdomainTenancyJwtTokenCustomizer` adiciona as claims `subdomain` e `audience` (`platform`/`client`); `SubdomainTenancyJwtTokenValidator` rejeita token cujo `subdomain` difere do host.
|
|
74
74
|
- **Conexões**: `TenantConnectionResolverImpl` verifica no master se o tenant existe e está ativo (`TenantNotFoundException` caso contrário), cria `SimpleDriverDataSource` por tenant, aplica limite/evicção e circuit breaker. Detalhes dos parâmetros em [[SeedGrid/Extensions/subdomain-tenancy/Configuracao|Configuração]].
|
|
75
|
-
- **Startup** (`MigrationService#onStart`, `@Priority(APPLICATION)`): no master roda, em ordem, security → audit (se `jpa`) → backup → billing → apikeys → ai-pricing
|
|
76
|
-
- **Signup → provisionamento**: `POST /public/tenants` grava o tenant pendente e envia OTP; `POST /public/tenants/validate-email` valida o código e chama `TenantProvisioningService#createTenantWithAdmin` (lock local + `pg_try_advisory_lock`, `CREATE DATABASE` idempotente, migrations security → tenant → audit → backup → apikeys, usuário root; rollback com `DROP DATABASE` se o banco foi criado no fluxo), depois `SubdomainBillingAccounts#ensureFor` (conta + trial no billing) e ativa o tenant.
|
|
75
|
+
- **Startup** (`MigrationService#onStart`, `@Priority(APPLICATION)`): no master roda, em ordem, security → audit (se `jpa`) → backup → billing → apikeys → ai-pricing → exchange → business-days (módulos de produto, `modules.<x>.enabled`, default `true`) → subdomain-tenancy → `db/migration/master` (+ additional), depois `AdminUserBootstrapService#seedAdminUserIfNeeded`. Tenants não migram no boot por padrão.
|
|
76
|
+
- **Signup → provisionamento**: `POST /public/tenants` grava o tenant pendente e envia OTP; `POST /public/tenants/validate-email` valida o código e chama `TenantProvisioningService#createTenantWithAdmin` (lock local + `pg_try_advisory_lock`, `CREATE DATABASE` idempotente, migrations security → tenant → audit → backup → apikeys → business-days, usuário root; rollback com `DROP DATABASE` se o banco foi criado no fluxo), depois `SubdomainBillingAccounts#ensureFor` (conta + trial no billing) e ativa o tenant.
|
|
77
77
|
- **Migração por tenant**: `TenantMigrationCoordinator` com estado em `tenant_migration_state` (`PENDING`/`MIGRATING`/`READY`/`FAILED`), lock com fencing token e heartbeat. Gatilhos: login (gate devolve `503` + `Retry-After: 15`), endpoint manual, ou boot.
|
|
78
78
|
- **Limpeza**: `TenantCleanupScheduler` remove do master os cadastros não validados mais velhos que o TTL (não remove o banco — ver Limitações).
|
|
79
79
|
|
|
@@ -25,6 +25,7 @@ Estado na análise (2026-10-14): todos na branch `main` e **sem alterações loc
|
|
|
25
25
|
| `seedgrid-quarkus-ext-billing` | Extension (core + stripe) | 2026.10.14 | `ba38efc347` | 2026-10-14 | [[SeedGrid/Extensions/billing/Visao-geral\|billing]] |
|
|
26
26
|
| `seedgrid-quarkus-ext-ai-pricing` | Extension | 2026.10.13 | `0608ca66b5` | 2026-10-13 | [[SeedGrid/Extensions/ai-pricing/Visao-geral\|ai-pricing]] |
|
|
27
27
|
| `seedgrid-quarkus-ext-exchange` | Extension | 2026.10.13 | `30f1fd6005` | 2026-10-13 | [[SeedGrid/Extensions/exchange/Visao-geral\|exchange]] |
|
|
28
|
+
| `seedgrid-quarkus-ext-business-days` | Extension (repositório ainda não criado) | 2026.10.15 | — | 2026-10-16 | [[SeedGrid/Extensions/business-days/Visao-geral|business-days]] |
|
|
28
29
|
| `seedgrid-quarkus-ext-audit` | Extension (core + postgresql + mongodb) | 2026.09.25 | `d5bf32e509` | 2026-09-25 | [[SeedGrid/Extensions/audit/Visao-geral\|audit]] |
|
|
29
30
|
| `seedgrid-quarkus-ext-backup` | Extension | 2026.10.09 | `3bed4075ea` | 2026-10-10 | [[SeedGrid/Extensions/backup/Visao-geral\|backup]] |
|
|
30
31
|
| `seedgrid-quarkus-ext-notification` | Extension (+ `api`) | 2026.10.15 | `3d00bee` | 2026-10-15 | [[SeedGrid/Extensions/notification/Visao-geral\|notification]] |
|
|
@@ -64,6 +65,14 @@ Documentação: [[SeedGrid/SeedGrid-components/Indice|Índice dos componentes]].
|
|
|
64
65
|
|
|
65
66
|
`front/next-projects/` contém apenas documentação de padrões/decisões (sem código) e não foi analisado.
|
|
66
67
|
|
|
68
|
+
### Produtos (`seedgrid-products/`)
|
|
69
|
+
|
|
70
|
+
Fora de `seedgrid-platform`; consomem as crates/extensions acima.
|
|
71
|
+
|
|
72
|
+
| Repositório | Tipo | Versão | Commit | Consome | Nota |
|
|
73
|
+
|---|---|---|---|---|---|
|
|
74
|
+
| `seedgrid-pulse` | Produto (servidor Rust + UI Next.js + SDKs) | 0.3.0 (servidor e UI) | `9dcbdad` | crates `security`, `login-tenancy`, `audit`, `apikeys`, `broker-*` (por path dependency) | [[SeedGrid/Produtos/Pulse/Visao-geral\|Pulse]] |
|
|
75
|
+
|
|
67
76
|
## Dependências entre módulos Java
|
|
68
77
|
|
|
69
78
|
Extraído dos `pom.xml` (excluindo `deployment` e `integration-tests`). Escopo `compile` salvo indicação.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, produto, pulse, autenticacao, chaves, seguranca]
|
|
3
|
+
fonte: seedgrid-products/seedgrid-pulse (backend/env.md, backend/PROTOCOL.md, migrations)
|
|
4
|
+
branch: main
|
|
5
|
+
commit: 9dcbdad
|
|
6
|
+
analisado-em: 2026-10-16
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Pulse — autenticação, chaves e permissions
|
|
10
|
+
|
|
11
|
+
O Pulse tem **credenciais distintas para atores distintos**. Elas nunca se substituem; mandar a errada é o erro mais comum de integração.
|
|
12
|
+
|
|
13
|
+
Voltar: [[SeedGrid/Produtos/Pulse/Visao-geral|Visão geral]]
|
|
14
|
+
|
|
15
|
+
## Quem usa o quê
|
|
16
|
+
|
|
17
|
+
| Ator | Credencial | Como envia | Serve para |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| **Backend de produto** (publica) | chave de conta **`project`** (`pulsek_…`) 🔒 | `x-api-key` ou `Authorization: Bearer` | publicar **só na conta da chave** e emitir token curto. **Não conecta** no WebSocket |
|
|
20
|
+
| **Navegador / app** (recebe) | **token curto** `pct_…` | `?access_token=` ou subprotocolo | conectar como **um usuário** (`subject`) da conta |
|
|
21
|
+
| **Agente instalado / serviço** (recebe) | chave de conta **`client`** 🔒 (com ou sem `subject`) | header, `?access_token=` ou subprotocolo | conectar como a conta (e, com `subject`, como um usuário). **Não publica** (403) |
|
|
22
|
+
| **Operação do Pulse** | `SEEDGRID_PULSE_SERVER_KEY` 🔒 | `x-api-key` | gerenciar contas/chaves e métricas. **Não publica** (403) |
|
|
23
|
+
| **Operador humano** (UI) | JWT do `security` | `Authorization: Bearer` | telas por **permission**; publica em qualquer conta com `PULSE_MESSAGE_PUBLISH` informando `accountId` |
|
|
24
|
+
|
|
25
|
+
Regras que mordem:
|
|
26
|
+
|
|
27
|
+
- O `kind` da chave (`project` \| `client`) é **obrigatório na emissão** e preservado na rotação. Chave `project` não tem `subject` (422).
|
|
28
|
+
- Quem publica é decidido pelo **`kind`**, não pelo `subject`.
|
|
29
|
+
- A chave de servidor **não vai para produto nenhum**.
|
|
30
|
+
- Chave `project` **nunca no navegador** nem em app distribuído.
|
|
31
|
+
|
|
32
|
+
## Contas e chaves
|
|
33
|
+
|
|
34
|
+
- **Conta** = fronteira de isolamento (entrega e replay nunca cruzam contas). Um produto ↔ uma ou mais contas.
|
|
35
|
+
- Criar chave: UI **Contas → conta → Chaves → Nova chave**, ou `POST /api/v1/accounts/{id}/keys` com `{ "name", "kind", "subject"? }`.
|
|
36
|
+
- O **segredo aparece uma vez** (UI com botão de copiar; API no campo `secret`). Depois só resta o prefixo (`keyPrefix`). Perdeu → **rotacionar** (`POST /accounts/{id}/keys/{keyId}/rotate`).
|
|
37
|
+
- A chave vive no banco (por conta, revogável, rotacionável); o banco guarda hash + prefixo. Revogar/rotacionar uma chave `client` ou revogar a conta derruba as conexões dela **na hora**, em todas as instâncias (fecha com `4403`).
|
|
38
|
+
- **Revogar** é conceito da **chave**. A **conta** não se revoga: vai para a **lixeira de contas** e depois é apagada (ver [[SeedGrid/Produtos/Pulse/Servidor/Operacao|Operação]]).
|
|
39
|
+
|
|
40
|
+
### O `subject` da chave
|
|
41
|
+
|
|
42
|
+
Definido na emissão e **imutável** (rotação preserva). É o `user` do protocolo. Use um id estável e não-PII (`usr_7f3a9c1e`, `agent:<uuid>`): nunca e-mail nem hostname. Sem `subject` = credencial de serviço (sem `user`, sem grupo implícito).
|
|
43
|
+
|
|
44
|
+
## Token curto de conexão (cliente sem segredo)
|
|
45
|
+
|
|
46
|
+
O cliente nunca recebe chave. O **backend do produto**, com a chave `project`, pede um token para o usuário **da sessão** e devolve só o token:
|
|
47
|
+
|
|
48
|
+
```http
|
|
49
|
+
POST /api/v1/connect-tokens
|
|
50
|
+
x-api-key: <chave project>
|
|
51
|
+
|
|
52
|
+
{ "subject": "<publicId da sessão>", "ttlSeconds": 300, "channels": ["orders"] }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{ "token": "pct_…", "expiresAt": 1791205500, "connectUrl": "wss://…/api/v1/connect" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `subject`: **da sessão, nunca de parâmetro do request** (senão um usuário pede token em nome de outro).
|
|
60
|
+
- `ttlSeconds` (padrão 300, teto 900): janela para **conectar**. A conexão aberta segue depois do vencimento até cair ou a credencial ser revogada.
|
|
61
|
+
- `channels` (opcional): restringe o que pode assinar (`channel_not_allowed` fora disso).
|
|
62
|
+
- `connectUrl` só vem se `SEEDGRID_PULSE_PUBLIC_WS_URL` estiver configurada.
|
|
63
|
+
- Erros: 401 chave inválida · 403 chave `client`/de servidor · 422 validação · 429 limite (com `Retry-After`) · 503 sem `SEEDGRID_PULSE_CONNECT_TOKEN_SECRET`.
|
|
64
|
+
- O token é assinado (HMAC-SHA256). Revogar a chave `project` que o emitiu ou a conta o invalida.
|
|
65
|
+
- Os SDKs subscriber pedem token a **cada (re)conexão** via `getToken`.
|
|
66
|
+
|
|
67
|
+
## Operador humano: JWT e permissions
|
|
68
|
+
|
|
69
|
+
Login pelo `security` (JWT RS256, 2FA opcional). Cada endpoint administrativo exige uma **permission** (ou a chave de servidor, para automação). O papel `ADMIN` herda as da migration; outros perfis são configurados em **Segurança → Perfis**.
|
|
70
|
+
|
|
71
|
+
| Grupo | Permissions |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Mensagens | `PULSE_MESSAGE_READ`, `PULSE_MESSAGE_PUBLISH`, `PULSE_MESSAGE_DELETE`, `PULSE_MESSAGE_PURGE` |
|
|
74
|
+
| Pendências / DLQ | `PULSE_BACKLOG_READ`, `PULSE_BACKLOG_DISCARD`, `PULSE_DLQ_READ`, `PULSE_DLQ_REPLAY`, `PULSE_DLQ_CLEAN` |
|
|
75
|
+
| Conexões / métricas / ajustes | `PULSE_CONNECTION_READ`, `PULSE_METRIC_READ`, `PULSE_SETTINGS_READ`, `PULSE_SETTINGS_UPDATE` |
|
|
76
|
+
| Contas | `PULSE_ACCOUNT_READ`, `_CREATE`, `_UPDATE`, `_REVOKE`, `PULSE_ACCOUNT_DELETE`, `PULSE_ACCOUNT_PURGE` |
|
|
77
|
+
| Chaves | `PULSE_KEY_READ`, `_CREATE`, `_ROTATE`, `_REVOKE`, `_PURGE` |
|
|
78
|
+
| Segurança | `PULSE_SECURITY_READ`, `_ADMIN`, `_USER_MANAGE`, `_ROLE_MANAGE` |
|
|
79
|
+
|
|
80
|
+
(Confirmado nas migrations `backend/migrations/tenant/`. As quatro de lixeira vêm da `0012`, concedidas só ao ADMIN; `DELETE` e `PURGE` são separadas de propósito.)
|
|
81
|
+
|
|
82
|
+
**Operações destrutivas**: exigem JWT humano (a chave de servidor recebe 401, pois toda exclusão precisa de autor) e gravam **audit** (quem, o quê, quantos).
|
|
83
|
+
|
|
84
|
+
## Boas práticas
|
|
85
|
+
|
|
86
|
+
- Chave `project` em variável de ambiente/secret do backend; rotacione ao suspeitar de vazamento.
|
|
87
|
+
- Um `subject` por pessoa (id estável), nunca compartilhado entre pessoas.
|
|
88
|
+
- Cliente de navegador/mobile: **sempre** token curto, nunca chave.
|
|
89
|
+
- Exemplos de demo nos repositórios de exemplo usam chaves de demonstração; não as use fora de dev.
|