@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.
Files changed (50) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/shared.js +1 -0
  3. package/docs/formato.md +1 -1
  4. package/package.json +1 -1
  5. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +3 -2
  6. package/seedgridKB/SeedGrid/Extensions/Indice.md +1 -0
  7. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +11 -18
  8. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +2 -2
  9. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +2 -2
  10. package/seedgridKB/SeedGrid/Extensions/business-days/Configuracao.md +36 -0
  11. package/seedgridKB/SeedGrid/Extensions/business-days/Exemplos.md +37 -0
  12. package/seedgridKB/SeedGrid/Extensions/business-days/Visao-geral.md +48 -0
  13. package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +10 -16
  14. package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +2 -2
  15. package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +2 -2
  16. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +4 -5
  17. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +1 -1
  18. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +3 -2
  19. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +2 -2
  20. package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +9 -0
  21. package/seedgridKB/SeedGrid/Produtos/Pulse/Autenticacao-e-chaves.md +89 -0
  22. package/seedgridKB/SeedGrid/Produtos/Pulse/Exemplos.md +44 -0
  23. package/seedgridKB/SeedGrid/Produtos/Pulse/Protocolo-e-API.md +191 -0
  24. package/seedgridKB/SeedGrid/Produtos/Pulse/SDKs.md +287 -0
  25. package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Configuracao.md +128 -0
  26. package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Instalacao.md +105 -0
  27. package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Operacao.md +86 -0
  28. package/seedgridKB/SeedGrid/Produtos/Pulse/Servidor/Providers.md +121 -0
  29. package/seedgridKB/SeedGrid/Produtos/Pulse/UI/Configuracao.md +61 -0
  30. package/seedgridKB/SeedGrid/Produtos/Pulse/UI/Visao-geral.md +74 -0
  31. package/seedgridKB/SeedGrid/Produtos/Pulse/Visao-geral.md +96 -0
  32. package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +1 -1
  33. package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +1 -1
  34. package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +1 -1
  35. package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +38 -26
  36. package/seedgridKB/SeedGrid/Toolkit/rules/backend-seedgrid.md +45 -0
  37. package/seedgridKB/SeedGrid/Toolkit/skills/sg-code-review/SKILL.md +1 -1
  38. package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-back/SKILL.md +4 -4
  39. package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/SKILL.md +3 -3
  40. package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-screen/SKILL.md +2 -2
  41. package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-skill/SKILL.md +20 -5
  42. package/seedgridKB/SeedGrid/Toolkit/skills/sg-review/SKILL.md +3 -3
  43. package/seedgridKB/SeedGrid/Visao-geral.md +7 -0
  44. package/seedgridKB/manifest.json +8 -7
  45. /package/seedgridKB/SeedGrid/Toolkit/skills/sg-code-review/references/{checklist.md → code-review-checklist.md} +0 -0
  46. /package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/references/{checklist.md → crud-front-checklist.md} +0 -0
  47. /package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/references/{patterns.md → crud-front-patterns.md} +0 -0
  48. /package/seedgridKB/SeedGrid/Toolkit/skills/sg-crud-front/references/{routing.md → crud-front-routing.md} +0 -0
  49. /package/seedgridKB/SeedGrid/Toolkit/skills/sg-new-screen/references/{checklist.md → new-screen-checklist.md} +0 -0
  50. /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.
@@ -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.2",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedgrid/ai-toolkit",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Instala agentes, skills, regras, templates e referências versionados em projetos locais para Claude Code e Codex.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -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.migration.enabled` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `boolean` | `false` | Runtime | Roda classpath:db/migration/ai-pricing com flyway_schema_history_ai_pricing | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
253
- | `seedgrid.exchange.migration.enabled` | Propriedades de outros prefixos seedgrid.* lidas pela login-tenancy | `boolean` | `false` | Runtime | Roda classpath:db/migration/exchange com flyway_schema_history_exchange | [[SeedGrid/Extensions/login-tenancy/Configuracao\|login-tenancy/Configuracao]] |
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 Propriedades de outras extensions que governam o ai-pricing
50
+ ### 2.3 Toggle do módulo
51
51
 
52
- | Propriedade | Dona | Padrão | Efeito |
53
- |---|---|---|---|
54
- | `seedgrid.ai-pricing.migration.enabled` | login-tenancy (`LoginTenancyMigrationService`) e subdomain-tenancy (`flyway/MigrationService`) | `false` | Roda `classpath:db/migration/ai-pricing` com a tabela `flyway_schema_history_ai_pricing`. **Não** é lida por esta extension. |
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` sobrescreve `quarkus.flyway.migrate-at-start=false` via `QuarkusTestProfile`.
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. No login-tenancy:
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
- # (tenancies) aplicar as migrations V900-V903. Default false.
108
- seedgrid.ai-pricing.migration.enabled=true
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: aplicar V900–V903
94
- seedgrid.ai-pricing.migration.enabled=true
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.14` (parent `seedgrid-parent:2026.07.02`) |
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
- Nos tenancies, o runner aplica essa location só quando `seedgrid.ai-pricing.migration.enabled=true` (default `false`, declarado em login-tenancy e subdomain-tenancy). Ver [[SeedGrid/Extensions/ai-pricing/Configuracao|Configuração]].
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 Propriedades de outras extensions que governam o exchange
54
+ ### 2.3 Toggle do módulo
55
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. |
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. Nos tenancies:
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
- # (tenancies) aplicar V800-V804. Default false.
106
- seedgrid.exchange.migration.enabled=true
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. Nos tenancies, ligue também `seedgrid.exchange.migration.enabled=true`.
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.migration.enabled=true # tenancies
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.14` (parent `seedgrid-parent:2026.07.02`) |
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
- Nos tenancies, o runner só aplica essas migrations com `seedgrid.exchange.migration.enabled=true` (default `false`).
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
- # Migrations opcionais de produto
175
- seedgrid.ai-pricing.migration.enabled=false
176
- seedgrid.exchange.migration.enabled=false
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/>migration.enabled}
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.migration.enabled` | `false` | Roda `db/migration/ai-pricing` no master | `RT/flyway/MigrationService` |
180
- | `seedgrid.exchange.migration.enabled` | `false` | Roda `db/migration/exchange` no master | `RT/flyway/MigrationService` |
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/exchange (se habilitados) → 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, 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.