@seedgrid/ai-toolkit 0.0.0-stage → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +162 -2
- package/dist/adapters/claude.js +114 -0
- package/dist/adapters/codex.js +108 -0
- package/dist/adapters/index.js +17 -0
- package/dist/adapters/shared.js +142 -0
- package/dist/adapters/types.js +1 -0
- package/dist/cli.js +209 -0
- package/dist/commands/common.js +98 -0
- package/dist/commands/doctor.js +290 -0
- package/dist/commands/init.js +9 -0
- package/dist/commands/install.js +107 -0
- package/dist/commands/remove.js +54 -0
- package/dist/commands/review.js +127 -0
- package/dist/commands/selfinstall.js +63 -0
- package/dist/commands/status.js +73 -0
- package/dist/commands/update.js +8 -0
- package/dist/commands/validate.js +27 -0
- package/dist/core/apply.js +181 -0
- package/dist/core/blocks.js +64 -0
- package/dist/core/content.js +528 -0
- package/dist/core/env.js +40 -0
- package/dist/core/frontmatter.js +29 -0
- package/dist/core/hash.js +14 -0
- package/dist/core/inspect.js +51 -0
- package/dist/core/lock.js +124 -0
- package/dist/core/paths.js +65 -0
- package/dist/core/plan.js +242 -0
- package/dist/core/tools.js +62 -0
- package/dist/core/types.js +11 -0
- package/dist/core/updates.js +121 -0
- package/docs/arquitetura.md +80 -0
- package/docs/compatibilidade.md +50 -0
- package/docs/formato.md +155 -0
- package/docs/instalacao.md +105 -0
- package/docs/manutencao.md +115 -0
- package/package.json +43 -4
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
- package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
- package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
- package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
- package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
- package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
- package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
- package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
- package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
- package/seedgridKB/SeedGrid/Versoes.md +64 -0
- package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
- package/seedgridKB/manifest.json +142 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, billing, rust]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-billing
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# billing — porte Rust (`seedgrid-rust-crate-billing`)
|
|
10
|
+
|
|
11
|
+
Porte das extensões Quarkus `seedgrid-billing-core` + `seedgrid-billing-stripe`. Lado Java: [[SeedGrid/Extensions/billing/Visao-geral|Visão geral do billing (Java)]] · [[SeedGrid/Extensions/billing/Configuracao|Configuração do billing (Java)]]. Configuração Rust: [[SeedGrid/Extensions/billing/Configuracao-Rust|Configuração Rust do billing]].
|
|
12
|
+
|
|
13
|
+
Domínio de billing independente de provedor (planos, assinaturas, uso), SPI de provedor, `BillingEventHandler` do host, dispatcher de webhook idempotente, router Axum (checkout/portal/webhook) e backend Stripe (cliente `reqwest` + verificação de assinatura). **Confirmado** (`src/lib.rs`).
|
|
14
|
+
|
|
15
|
+
## Identificação
|
|
16
|
+
| Item | Valor |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Pacote Cargo | `seedgrid-rust-crate-billing` (lib `seedgrid_billing`) |
|
|
19
|
+
| Versão | workspace `2026.10.14` |
|
|
20
|
+
| Features | `postgres` (default; `sqlx`, repositório e migrations), `stripe` (default; `reqwest`, `hmac`, `sha2`, `hex`) |
|
|
21
|
+
| Dependência SeedGrid | `seedgrid-rust-crate-resilience` (rate limit) |
|
|
22
|
+
| Consumidores | login-tenancy, subdomain-tenancy (doc de `src/lib.rs`) |
|
|
23
|
+
|
|
24
|
+
## API pública principal
|
|
25
|
+
| Símbolo | Papel | Fonte |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `BillingService::new(Arc<dyn BillingProvider>)` | fachada: `create_checkout`, `create_portal`, `process_webhook`, `change_subscription_plan`, `cancel_subscription(_immediately)`, `pause/resume/reactivate_subscription`, `list_invoices`, `get_upcoming_invoice`, `get_subscription`, `preview_plan_change`… | `src/service.rs` |
|
|
28
|
+
| traits `BillingProvider`, `BillingCatalogProvider`, `BillingUsageProvider` | SPI; capacidades detectadas por `as_catalog()`/`as_usage()` (equivalente ao `instanceof` do Java) | `src/spi.rs` |
|
|
29
|
+
| trait `BillingEventHandler` | lógica de domínio do host para eventos | `src/spi.rs` |
|
|
30
|
+
| `BillingEventDispatcher::new(service, repo, Option<handler>)` | idempotência por `(provider, event_id)` | `src/dispatcher.rs` |
|
|
31
|
+
| `BillingApiState::new` / `::builder(..).authorizer(..).build()` | estado do router; guard default `AllowAllBillingAuthorizer` | `src/state.rs` |
|
|
32
|
+
| `router(state)` | rotas abaixo | `src/routes.rs` |
|
|
33
|
+
| `checkout_rate_limit()`, `portal_rate_limit()`, `webhook_rate_limit()` | `SeedGridRateLimit` (`billing-checkout` 30/min, `billing-portal` 30/min, `billing-webhook` 300/min) para o host acoplar o middleware do resilience | `src/routes.rs` |
|
|
34
|
+
| `stripe::StripeBillingProvider::new(StripeConfig)` | backend Stripe; Test Clock em chaves `sk_test` | `src/stripe/provider.rs` |
|
|
35
|
+
| `stripe::ensure_product_bootstrap` | garante o produto base no startup (opt-in por `product`) — o host precisa chamar | `src/stripe/bootstrap.rs` |
|
|
36
|
+
| `BillingPlatform::assemble(Option<&PgPool>, BillingOverrides)` | montagem "estilo CDI": exige Postgres **e** `api_key` Stripe; roda migrations | `src/platform.rs` (features `postgres`+`stripe`) |
|
|
37
|
+
| `migrate` / `MIGRATOR` | `0500_create_billing_events.sql`, `0501_add_permissions.sql`; histórico `_sqlx_migrations_billing` | `src/lib.rs` |
|
|
38
|
+
| `openapi()` | spec utoipa | `src/apidoc.rs` |
|
|
39
|
+
|
|
40
|
+
Permissões (constantes em `src/state.rs`): `BILLING_CHECKOUT_CREATE`, `BILLING_PORTAL_CREATE`, `BILLING_SUBSCRIPTION_READ`.
|
|
41
|
+
|
|
42
|
+
## Endpoints
|
|
43
|
+
| Método | Path | Permissão |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| POST | `/billing/checkout` | `BILLING_CHECKOUT_CREATE` |
|
|
46
|
+
| POST | `/billing/portal` | `BILLING_PORTAL_CREATE` |
|
|
47
|
+
| GET | `/billing/subscription` | `BILLING_SUBSCRIPTION_READ` — **só no Rust** (extensão deliberada) |
|
|
48
|
+
| POST | `/public/billing/webhook` | público (assinatura do Stripe) |
|
|
49
|
+
|
|
50
|
+
## Exemplo (doc de `src/lib.rs`)
|
|
51
|
+
```rust
|
|
52
|
+
use std::sync::Arc;
|
|
53
|
+
use seedgrid_billing::{
|
|
54
|
+
migrate, BillingService, BillingEventDispatcher, BillingApiState, router,
|
|
55
|
+
PgBillingEventRepository, config::StripeConfig, stripe::StripeBillingProvider,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
migrate(&pool).await?;
|
|
59
|
+
let provider = Arc::new(StripeBillingProvider::new(StripeConfig::from_env()));
|
|
60
|
+
let service = BillingService::new(provider);
|
|
61
|
+
let repo = Arc::new(PgBillingEventRepository::new(pool));
|
|
62
|
+
let dispatcher = BillingEventDispatcher::new(service.clone(), repo, /* handler */ None);
|
|
63
|
+
let app = router(BillingApiState::new(service, dispatcher));
|
|
64
|
+
```
|
|
65
|
+
Alternativa: `BillingPlatform::assemble(Some(&pool), BillingOverrides { event_handler: Some(handler) })`. Não há app em `rust/examples/` para billing.
|
|
66
|
+
|
|
67
|
+
## Testes
|
|
68
|
+
- Unitários em `src/*` (inclui teste de alias `STRPE` em `config.rs` e `ensure_product` no provider).
|
|
69
|
+
- `tests/pg_billing_events_it.rs` (`#[ignore]`, `BILLING_IT_PG_URL`); `tests/stripe_transport_it.rs` (`BILLING_STRIPE_IT_BASE`, `BILLING_STRIPE_IT_KEY`).
|
|
70
|
+
- **Não executados.**
|
|
71
|
+
|
|
72
|
+
## Limitações
|
|
73
|
+
|
|
74
|
+
- A rota `GET /billing/subscription` existe só no Rust.
|
|
75
|
+
- O `seedgrid-billing-core` Java tem grupos de configuração (`seedgrid.billing.trial`, `.catalog`, `.checkout`, `.portal`, `.access-gate`, `.feature-gate`, `.reconciliation`, `.api`, `.plan-term.additional-attributes`, `business-timezone`, `currency`, `overage-meter-name`, `persistence-unit`) que **não têm contraparte** em `src/config.rs` do Rust (Confirmado).
|
|
76
|
+
|
|
77
|
+
## Enums
|
|
78
|
+
Equivalentes Java: [[SeedGrid/Extensions/billing/Enums|Enums do billing (Java)]].
|
|
79
|
+
|
|
80
|
+
| Enum | Arquivo | Java equivalente |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `BillingEventType` | `src/domain.rs` | [[SeedGrid/Extensions/billing/Enums#BillingEventType\|BillingEventType]] |
|
|
83
|
+
| `RecurringInterval` | `src/dtos.rs` | [[SeedGrid/Extensions/billing/Enums#RecurringInterval\|RecurringInterval]] |
|
|
84
|
+
| `AggregationFormula` | `src/dtos.rs` | [[SeedGrid/Extensions/billing/Enums#AggregationFormula\|AggregationFormula]] |
|
|
85
|
+
| `TiersMode` | `src/dtos.rs` | [[SeedGrid/Extensions/billing/Enums#TiersMode\|TiersMode]] |
|
|
86
|
+
| `BillingError` | `src/error.rs` | exceções do billing |
|
|
87
|
+
| `HttpMethod` (`Get`, `Post`, `Delete`) | `src/stripe/transport.rs` | interno do transporte Stripe |
|
|
88
|
+
|
|
89
|
+
### BillingEventType
|
|
90
|
+
`#[serde(rename_all = "SCREAMING_SNAKE_CASE")]`; `name()` = nome Java; é o valor da coluna `billing_events.type VARCHAR(50)` (sem CHECK). Mapeamento do Stripe (`stripe/translate.rs` → `map_event_type`):
|
|
91
|
+
|
|
92
|
+
| Valor | Evento Stripe |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `CheckoutCompleted` (`CHECKOUT_COMPLETED`) | `checkout.session.completed` |
|
|
95
|
+
| `PaymentConfirmed` (`PAYMENT_CONFIRMED`) | `invoice.paid` |
|
|
96
|
+
| `PaymentFailed` (`PAYMENT_FAILED`) | `invoice.payment_failed` |
|
|
97
|
+
| `SubscriptionCreated` (`SUBSCRIPTION_CREATED`) | `customer.subscription.created` |
|
|
98
|
+
| `SubscriptionUpdated` (`SUBSCRIPTION_UPDATED`) | `customer.subscription.updated` |
|
|
99
|
+
| `SubscriptionCanceled` (`SUBSCRIPTION_CANCELED`) | `customer.subscription.deleted` |
|
|
100
|
+
| `RefundCreated` (`REFUND_CREATED`) | `charge.refunded` |
|
|
101
|
+
| `DisputeOpened` (`DISPUTE_OPENED`) | `charge.dispute.created` |
|
|
102
|
+
|
|
103
|
+
Qualquer outro tipo de evento → `BillingError::UnsupportedEvent` (o webhook responde 204). Os 8 valores são **iguais** aos do Java.
|
|
104
|
+
|
|
105
|
+
### RecurringInterval / AggregationFormula / TiersMode
|
|
106
|
+
`#[serde(rename_all = "UPPERCASE")]`. `RecurringInterval` = `DAY`, `WEEK`, `MONTH`, `YEAR` (Stripe `day`/`week`/`month`/`year`; ausente → `MONTH`). `AggregationFormula` = `SUM`, `COUNT`, `LAST` (ausente → `SUM`; `LAST` é mapeado para `sum` no Stripe, lacuna herdada do Java). `TiersMode` = `GRADUATED`, `VOLUME`. Valores iguais ao Java.
|
|
107
|
+
|
|
108
|
+
### BillingError
|
|
109
|
+
`Unsupported`, `InvalidWebhook` (400 no webhook), `UnsupportedEvent` (204), `Provider` (500), `Forbidden` (403), `Config`, `Json`, `Database` (feature `postgres`), `Internal`.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, billing, quarkus]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-billing
|
|
4
|
+
branch: main
|
|
5
|
+
commit: ba38efc347
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Billing (Quarkus): visão geral
|
|
10
|
+
|
|
11
|
+
Assinaturas prontas para hosts Quarkus. Cobre planos, condições comerciais (terms), trial, checkout, portal do cliente, troca de plano, cancelamento, ciclo de cobrança, contadores de uso (franquia e excedente por contador) e webhook. Tudo é exposto em endpoints REST da própria extension. O gateway de pagamento fica atrás da SPI `BillingProvider`, e há um provider pronto para **Stripe**.
|
|
12
|
+
|
|
13
|
+
- Configuração: [[SeedGrid/Extensions/billing/Configuracao|Configuração do billing]]
|
|
14
|
+
- Exemplos: [[SeedGrid/Extensions/billing/Exemplos|Exemplos do billing]]
|
|
15
|
+
- Enums: [[SeedGrid/Extensions/billing/Enums|Enums do billing]]
|
|
16
|
+
- Porte Rust: [[SeedGrid/Extensions/billing/Rust|Porte Rust]]
|
|
17
|
+
|
|
18
|
+
> Segundo o README, "o host não conhece billing": ele adiciona a dependência e configura `seedgrid.billing.*`. Não escreve controller, entity, migration nem handler de webhook. Se cobra por uso, declara os contadores (`UsageMeterContributor`) e marca onde contar (`@ConsumesUsage`). **Confirmado** (README e `integration-tests`, que sobem um app sem nenhuma classe de billing própria).
|
|
19
|
+
|
|
20
|
+
## Módulos Maven e coordenadas
|
|
21
|
+
|
|
22
|
+
Agregador: `br.com.seedgrid:seedgrid-billing:2026.10.14-1` (parent `br.com.seedgrid:seedgrid-parent:2026.07.02`).
|
|
23
|
+
|
|
24
|
+
| Submódulo | Parent | Artefatos | Papel |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| `seedgrid-billing-core` | `seedgrid-billing-parent:2026.10.14-1` | runtime `seedgrid-billing-core`, deployment `seedgrid-billing-core-deployment`, `integration-tests` (não publicado) | modelo, REST, regras, SPIs, migrations |
|
|
27
|
+
| `seedgrid-billing-stripe` | `seedgrid-billing-stripe-parent:2026.10.14-1` | runtime `seedgrid-billing-stripe`, deployment `seedgrid-billing-stripe-deployment`, `integration-tests` | `StripeBillingProvider` (stripe-java `26.12.0`) e `StripeProductBootstrap` |
|
|
28
|
+
|
|
29
|
+
O groupId é sempre `br.com.seedgrid`. As features Quarkus são `seedgrid-billing-core` e `seedgrid-billing-stripe`, declaradas em `SeedgridBillingProcessor` e `SeedgridBillingStripeProcessor`.
|
|
30
|
+
|
|
31
|
+
### Dependências SeedGrid (runtime do core)
|
|
32
|
+
|
|
33
|
+
| Artefato | Versão no pom | Para quê |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `seedgrid-security` | 2026.10.08 | `Company`, `User`, `Permission`, `@PlatformScope`, `UserService.deactivateUserInCompany` |
|
|
36
|
+
| `seedgrid-commons` | 2026.10.08 | `ApiExceptionExtension`, `ProblemType`, `BaseEntity` |
|
|
37
|
+
| `seedgrid-audit-core` | 2026.09.25 | `@Audit` em serviços administrativos |
|
|
38
|
+
| `seedgrid-privacy` | 2026.07.27 | dependência declarada (uso específico não investigado) |
|
|
39
|
+
| `seedgrid-resilience-core` | 2026.07.08 | `@SeedGridRateLimit` no webhook, checkout e portal |
|
|
40
|
+
| `seedgrid-notification-api` | 2026.10.08 (`seedgrid.notification.version`) | catálogo e publicação dos eventos `billing.*` |
|
|
41
|
+
|
|
42
|
+
Também depende do Quarkus: `arc`, `hibernate-orm`, `jdbc-postgresql`, `flyway`, `rest-jackson`, `hibernate-validator` e `smallrye-openapi`.
|
|
43
|
+
|
|
44
|
+
**Quem depende do billing:** `login-tenancy` e `subdomain-tenancy` (o billing não conhece nenhum deles). Ver [[SeedGrid/Extensions/login-tenancy/Visao-geral|login-tenancy]] e [[SeedGrid/Extensions/subdomain-tenancy/Visao-geral|subdomain-tenancy]].
|
|
45
|
+
|
|
46
|
+
## Arquitetura
|
|
47
|
+
|
|
48
|
+
```mermaid
|
|
49
|
+
flowchart LR
|
|
50
|
+
Client -->|/me/*, /admin/*| REST[Controllers do core]
|
|
51
|
+
REST --> SVC[Services: Plan, Trial, Checkout, SubscriptionChange, Usage...]
|
|
52
|
+
SVC --> BS[BillingService]
|
|
53
|
+
BS --> SPI{{BillingProvider SPI}}
|
|
54
|
+
SPI --> STRIPE[StripeBillingProvider]
|
|
55
|
+
Stripe((Stripe)) -->|POST /public/billing/webhook| WH[BillingWebhookController]
|
|
56
|
+
WH --> SPI
|
|
57
|
+
WH --> H[SubscriptionBillingEventHandler]
|
|
58
|
+
SVC --> DB[(tabelas billing via BillingEntityManager)]
|
|
59
|
+
SVC -. eventos CDI .-> OBS[Observers do host / notification]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Pacotes de `br.com.seedgrid.billing`:
|
|
63
|
+
|
|
64
|
+
| Pacote | Conteúdo |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `annotations` | `@ConsumesUsage`, `@RequiresPlanFeature` |
|
|
67
|
+
| `configs` | `BillingConfig`, mais um `@ConfigMapping` por grupo e `BusinessTimeZone` |
|
|
68
|
+
| `controllers` | `AdminPlan`, `AdminSubscription`, `AdminAccount`, `AdminBilling`, `Subscription`, `PlanCatalog`, `Usage`, `MeBilling`, `BillingWebhook`, `RestControllerPath` |
|
|
69
|
+
| `filters` | `BillingApiToggleFilter` (api.enabled), `AccessGateFilter` (bloqueio geral), `BillingApiOpenApiFilter` |
|
|
70
|
+
| `interceptors` | interceptors das duas anotações |
|
|
71
|
+
| `repositories` | JPA puro sobre `BillingEntityManager` |
|
|
72
|
+
| `services` | regras de negócio |
|
|
73
|
+
| `spis` (+`impl`) | pontos de extensão |
|
|
74
|
+
| `notifications` | `BillingNotificationCatalog`, `BillingLifecycleNotificationObserver`, `UserAccessEmailObserver` |
|
|
75
|
+
|
|
76
|
+
No **build**, o deployment coleta todo `@ConsumesUsage` e cria o bean sintético `ConsumesUsageSites`. No **startup**, `UsageMeterCatalog` recusa um contador não declarado e informa o método na mensagem. **Confirmado** (`SeedgridBillingProcessor#consumesUsageSites`).
|
|
77
|
+
|
|
78
|
+
Modelo: `Plan` 1:N `PlanTerm` 1:N `PlanTermMeter`. `Account` 1:N `Subscription` (N:1 `PlanTerm`) 1:N `BillingCycle` 1:N `BillingCycleMeter`. `Account` 1:N `Purchase`. **Confirmado** (`entities/`).
|
|
79
|
+
|
|
80
|
+
## APIs públicas e pontos de integração
|
|
81
|
+
|
|
82
|
+
### Anotações
|
|
83
|
+
- `@ConsumesUsage(meter = "...", units = 1)`: checa antes da execução e contabiliza só se o método retornar normalmente. O `meter` é obrigatório.
|
|
84
|
+
- `@RequiresPlanFeature(value = "PERMISSAO", message = "")`: responde 402 `FEATURE_NOT_IN_PLAN` (ou `TRIAL_EXPIRED`).
|
|
85
|
+
|
|
86
|
+
### SPIs (todas com default `@DefaultBean`, exceto o provider)
|
|
87
|
+
| SPI | Default | Assinatura principal |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `BillingProvider` | — (fornecido por `seedgrid-billing-stripe`) | `createCheckout`, `createPortal`, `parseAndVerifyWebhook`, `changeSubscriptionPlan(..., List<String> newMeteredPriceIds)`, ... |
|
|
90
|
+
| `BillingCatalogProvider` | — (opcional; Stripe implementa) | `createPrice`, `ensureProduct`, `archivePrice`, ... |
|
|
91
|
+
| `BillingUsageProvider` | — (opcional; Stripe implementa) | `ensureMeter`, `createMeteredPrice`, `reportUsage` |
|
|
92
|
+
| `UsageMeterContributor` | nenhum contador | `List<UsageMeterDefinition> meters()` (`record UsageMeterDefinition(String code, String label)`) |
|
|
93
|
+
| `PlanTermAdditionalFieldsValidator` | `DefaultPlanTermAdditionalFieldsValidator` | `validate(PlanTerm, Map<String, JsonNode>)` |
|
|
94
|
+
| `PlanTermUsageChecker` | `DefaultPlanTermUsageChecker` | `isInUse(Collection<Long>)` |
|
|
95
|
+
| `CurrentAccountResolver` | `DefaultCurrentAccountResolver` | `requireCurrentUser()`, `requireCurrentAccount()`, `billingContactEmail()` |
|
|
96
|
+
| `AccountMembersGateway` | `CompanyAccountMembersGateway` | `activeUsers`, `isResponsible`, `deactivate`, `findByPublicIds` |
|
|
97
|
+
| `BillingAccountScope` | `UnrestrictedBillingAccountScope` | `Optional<Set<Long>> visibleCompanyIds()` |
|
|
98
|
+
| `BillingEventHandler` | `SubscriptionBillingEventHandler` | `handle(BillingEvent)` |
|
|
99
|
+
|
|
100
|
+
> **Inferência:** um host precisa de **exatamente um** bean `BillingProvider`. `BillingService` o injeta direto, e os testes usam dublês (`NoopBillingProvider`, `FakeBillingProvider`). Sem o módulo Stripe nem provider próprio, a injeção ficaria insatisfeita. Não executei para confirmar.
|
|
101
|
+
|
|
102
|
+
### Serviço programático
|
|
103
|
+
`UsageService#assertCanConsume(Account, String meter, int units)` e `UsageService#consume(Account, String meter, int units, String idempotencyKey)`. O `consume` é `@Transactional` e retorna `UsageConsumedEvent`.
|
|
104
|
+
|
|
105
|
+
### Endpoints REST (`RestControllerPath`)
|
|
106
|
+
| Método | Caminho | Acesso |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| GET/POST | `/admin/plans` | plataforma + `PLAN_READ`/`PLAN_CREATE` |
|
|
109
|
+
| GET/PUT/DELETE | `/admin/plans/{planId}` | plataforma + `PLAN_*` |
|
|
110
|
+
| GET/POST | `/admin/plans/{planId}/terms` | plataforma + `PLAN_TERM_*` |
|
|
111
|
+
| PATCH/DELETE | `/admin/plans/{planId}/terms/{termId}` | plataforma + `PLAN_TERM_*` |
|
|
112
|
+
| POST | `/admin/plans/{planId}/terms/{termId}/publish`, `/archive` | plataforma + `PLAN_TERM_*` |
|
|
113
|
+
| GET/PATCH | `/admin/plans/trial` | plataforma + `PLAN_TERM_*` |
|
|
114
|
+
| GET/POST | `/admin/subscriptions` | plataforma + `SUBSCRIPTION_*` |
|
|
115
|
+
| GET | `/admin/accounts`, `/admin/accounts/{accountId}`, `/admin/accounts/options`, `/admin/accounts/{accountId}/history` | plataforma + `ACCOUNT_READ`/`ACCOUNT_OPTIONS_READ` |
|
|
116
|
+
| POST | `/admin/accounts/{accountId}/grant-units`, `/grant-trial-days` | plataforma + `ACCOUNT_GRANT_USAGE` |
|
|
117
|
+
| GET | `/admin/billing/meters`, `/admin/billing/overview` | plataforma |
|
|
118
|
+
| GET | `/me/subscription`, `/me/plans`, `/me/usage` | autenticado |
|
|
119
|
+
| GET/POST | `/me/billing/checkout`, `/me/billing/checkout/preview` | autenticado |
|
|
120
|
+
| POST | `/me/billing/portal`, `/change-plan`, `/cancel`, `/reactivate`, `/cancel-scheduled-change`, `/trial-ended` | autenticado |
|
|
121
|
+
| GET | `/me/billing/change-preview`, `/invoices`, `/upcoming` | autenticado |
|
|
122
|
+
| GET/PUT | `/me/billing/downgrade-user-selection` | autenticado |
|
|
123
|
+
| POST | `/public/billing/webhook` | pública (assinatura do provider) |
|
|
124
|
+
|
|
125
|
+
Os caminhos são **Confirmados** em `RestControllerPath`. As permissões vêm do README. Com `seedgrid.billing.api.enabled=false`, todos os prefixos exceto o webhook respondem 404 e somem do OpenAPI (`RestControllerPath.API_PREFIXES`).
|
|
126
|
+
|
|
127
|
+
Rate limit via resilience (**Confirmado**, `@SeedGridRateLimit`):
|
|
128
|
+
|
|
129
|
+
| configKey | Endpoint | Limite |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `billing-webhook` | webhook | 300/min |
|
|
132
|
+
| `billing-checkout` | `POST /me/billing/checkout` | 30/min |
|
|
133
|
+
| `billing-portal` | `POST /me/billing/portal` | 30/min |
|
|
134
|
+
|
|
135
|
+
### Eventos CDI
|
|
136
|
+
| Evento | Tipos | Observação |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `SubscriptionLifecycleEvent` | `ACTIVATED, UPGRADED, DOWNGRADE_SCHEDULED, DOWNGRADE_CANCELED, CANCELLATION_REQUESTED, CANCELED, REACTIVATED, PAST_DUE, TRIAL_ENDED` | Disparado dentro da transação. Após o commit, a extension publica `billing.*` no notification. |
|
|
139
|
+
| `UserAccessEvent` | `LOSS_SCHEDULED, LOSS_APPLIED, RESTORED` | A extension envia o e-mail (templates `templates/billing-default/`, sobrescrevíveis em `templates/billing/`). |
|
|
140
|
+
| `UsageConsumedEvent` | — | Um por consumo contabilizado, com o `meter`. |
|
|
141
|
+
|
|
142
|
+
### Stripe (`seedgrid-billing-stripe`)
|
|
143
|
+
- `StripeBillingProvider` implementa `BillingProvider`, `BillingCatalogProvider` e `BillingUsageProvider`.
|
|
144
|
+
- Mapeia os eventos Stripe para `BillingEventType`: `checkout.session.completed`, `invoice.paid`, `invoice.payment_failed`, `customer.subscription.created/updated/deleted`, `charge.refunded`, `charge.dispute.created`.
|
|
145
|
+
- Com chave `sk_test*`, cria customers presos a um Test Clock (desligável).
|
|
146
|
+
- `StripeProductBootstrap` garante o produto base no startup (best-effort).
|
|
147
|
+
|
|
148
|
+
## Migrations
|
|
149
|
+
`db/migration/billing`, de **V500 a V513** (tabela de histórico default `flyway_schema_history_billing`):
|
|
150
|
+
|
|
151
|
+
| Versão | Conteúdo |
|
|
152
|
+
|---|---|
|
|
153
|
+
| V500 | `billing_events` |
|
|
154
|
+
| V501 | permissões de checkout/portal |
|
|
155
|
+
| V502 | `accounts`, `plans`, `plan_terms` |
|
|
156
|
+
| V503 | timestamps com fuso |
|
|
157
|
+
| V504 | `max_users`, `plan_term_permissions` |
|
|
158
|
+
| V505 | plano/term TRIAL com IDs fixos |
|
|
159
|
+
| V506 | `trial_days` |
|
|
160
|
+
| V507 | `additional_attributes jsonb` |
|
|
161
|
+
| V508 | colunas `BaseEntity` |
|
|
162
|
+
| V509 | `tenant_subscriptions`, `subscription_billing_cycles`, `billing_purchases` |
|
|
163
|
+
| V510 | permissões `PLAN_*`, `PLAN_TERM_*`, `SUBSCRIPTION_*` |
|
|
164
|
+
| V511 | `billing_account_history`, permissões `ACCOUNT_*` |
|
|
165
|
+
| V512 | audiences |
|
|
166
|
+
| V513 | `plan_term_meters`, `billing_cycle_meters` |
|
|
167
|
+
|
|
168
|
+
**Confirmado** (arquivos SQL e README do core).
|
|
169
|
+
|
|
170
|
+
## Testes (não executados)
|
|
171
|
+
- `seedgrid-billing-core/runtime/src/test`: unitários Mockito sem Quarkus. Cobrem services (`UsageServiceTest`, `SeatServiceTest`, `TrialEndedNotifierTest`, `PlanPublicationServiceTest`...), filtros (`AccessGateFilterTest`, `BillingApiToggleFilterTest`, `BillingPathsTest`), `BillingEntityManagerTest` e notificações.
|
|
172
|
+
- `seedgrid-billing-core/integration-tests`: PostgreSQL via Testcontainers. Cobrem `SubscriptionFlowTest`, `UsageTest`, `FeatureGateTest`, `AccessGateEnabledTest`, `ApiDisabledTest`, `AdminAccountTest`, `AdminAccountScopeTest`, `AdminPlanTest`, `BillingOverviewTest`, `LegacyHostSchemaMigrationTest`, entre outros.
|
|
173
|
+
- `deployment/src/test`: smoke (`SeedgridBillingTest`, `SeedgridBillingDevModeTest`, `SeedgridBillingStripeTest`...).
|
|
174
|
+
- `seedgrid-billing-stripe/runtime/src/test`: `StripeBillingProviderTest`.
|
|
175
|
+
|
|
176
|
+
## Limitações
|
|
177
|
+
- Colunas antigas (`plan_terms.overage_price`, `provider_overage_price_id`, `subscription_billing_cycles.*_units`) continuam no banco, **inertes**, até o seedgrid-report migrar os dados (CHANGELOG 2026.10.08).
|
|
178
|
+
- O billing depende da security. Com Flyway nativo, o host precisa listar `db/migration/security` e `db/migration/billing` (comentário em `deployment/src/test/resources/application.properties`).
|
|
179
|
+
- O `microprofile-config.properties` do core redefine `quarkus.flyway.*` com ordinal 100. Ver [[SeedGrid/Extensions/billing/Configuracao|Configuração]], seção de frameworks.
|
|
180
|
+
- Os assuntos dos e-mails de acesso estão fixos em código, com "SeedGrid App" (`UserAccessEmails`). Não há propriedade para mudá-los.
|
|
181
|
+
- Não há job de expiração de trial: a verificação acontece a cada chamada.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, broker, rust, configuracao]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-broker
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# broker — Configuração Rust
|
|
10
|
+
|
|
11
|
+
Visão geral: [[SeedGrid/Extensions/broker/Visao-geral|Visão geral do broker]]. Não há equivalente Java.
|
|
12
|
+
|
|
13
|
+
## Cabeçalho
|
|
14
|
+
| Item | Valor |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Mecanismo | **argumentos de construtor e structs** passados pelo host; as crates **não leem variáveis de ambiente** (`grep` por `env::var` em `crates/` sem resultado — **Confirmado**) |
|
|
17
|
+
| Seleção de backend | feita pelo host (ex.: `BROKER_PROVIDER` no `seedgrid-pulse` e no exemplo) |
|
|
18
|
+
| Leitura | na construção do broker |
|
|
19
|
+
| Features Cargo | nenhuma em nenhuma das 5 crates |
|
|
20
|
+
|
|
21
|
+
## Parâmetros por backend
|
|
22
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
23
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
24
|
+
| `MemoryBroker::new(capacity)` | usize | ≥ 1 (0 vira 1) | `512` (`Default`) | Não | capacidade do `broadcast`; assinante atrasado além disso deixa de receber | `MemoryBroker` | buffer do `mpsc` por assinante é fixo em 512 | construtor | `crates/seedgrid-broker-memory/src/lib.rs` |
|
|
25
|
+
| `RedisBroker::connect(url, _)` | &str | URL `redis://` / `rediss://` aceita pelo crate `redis` | — | Sim | conecta e faz `PING` (falha → erro) | `RedisBroker` | — | construtor | `crates/seedgrid-broker-redis/src/lib.rs` |
|
|
26
|
+
| `RedisBroker::connect(_, channel)` | &str | nome de canal | — | Sim | canal único de PUBLISH/SUBSCRIBE; vazio só é rejeitado pela função livre `connect` | idem | — | construtor | idem |
|
|
27
|
+
| `NatsConfig.url` / `NatsConfig.subject` | String | — | sem `Default` | Sim (struct) | apenas armazenados (scaffold) | uso não encontrado | — | `NatsBroker::connect` | `crates/seedgrid-broker-nats/src/lib.rs` |
|
|
28
|
+
| `RabbitMqConfig.url` / `.exchange` / `.routing_key` | String | — | sem `Default` | Sim (struct) | apenas armazenados (scaffold) | uso não encontrado | — | `RabbitMqBroker::connect` | `crates/seedgrid-broker-rabbitmq/src/lib.rs` |
|
|
29
|
+
|
|
30
|
+
## Variáveis de ambiente do host/exemplo (não lidas pelas crates)
|
|
31
|
+
| Variável | Valores | Padrão no exemplo | Onde |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `BROKER_PROVIDER` | `memory`, `redis` (outro → erro) | `memory` | `rust/examples/seedgrid-broker-example/src/main.rs` → `build_broker` |
|
|
34
|
+
| `BROKER_REDIS_URL` | URL Redis | `redis://localhost:6379` | idem |
|
|
35
|
+
| `BROKER_REDIS_CHANNEL` | nome de canal | `seedgrid` | idem |
|
|
36
|
+
| `RUST_LOG` | filtro `tracing` | — | idem |
|
|
37
|
+
|
|
38
|
+
## Receitas
|
|
39
|
+
- **Testes/dev**: `Arc::new(MemoryBroker::default())`.
|
|
40
|
+
- **Produção (várias instâncias)**: `RedisBroker::connect("redis://<host>:6379", "<canal>")`; todas as instâncias devem usar o mesmo canal.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, broker, rust]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-broker
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# broker — Visão geral (só Rust)
|
|
10
|
+
|
|
11
|
+
Abstração de **mensageria pub/sub** da plataforma SeedGrid. Define um contrato único (`Broker`) e backends que o implementam; o host programa contra o trait e escolhe o backend na composição (por configuração dele). **Não existe extensão Java equivalente** (**Confirmado**: não há `seedgrid-quarkus-ext-broker` em `java/`). Configuração: [[SeedGrid/Extensions/broker/Configuracao-Rust|Configuração Rust do broker]].
|
|
12
|
+
|
|
13
|
+
Caso de uso principal: o produto `seedgrid-pulse` (fora do `seedgrid-platform`), que escolhe o backend por `BROKER_PROVIDER`.
|
|
14
|
+
|
|
15
|
+
## Crates (sub-workspace)
|
|
16
|
+
Diretório `rust/seedgrid-rust-crate-broker/crates/`; as 5 crates são membros do workspace raiz `rust/Cargo.toml` e herdam `version` (`2026.10.14`), `edition` (**2024**), `license` (`MIT`), `authors` e dependências de `[workspace.package]`/`[workspace.dependencies]`. Não há `Cargo.toml` próprio na raiz de `seedgrid-rust-crate-broker` (era um workspace aninhado, absorvido — comentário em `rust/Cargo.toml`).
|
|
17
|
+
|
|
18
|
+
| Crate | Papel | Estado (**Confirmado** no código) |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `seedgrid-broker-spi` | contrato: `Broker`, `BrokerMessage`, `BackendKind`, `BrokerReceiver`, `DynBroker` | estável |
|
|
21
|
+
| `seedgrid-broker-memory` | backend in-process (`tokio::sync::broadcast`) | funcional |
|
|
22
|
+
| `seedgrid-broker-redis` | backend Redis Pub/Sub (canal RESP único) | funcional |
|
|
23
|
+
| `seedgrid-broker-nats` | `NatsConfig` + `NatsBroker` | **scaffold**: `publish`/`subscribe` retornam erro "ainda nao foi implementado" |
|
|
24
|
+
| `seedgrid-broker-rabbitmq` | `RabbitMqConfig` + `RabbitMqBroker` | **scaffold**: idem |
|
|
25
|
+
|
|
26
|
+
Nenhuma crate tem features Cargo ou dependência de outras crates SeedGrid além do SPI.
|
|
27
|
+
|
|
28
|
+
## Contrato (`crates/seedgrid-broker-spi/src/lib.rs`)
|
|
29
|
+
```rust
|
|
30
|
+
pub type BrokerReceiver = mpsc::Receiver<BrokerMessage>;
|
|
31
|
+
pub type DynBroker = Arc<dyn Broker>;
|
|
32
|
+
|
|
33
|
+
pub struct BrokerMessage {
|
|
34
|
+
pub topic: String,
|
|
35
|
+
pub payload: Vec<u8>,
|
|
36
|
+
pub headers: BTreeMap<String, String>, // #[serde(default)]
|
|
37
|
+
pub key: Option<String>, // omitido no JSON quando None
|
|
38
|
+
}
|
|
39
|
+
// BrokerMessage::new(topic, payload).with_header(k, v).with_key(k)
|
|
40
|
+
|
|
41
|
+
pub enum BackendKind { Memory, Redis, Nats, RabbitMq }
|
|
42
|
+
|
|
43
|
+
#[async_trait]
|
|
44
|
+
pub trait Broker: Send + Sync {
|
|
45
|
+
fn backend_kind(&self) -> BackendKind;
|
|
46
|
+
async fn publish(&self, message: BrokerMessage) -> Result<()>; // anyhow::Result
|
|
47
|
+
async fn subscribe(&self) -> Result<BrokerReceiver>;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Fluxo
|
|
52
|
+
```mermaid
|
|
53
|
+
sequenceDiagram
|
|
54
|
+
participant C as Consumidor (host)
|
|
55
|
+
participant B as Broker
|
|
56
|
+
participant I as Infra (Redis)
|
|
57
|
+
participant P as Produtor (host)
|
|
58
|
+
C->>B: subscribe() -> BrokerReceiver (mpsc 512)
|
|
59
|
+
B->>I: SUBSCRIBE <canal>
|
|
60
|
+
P->>B: publish(BrokerMessage)
|
|
61
|
+
B->>I: PUBLISH <canal> <json>
|
|
62
|
+
I-->>B: mensagem
|
|
63
|
+
B-->>C: BrokerMessage (host filtra por topic)
|
|
64
|
+
```
|
|
65
|
+
- **Canal único**: o `subscribe()` entrega **todas** as mensagens; `topic` é só um campo para roteamento no host, não um filtro do backend.
|
|
66
|
+
- Só chega o que foi publicado **depois** da inscrição (memory e redis).
|
|
67
|
+
|
|
68
|
+
## Comportamento por backend
|
|
69
|
+
| Backend | Detalhes (**Confirmado**) |
|
|
70
|
+
|---|---|
|
|
71
|
+
| memory | `MemoryBroker::new(capacity)` (mínimo 1; `Default` = 512). `publish` ignora a falta de inscritos (mensagem descartada, `Ok(())`). Cada `subscribe` cria uma task que repassa para um `mpsc` de 512. Se o assinante ficar para trás além da capacidade, `broadcast::Receiver::recv` retorna `Lagged` e o laço `while let Ok(..)` **termina** — a assinatura para de entregar sem erro (**Inferência** a partir da API do tokio; comportamento não testado no repositório). |
|
|
72
|
+
| redis | `RedisBroker::connect(url, channel)` abre o cliente e faz `PING`. `publish` serializa a mensagem em JSON (`serde_json`) e faz `PUBLISH` no canal. `subscribe` (serializado por mutex) abre um pubsub, assina o canal e repassa a um `mpsc` de 512; payloads que não decodificam são logados (`warn`) e descartados; fim do stream encerra a task. A função livre `seedgrid_broker_redis::connect(url, channel)` valida canal não vazio; `RedisBroker::connect` **não** valida. |
|
|
73
|
+
| nats / rabbitmq | `connect(config)` só guarda a config; `publish`/`subscribe` falham. |
|
|
74
|
+
|
|
75
|
+
## Exemplo (de `rust/examples/seedgrid-broker-example/src/main.rs`)
|
|
76
|
+
```rust
|
|
77
|
+
async fn build_broker() -> Result<DynBroker> {
|
|
78
|
+
let provider = std::env::var("BROKER_PROVIDER").unwrap_or_else(|_| "memory".to_string());
|
|
79
|
+
match provider.as_str() {
|
|
80
|
+
"memory" => Ok(Arc::new(MemoryBroker::default())),
|
|
81
|
+
"redis" => {
|
|
82
|
+
let url = std::env::var("BROKER_REDIS_URL").unwrap_or_else(|_| "redis://localhost:6379".to_string());
|
|
83
|
+
let channel = std::env::var("BROKER_REDIS_CHANNEL").unwrap_or_else(|_| "seedgrid".to_string());
|
|
84
|
+
Ok(Arc::new(RedisBroker::connect(&url, &channel).await?))
|
|
85
|
+
}
|
|
86
|
+
other => anyhow::bail!("BROKER_PROVIDER desconhecido: {other} (use memory|redis)"),
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let mut rx = broker.subscribe().await?; // assinar ANTES de publicar
|
|
91
|
+
broker.publish(BrokerMessage::new("pedidos.criado", br#"{"id":1}"#.to_vec())).await?;
|
|
92
|
+
let msg = rx.recv().await;
|
|
93
|
+
```
|
|
94
|
+
A leitura de env acima é do **exemplo**, não das crates.
|
|
95
|
+
|
|
96
|
+
## Testes
|
|
97
|
+
- Unitário: `publishes_to_subscribers` em `crates/seedgrid-broker-memory/src/lib.rs`.
|
|
98
|
+
- Nenhum teste nas crates redis/nats/rabbitmq/spi.
|
|
99
|
+
- E2E Testcontainers: `rust/examples/seedgrid-broker-example/tests/broker_e2e.rs` (memória + Redis).
|
|
100
|
+
- **Não executados.**
|
|
101
|
+
|
|
102
|
+
## Limitações
|
|
103
|
+
- NATS e RabbitMQ sem implementação.
|
|
104
|
+
- Sem reconexão automática no Redis (fim do stream encerra a assinatura).
|
|
105
|
+
- Sem garantia de entrega (pub/sub puro; perde mensagens sem assinante).
|
|
106
|
+
|
|
107
|
+
## Enums
|
|
108
|
+
Sem equivalente Java (módulo só Rust).
|
|
109
|
+
|
|
110
|
+
| Enum | Arquivo | Variantes |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `BackendKind` | `crates/seedgrid-broker-spi/src/lib.rs` | `Memory`, `Redis`, `Nats`, `RabbitMq` |
|
|
113
|
+
|
|
114
|
+
`BackendKind` é devolvido por `Broker::backend_kind()` e não é serializado (sem serde); `Nats` e `RabbitMq` só são retornados pelos esqueletos, cujos `publish`/`subscribe` falham. A escolha do backend (`BROKER_PROVIDER=memory|redis` no exemplo) é texto do host, não este enum.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, cache, rust, configuracao]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-cache
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# cache — Configuração Rust
|
|
10
|
+
|
|
11
|
+
Visão do crate: [[SeedGrid/Extensions/cache/Rust|Porte Rust do cache]] · Java: [[SeedGrid/Extensions/cache/Configuracao|Configuração do cache (Java)]].
|
|
12
|
+
|
|
13
|
+
## Cabeçalho
|
|
14
|
+
| Item | Valor |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Struct | `CacheConfig` (+ enum `ProviderDownLog`) — `rust/seedgrid-rust-crate-cache/src/config.rs` |
|
|
17
|
+
| Mecanismo | `CacheConfig::from_env()`, `CacheConfig::new(hosts)` ou literal; passada a `RedisCache::connect` / `CacheBackend::Distributed` |
|
|
18
|
+
| Prefixo Java | `seedgrid.cache.*` (fachada que faz alias de `quarkus.redis.*` via `RelocateConfigSourceInterceptor`) |
|
|
19
|
+
| Precedência | `SEEDGRID_CACHE_<X>` > `QUARKUS_REDIS_<X>` (exceto `IF_PROVIDER_IS_DOWN`, sem fallback) — `alias_resolve` |
|
|
20
|
+
| Leitura | quando o host chama `from_env()`; no workspace, só o exemplo `seedgrid-cache-example` chama |
|
|
21
|
+
| Backend in-memory | sem configuração |
|
|
22
|
+
|
|
23
|
+
Valores são `trim`ados; vazio conta como ausente (`alias_resolve`).
|
|
24
|
+
|
|
25
|
+
## Variáveis de ambiente
|
|
26
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
27
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
28
|
+
| `SEEDGRID_CACHE_HOSTS` / fallback `QUARKUS_REDIS_HOSTS` (Java `seedgrid.cache.hosts` / `quarkus.redis.hosts`) | String | `host:porta`, `redis://...`, `rediss://...`; lista por vírgula (só o 1º é usado) | `localhost:6379` | Não | montado em URL por `redis_url()` (prefixa `redis://` se faltar esquema) | `RedisCache::connect` | `password` | `from_env()` | `config.rs` → `from_env`, `redis_url`; `redis_backend.rs` → `connect` |
|
|
29
|
+
| 🔒 `SEEDGRID_CACHE_PASSWORD` / `QUARKUS_REDIS_PASSWORD` | `Option<String>` | texto | — | Não | injetada como `:<senha>@` na URL se ela ainda não tiver `@` | `redis_url()` | `hosts` | `from_env()` | `config.rs` |
|
|
30
|
+
| `SEEDGRID_CACHE_TIMEOUT` / `QUARKUS_REDIS_TIMEOUT` | `Option<Duration>` | número = segundos; `Nms`, `Ns`, `Nm`; `PTnS`/`PTnM` | — | Não | timeout de conexão **e** de resposta; inválido → ignorado | `RedisCache::connect` | — | `from_env()` | `config.rs` → `parse_duration`; `redis_backend.rs` |
|
|
31
|
+
| `SEEDGRID_CACHE_IF_PROVIDER_IS_DOWN` (Java `seedgrid.cache.if-provider-is-down`) | `ProviderDownLog` | `WARN`, `ERROR` (case-insensitive); outro → `WARN` | `WARN` | Não | só muda o nível do log; Rust sempre degrada (Java `ERROR` relança) | `RedisCache` (`on_provider_down`) | sem fallback `QUARKUS_REDIS_*` | `from_env()` | `config.rs`; `redis_backend.rs` |
|
|
32
|
+
|
|
33
|
+
Mapeamento Java: **Confirmado** — o nome `seedgrid.cache.if-provider-is-down` está em `java/seedgrid-quarkus-lib-cache/.../CacheProviderFailSoft.java` (`PROP`); a relação `seedgrid.cache.*` ↔ `quarkus.redis.*` está no interceptor Java (comentários lidos). A conversão para env segue a regra MicroProfile sem ambiguidade.
|
|
34
|
+
|
|
35
|
+
## Struct `CacheConfig`
|
|
36
|
+
| Campo | Tipo | `Default` |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `hosts` | String | `localhost:6379` |
|
|
39
|
+
| `password` | `Option<String>` | `None` |
|
|
40
|
+
| `timeout` | `Option<Duration>` | `None` |
|
|
41
|
+
| `if_provider_is_down` | `ProviderDownLog` | `Warn` |
|
|
42
|
+
|
|
43
|
+
`RedisCache::connect_url` e `from_connection` ignoram `CacheConfig` e usam `Warn`; `with_provider_down_log` sobrescreve.
|
|
44
|
+
|
|
45
|
+
## Features Cargo
|
|
46
|
+
| Feature | Padrão | Efeito |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
|
|
49
|
+
## Somente testes / exemplos
|
|
50
|
+
| Variável | Onde |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `SEEDGRID_CACHE_TEST_URL` | `tests/redis_backend.rs` (default `redis://localhost:6379`) |
|
|
53
|
+
| `RUST_LOG` | exemplo |
|
|
54
|
+
|
|
55
|
+
## Configuração mínima
|
|
56
|
+
```dotenv
|
|
57
|
+
SEEDGRID_CACHE_HOSTS=localhost:6379
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Configuração completa comentada
|
|
61
|
+
```dotenv
|
|
62
|
+
SEEDGRID_CACHE_HOSTS=redis://<host>:6379 # ou host:porta; rediss:// para TLS
|
|
63
|
+
SEEDGRID_CACHE_PASSWORD=<SEGREDO:redis-password>
|
|
64
|
+
SEEDGRID_CACHE_TIMEOUT=5s # 5 | 5s | 500ms | PT5S
|
|
65
|
+
SEEDGRID_CACHE_IF_PROVIDER_IS_DOWN=WARN # WARN|ERROR (apenas nível de log)
|
|
66
|
+
# Fallback se SEEDGRID_CACHE_* faltar:
|
|
67
|
+
# QUARKUS_REDIS_HOSTS=redis://<host>:6379
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Receitas
|
|
71
|
+
- **Dev/single-node**: não configure nada e use `default_cache()` / `InMemoryCache::new()`.
|
|
72
|
+
- **Redis/Valkey/Dragonfly**: `SEEDGRID_CACHE_HOSTS` + `build(CacheBackend::Distributed { flavor, config: CacheConfig::from_env() })`.
|
|
73
|
+
- **Reaproveitar env de um host Quarkus**: `QUARKUS_REDIS_HOSTS`/`QUARKUS_REDIS_PASSWORD` funcionam como fallback.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, library, cache, configuracao]
|
|
3
|
+
fonte: java/seedgrid-quarkus-lib-cache
|
|
4
|
+
branch: main
|
|
5
|
+
commit: 14bd916a09
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# SeedGrid Cache — Configuração
|
|
10
|
+
|
|
11
|
+
Voltar: [[SeedGrid/Extensions/cache/Visao-geral|Visão geral do cache]] · [[SeedGrid/Extensions/cache/Exemplos|Exemplos do cache]] · [[SeedGrid/Extensions/cache/Rust|Porte Rust]]
|
|
12
|
+
|
|
13
|
+
## 1. Cabeçalho
|
|
14
|
+
|
|
15
|
+
| Item | Valor |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Prefixos | `seedgrid.cache.*` (próprio + fachada/alias de `quarkus.redis.*`) |
|
|
18
|
+
| Classes de config | Nenhuma `@ConfigMapping`/`@ConfigRoot`. Leitura direta via `ConfigProvider` em `CacheProviderFailSoft`; alias via `SeedGridCacheConfigRelocateInterceptor` (SmallRye `RelocateConfigSourceInterceptor`) |
|
|
19
|
+
| Default embutido | `seedgrid-cache-core/src/main/resources/META-INF/microprofile-config.properties` (ordinal MP padrão 100 → `application.properties` do host, ordinal 250, sobrescreve) |
|
|
20
|
+
| Fase | Runtime. `if-provider-is-down` é relido **a cada falha** do backend (sem cache), logo mudanças de fonte dinâmica valem na hora. O alias vale para qualquer fase em que o interceptor esteja carregado (ver dúvidas) |
|
|
21
|
+
| Seleção de backend | **Não há propriedade**: o provider ativo é o que estiver no classpath (`seedgrid-cache-redis`/`-valkey`/`-dragonfly`); sem nenhum, usa `DefaultSeedGridCache` in-memory |
|
|
22
|
+
|
|
23
|
+
Mecanismo de leitura investigado: `@ConfigMapping`, `@ConfigRoot`, `@ConfigProperty`, `ConfigProvider`, `microprofile-config.properties`, `META-INF/services`, `application.properties` de testes. Só `CacheProviderFailSoft#level()` lê config diretamente.
|
|
24
|
+
|
|
25
|
+
## 2. Propriedades próprias
|
|
26
|
+
|
|
27
|
+
### 2.1 Política de falha do backend
|
|
28
|
+
|
|
29
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
|
|
30
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
31
|
+
| `seedgrid.cache.if-provider-is-down` | `String` (parse para enum `CacheProviderFailSoft.Level`) | `WARN`, `ERROR` (case-insensitive; qualquer outro valor ou ausência → `WARN`) — ver [[SeedGrid/Extensions/cache/Enums#Level|Level]] | `WARN` (no `microprofile-config.properties` da lib e no `orElse("WARN")` do código) | Não | `WARN`: loga WARN e degrada (`get*` → vazio, `increment` → `0`, `put`/`delete` → no-op); a request continua. `ERROR`: loga ERROR e relança a `RuntimeException` do backend | Lida em toda falha de `getString/getBytes/getLong/putString/putBytes/putLong/increment/delete` dos providers RESP. **Não** afeta `withLock` nem o `DefaultSeedGridCache` | Não é relocada para `quarkus.redis.*` (o relocate só mexe em nomes que começam com `quarkus.redis.`). Equivalente no crate Rust é sempre fail-soft | Runtime (relida a cada falha) | Declaração: `seedgrid-cache-core/.../commons/spi/CacheProviderFailSoft.java` → `PROP`, `level()`; default: `seedgrid-cache-core/src/main/resources/META-INF/microprofile-config.properties`. Consumo: `SeedGridCacheRedis`, `SeedGridCacheValkey`, `SeedGridCacheDragonfly` via `CacheProviderFailSoft.get/run` |
|
|
32
|
+
|
|
33
|
+
Variável de ambiente: `SEEDGRID_CACHE_IF_PROVIDER_IS_DOWN` — **Inferência** (regra MP; a lib lê o nome exato via `ConfigProvider`, então a regra de conversão do `EnvConfigSource` se aplica sem ambiguidade).
|
|
34
|
+
|
|
35
|
+
### 2.2 Fachada `seedgrid.cache.*` → `quarkus.redis.*` (alias)
|
|
36
|
+
|
|
37
|
+
Mecanismo (**Confirmado** em `SeedGridCacheConfigRelocateInterceptor#relocate` e `SeedGridCacheConfigRelocateInterceptorTest`): quando qualquer código pede `quarkus.redis.<sufixo>`, o interceptor procura primeiro `seedgrid.cache.<sufixo>`; se não houver valor, usa `quarkus.redis.<sufixo>`. Portanto **qualquer** propriedade do `quarkus-redis-client` pode ser escrita com o prefixo `seedgrid.cache.`, e `seedgrid.cache.*` tem precedência sobre `quarkus.redis.*` quando ambas existem.
|
|
38
|
+
|
|
39
|
+
Tipos, valores aceitos e padrões são os do `quarkus-redis-client` (Quarkus 3.30.8) — **não definidos pela SeedGrid**; consulte a documentação do Quarkus. As chaves abaixo são as citadas no código/testes/README da lib:
|
|
40
|
+
|
|
41
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
|
|
42
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
43
|
+
| `seedgrid.cache.<sufixo>` | conforme `quarkus.redis.<sufixo>` | conforme Quarkus | conforme Quarkus | Não | Alias de `quarkus.redis.<sufixo>`; vence o nome nativo | `quarkus-redis-client` (consumido pelo `RedisDataSource` injetado nos providers) | Fallback: `quarkus.redis.<sufixo>` | A da propriedade Quarkus correspondente | `seedgrid-cache-core/.../config/SeedGridCacheConfigRelocateInterceptor.java` → `relocate(String)`; registro: `META-INF/services/io.smallrye.config.ConfigSourceInterceptor` |
|
|
44
|
+
| `seedgrid.cache.hosts` | conforme `quarkus.redis.hosts` (URIs `redis://host:porta`) | conforme Quarkus | conforme Quarkus (sem valor, o client padrão do Quarkus é usado; dev services podem subir um servidor) | Condicional — necessária em produção quando um provider RESP está no classpath (sem ela o client não aponta para o servidor real). **Inferência** | Endereço do servidor Redis/Valkey/Dragonfly | `RedisDataSource` default | Alias de `quarkus.redis.hosts` | Runtime (Quarkus) | Testes: `SeedGridCacheConfigRelocateInterceptorTest`, `RedisAliasTestResource#start()`, `ValkeyAliasTestResource`, `DragonflyAliasTestResource`; README |
|
|
45
|
+
| `seedgrid.cache.password` 🔒 | conforme `quarkus.redis.password` | — | — | Condicional (servidor com AUTH) | Senha do servidor | `RedisDataSource` | Alias de `quarkus.redis.password` | Runtime (Quarkus) | `SeedGridCacheConfigRelocateInterceptorTest`; `README.md` (`${CACHE_PASSWORD:}`) |
|
|
46
|
+
| `seedgrid.cache.timeout` | conforme `quarkus.redis.timeout` (`Duration`, ex.: `PT5S`) | conforme Quarkus | conforme Quarkus | Não | Timeout do client | `RedisDataSource` | Alias de `quarkus.redis.timeout` | Runtime (Quarkus) | `SeedGridCacheConfigRelocateInterceptorTest`; `README.adoc` |
|
|
47
|
+
| `seedgrid.cache.max-pool-size` | conforme `quarkus.redis.max-pool-size` (int) | conforme Quarkus | conforme Quarkus | Não | Tamanho do pool | `RedisDataSource` | Alias de `quarkus.redis.max-pool-size` | Runtime (Quarkus) | `SeedGridCacheConfigRelocateInterceptorTest`; `README.md`, `README.adoc` |
|
|
48
|
+
| `seedgrid.cache.max-pool-waiting` | conforme `quarkus.redis.max-pool-waiting` (int) | conforme Quarkus | conforme Quarkus | Não | Fila de espera do pool | `RedisDataSource` | Alias de `quarkus.redis.max-pool-waiting` | Runtime (Quarkus) | `README.adoc` (sem teste) |
|
|
49
|
+
|
|
50
|
+
Variáveis de ambiente para o alias (ex.: `SEEDGRID_CACHE_HOSTS`): **Inferência** — o interceptor pede o nome exato `seedgrid.cache.hosts`, que o `EnvConfigSource` resolve pela regra MP. `QUARKUS_REDIS_HOSTS` continua funcionando como fallback. Não testado.
|
|
51
|
+
|
|
52
|
+
## 3. Propriedades de frameworks usadas/recomendadas
|
|
53
|
+
|
|
54
|
+
| Propriedade | Situação | Origem |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `quarkus.redis.*` | Continua aceita como fallback do alias (compatibilidade) | `SeedGridCacheConfigRelocateInterceptor` |
|
|
57
|
+
| `quarkus.arc.selected-alternatives` | Usada nos testes para habilitar o provider (`...SeedGridCacheRedis` etc.). Em apps normais os providers já são alternativas habilitadas por `@Priority(1)` — **Inferência** | `seedgrid-cache-*/src/test/resources/application.properties` |
|
|
58
|
+
| `quarkus.redis.devservices.enabled` | Desligada nos testes para provar o relocate. Também poderia ser escrita como `seedgrid.cache.devservices.enabled` pelo alias — **Inferência** (propriedade build-time; depende de o interceptor estar ativo no build, não testado) | idem |
|
|
59
|
+
| `quarkus.index-dependency.*` | **Não** necessária: `seedgrid-cache-core` empacota `META-INF/jandex.idx` (`jandex-maven-plugin` nos poms) | `pom.xml`; comentário em `java/examples/seedgrid-cache-example/src/main/resources/application.properties` |
|
|
60
|
+
|
|
61
|
+
## 4. Propriedades só de testes/exemplos
|
|
62
|
+
|
|
63
|
+
| Propriedade | Onde | Observação |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `quarkus.redis.devservices.enabled=false` | `seedgrid-cache-{redis,valkey,dragonfly}/src/test/resources/application.properties` | garante que só `seedgrid.cache.hosts` configure o client |
|
|
66
|
+
| `quarkus.arc.selected-alternatives=<provider>` | idem | habilita o provider testado |
|
|
67
|
+
| `seedgrid.cache.hosts` (dinâmica, URL do container) | `*AliasTestResource#start()` | injetada pelo test resource |
|
|
68
|
+
| `seedgrid.cache.example.item-ttl` (`Duration`, default `PT30S` no `@ConfigProperty`) | `java/examples/seedgrid-cache-example` → `CatalogService` | **propriedade do exemplo, não da lib** (apesar do prefixo); não é relocada |
|
|
69
|
+
|
|
70
|
+
## 5. Aliases, obsoletas, renomeações
|
|
71
|
+
|
|
72
|
+
- `seedgrid.cache.<x>` ↔ `quarkus.redis.<x>` (alias, precedência para `seedgrid.cache.*`). **Confirmado.**
|
|
73
|
+
- Clientes nomeados: pelo código, `quarkus.redis.<nome>.hosts` também é procurado como `seedgrid.cache.<nome>.hosts` (o relocate é por prefixo). Ambos os prefixos funcionam; os providers SeedGrid usam só o client `@Default`. **Inferência** (sem teste).
|
|
74
|
+
- Nenhuma propriedade obsoleta encontrada.
|
|
75
|
+
|
|
76
|
+
## 6. Configuração mínima
|
|
77
|
+
|
|
78
|
+
```properties
|
|
79
|
+
# Com um provider RESP no classpath (seedgrid-cache-redis | -valkey | -dragonfly):
|
|
80
|
+
seedgrid.cache.hosts=redis://<host>:6379
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Sem provider no classpath não é necessária nenhuma propriedade (cache in-memory).
|
|
84
|
+
|
|
85
|
+
## 7. Configuração completa comentada
|
|
86
|
+
|
|
87
|
+
```properties
|
|
88
|
+
# Reação a falha do backend distribuído: WARN (fail-soft, padrão) | ERROR (fail-closed, relança)
|
|
89
|
+
seedgrid.cache.if-provider-is-down=WARN
|
|
90
|
+
|
|
91
|
+
# --- Fachada de quarkus.redis.* (qualquer chave do quarkus-redis-client vale com este prefixo) ---
|
|
92
|
+
seedgrid.cache.hosts=redis://<host>:6379
|
|
93
|
+
seedgrid.cache.password=<SEGREDO:cache-password>
|
|
94
|
+
seedgrid.cache.timeout=PT5S # exemplo de Duration ISO-8601; padrão é o do Quarkus
|
|
95
|
+
seedgrid.cache.max-pool-size=16 # exemplo; padrão é o do Quarkus
|
|
96
|
+
seedgrid.cache.max-pool-waiting=100 # exemplo; padrão é o do Quarkus
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Os valores numéricos/Duration acima são exemplos de formato, não padrões.
|
|
100
|
+
|
|
101
|
+
## 8. Receitas
|
|
102
|
+
|
|
103
|
+
- **Dev local / instância única sem servidor**: dependa só de `seedgrid-cache-core`; nada a configurar (`DefaultSeedGridCache`).
|
|
104
|
+
- **Produção multi-instância com Redis**: adicione `seedgrid-cache-redis` + `seedgrid.cache.hosts` (+ `password` se houver AUTH). Trocar para Valkey/Dragonfly = trocar o artifact; a config continua a mesma.
|
|
105
|
+
- **Cache crítico (não pode servir dado "degradado")**: `seedgrid.cache.if-provider-is-down=ERROR` — operações relançam a exceção do backend.
|
|
106
|
+
- **Migração de config legada**: `quarkus.redis.*` existente continua funcionando; migre para `seedgrid.cache.*` quando quiser (o novo vence).
|
|
107
|
+
|
|
108
|
+
## 9. Dúvidas e lacunas
|
|
109
|
+
|
|
110
|
+
- **Não confirmado**: se o interceptor (registrado via `ServiceLoader`) é aplicado também na fase de build do Quarkus — relevante para chaves build-time como `devservices.*`. Os ITs só provam runtime (`hosts`).
|
|
111
|
+
- **Não confirmado**: comportamento de `withLock` quando o backend cai (não é envolvido por `CacheProviderFailSoft`; a exceção propaga).
|
|
112
|
+
- Equivalência exata com a config do crate Rust: ver [[SeedGrid/Extensions/cache/Configuracao-Rust|Configuração Rust do cache]].
|