@seedgrid/ai-toolkit 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +151 -2
- package/dist/adapters/claude.js +114 -0
- package/dist/adapters/codex.js +108 -0
- package/dist/adapters/index.js +17 -0
- package/dist/adapters/shared.js +142 -0
- package/dist/adapters/types.js +1 -0
- package/dist/cli.js +203 -0
- package/dist/commands/common.js +98 -0
- package/dist/commands/doctor.js +290 -0
- package/dist/commands/init.js +9 -0
- package/dist/commands/install.js +107 -0
- package/dist/commands/remove.js +54 -0
- package/dist/commands/review.js +127 -0
- package/dist/commands/status.js +73 -0
- package/dist/commands/update.js +8 -0
- package/dist/commands/validate.js +27 -0
- package/dist/core/apply.js +181 -0
- package/dist/core/blocks.js +64 -0
- package/dist/core/content.js +528 -0
- package/dist/core/env.js +40 -0
- package/dist/core/frontmatter.js +29 -0
- package/dist/core/hash.js +14 -0
- package/dist/core/inspect.js +51 -0
- package/dist/core/lock.js +124 -0
- package/dist/core/paths.js +65 -0
- package/dist/core/plan.js +242 -0
- package/dist/core/tools.js +62 -0
- package/dist/core/types.js +11 -0
- package/dist/core/updates.js +121 -0
- package/docs/arquitetura.md +80 -0
- package/docs/compatibilidade.md +50 -0
- package/docs/formato.md +155 -0
- package/docs/instalacao.md +105 -0
- package/docs/manutencao.md +115 -0
- package/package.json +43 -4
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
- package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
- package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
- package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
- package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
- package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
- package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
- package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
- package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
- package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
- package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
- package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
- package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
- package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
- package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
- package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
- package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
- package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
- package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
- package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
- package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
- package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
- package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
- package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
- package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
- package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
- package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
- package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
- package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
- package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
- package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
- package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
- package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
- package/seedgridKB/SeedGrid/Versoes.md +64 -0
- package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
- package/seedgridKB/manifest.json +142 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, backup, exemplos]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-backup
|
|
4
|
+
branch: main
|
|
5
|
+
commit: 3bed4075ea
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Exemplos — backup (Quarkus)
|
|
10
|
+
|
|
11
|
+
Voltar: [[SeedGrid/Extensions/backup/Visao-geral|Visão geral do backup]] · Propriedades: [[SeedGrid/Extensions/backup/Configuracao|Configuração do backup]]
|
|
12
|
+
|
|
13
|
+
Todos os exemplos usam tipos e assinaturas reais do runtime (`br.com.seedgrid.backup.*`). Fonte indicada em cada um.
|
|
14
|
+
|
|
15
|
+
## 1. Dependência Maven
|
|
16
|
+
|
|
17
|
+
Fonte: `runtime/pom.xml` (coordenadas reais).
|
|
18
|
+
|
|
19
|
+
```xml
|
|
20
|
+
<dependency>
|
|
21
|
+
<groupId>br.com.seedgrid</groupId>
|
|
22
|
+
<artifactId>seedgrid-backup</artifactId>
|
|
23
|
+
<version>2026.10.09</version>
|
|
24
|
+
</dependency>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
O host também precisa de: datasource PostgreSQL, um bean `CurrentUserProvider` (commons), um `UserContactProvider` (para o e-mail) e, para `@Audit` persistir, um provider de auditoria (ex. `seedgrid-audit-postgresql`) — ver [[SeedGrid/Extensions/audit/Visao-geral|audit]].
|
|
28
|
+
|
|
29
|
+
## 2. Fluxo REST
|
|
30
|
+
|
|
31
|
+
Fonte: `ExportController`, `ExportRequest`, `ExportResponse`, `README.md` (seção "Endpoints REST").
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Criar (BACKUP_CREATE) -> 201
|
|
35
|
+
curl -X POST https://<host>/exports \
|
|
36
|
+
-H "Authorization: Bearer <SEGREDO:token>" \
|
|
37
|
+
-H "Content-Type: application/json" \
|
|
38
|
+
-d '{ "format": "CSV_ZIP", "scope": "DOMAIN" }'
|
|
39
|
+
|
|
40
|
+
# Listar jobs do usuário corrente (BACKUP_READ)
|
|
41
|
+
curl "https://<host>/exports?page=0&size=20" -H "Authorization: Bearer <SEGREDO:token>"
|
|
42
|
+
|
|
43
|
+
# Status (BACKUP_READ) -> 200 / 404
|
|
44
|
+
curl https://<host>/exports/<jobId> -H "Authorization: Bearer <SEGREDO:token>"
|
|
45
|
+
|
|
46
|
+
# Download (BACKUP_DOWNLOAD) -> 200 application/zip / 404 não pronto / 410 expirado ou falho
|
|
47
|
+
curl -OJ https://<host>/exports/<jobId>/download -H "Authorization: Bearer <SEGREDO:token>"
|
|
48
|
+
|
|
49
|
+
# Cancelar ou excluir (BACKUP_DELETE) -> 204 / 404
|
|
50
|
+
curl -X DELETE https://<host>/exports/<jobId> -H "Authorization: Bearer <SEGREDO:token>"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Valores aceitos: `format` = `CSV_ZIP` | `SQL_DUMP_ZIP`; `scope` = `DOMAIN` | `RAW`. Resposta de criação: `ExportResponse` com `status = QUEUED`, `progress = 0`.
|
|
54
|
+
|
|
55
|
+
Conteúdo do ZIP `CSV_ZIP` (fonte: `CsvZipExporter#createZipArchive`): `data/<tabela-ou-entidade>.csv`, `manifest.json`, `checksums.txt`; nome `export_<schema>_<timestamp>.zip`, gravado sob o prefixo `<schema>/exports` do storage.
|
|
56
|
+
|
|
57
|
+
## 3. Exporter customizado (SPI `BackupExporter`)
|
|
58
|
+
|
|
59
|
+
Fonte: `spi/BackupExporter.java`, `spi/ExportContext.java`, `spi/ExportResult.java`; adaptado do `README.md` ("Implementar um BackupExporter"). Atenção: a extensão já registra exporters para `CSV_ZIP` e `SQL_DUMP_ZIP`; o `BackupExporterRegistry` lança `IllegalStateException` no startup se houver dois beans para o mesmo `BackupFormat`. Portanto um exporter próprio só pode coexistir se o default do mesmo formato for removido (ex. `quarkus.arc.exclude-types`) — **Inferência**; não há novos valores de `BackupFormat` além dos dois existentes.
|
|
60
|
+
|
|
61
|
+
```java
|
|
62
|
+
import java.util.List;
|
|
63
|
+
|
|
64
|
+
import br.com.seedgrid.backup.domains.BackupFormat;
|
|
65
|
+
import br.com.seedgrid.backup.domains.ExportScope;
|
|
66
|
+
import br.com.seedgrid.backup.spi.BackupExporter;
|
|
67
|
+
import br.com.seedgrid.backup.spi.ExportContext;
|
|
68
|
+
import br.com.seedgrid.backup.spi.ExportException;
|
|
69
|
+
import br.com.seedgrid.backup.spi.ExportResult;
|
|
70
|
+
import br.com.seedgrid.backup.spi.ExportValidationException;
|
|
71
|
+
import jakarta.enterprise.context.ApplicationScoped;
|
|
72
|
+
|
|
73
|
+
@ApplicationScoped
|
|
74
|
+
public class MySqlDumpExporter implements BackupExporter {
|
|
75
|
+
|
|
76
|
+
@Override
|
|
77
|
+
public BackupFormat format() {
|
|
78
|
+
return BackupFormat.SQL_DUMP_ZIP;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Override
|
|
82
|
+
public void validate(ExportContext ctx) throws ExportValidationException {
|
|
83
|
+
if (ctx.getScope() != ExportScope.RAW) {
|
|
84
|
+
throw new ExportValidationException("só RAW é suportado");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@Override
|
|
89
|
+
public ExportResult export(ExportContext ctx) throws ExportException {
|
|
90
|
+
ctx.updateProgress(10, "extraindo dados");
|
|
91
|
+
byte[] zipBytes = buildZip(ctx); // sua lógica
|
|
92
|
+
String key = ctx.getStorageService().store("export.zip", zipBytes);
|
|
93
|
+
ctx.updateProgress(100, "concluído");
|
|
94
|
+
|
|
95
|
+
return ExportResult.builder()
|
|
96
|
+
.artifacts(List.of(ExportResult.ArtifactData.builder()
|
|
97
|
+
.type(ExportResult.ArtifactType.ZIP)
|
|
98
|
+
.storageKey(key)
|
|
99
|
+
.filename("export.zip")
|
|
100
|
+
.sizeBytes(zipBytes.length)
|
|
101
|
+
.mimeType("application/zip")
|
|
102
|
+
.build()))
|
|
103
|
+
.totalSizeBytes(zipBytes.length)
|
|
104
|
+
.build();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private byte[] buildZip(ExportContext ctx) {
|
|
108
|
+
throw new UnsupportedOperationException("implementar");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`ExportContext` expõe (Lombok `@Data`): `getJobId()`, `getFormat()`, `getScope()`, `getDatabaseSchema()`, `getOptions()`, `getOption(key, default)` (mapa `options` do pedido; os exporters embutidos não o leem), `updateProgress(int, String)`, `getStorageService()` (`store`/`retrieve`/`delete`) e `getExportJob()` (pode ser `null` — o pipeline não o preenche mais).
|
|
114
|
+
|
|
115
|
+
## 4. `TenantProvider` para host multitenant
|
|
116
|
+
|
|
117
|
+
Fonte: `spi/TenantProvider.java`; default `configs/SingleTenantBackupProvider` (`@DefaultBean`, tenant `"public"`). O valor do tenant é usado como **schema PostgreSQL** (filtro de `information_schema`) e como prefixo do storage. Schedulers iteram `getAllTenants()` e não fazem nada se a lista vier vazia.
|
|
118
|
+
|
|
119
|
+
```java
|
|
120
|
+
import java.util.List;
|
|
121
|
+
import java.util.Optional;
|
|
122
|
+
|
|
123
|
+
import br.com.seedgrid.backup.spi.TenantProvider;
|
|
124
|
+
import jakarta.enterprise.context.ApplicationScoped;
|
|
125
|
+
|
|
126
|
+
@ApplicationScoped
|
|
127
|
+
public class MyTenantBackupProvider implements TenantProvider {
|
|
128
|
+
|
|
129
|
+
private static final ThreadLocal<String> CURRENT = new ThreadLocal<>();
|
|
130
|
+
|
|
131
|
+
@Override
|
|
132
|
+
public Optional<String> getCurrentTenant() {
|
|
133
|
+
return Optional.ofNullable(CURRENT.get()); // ou resolver do contexto da requisição
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@Override
|
|
137
|
+
public void setCurrentTenant(String tenantId) {
|
|
138
|
+
CURRENT.set(tenantId);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@Override
|
|
142
|
+
public void clearCurrentTenant() {
|
|
143
|
+
CURRENT.remove();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@Override
|
|
147
|
+
public List<String> getAllTenants() {
|
|
148
|
+
return List.of("tenant_a", "tenant_b"); // schemas existentes
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
O teste `TestTenantProvider` usa o mesmo padrão com `@Alternative @Priority(1)`; a extensão `seedgrid-subdomain-tenancy` fornece um `MultiTenantBackupProvider` (`java/seedgrid-quarkus-ext-subdomain-tenancy/runtime/src/main/java/br/com/seedgrid/subdomaintenancy/backup/MultiTenantBackupProvider.java`).
|
|
154
|
+
|
|
155
|
+
## 5. Reagir ao fim do export (`SgUserEvent`)
|
|
156
|
+
|
|
157
|
+
Fonte: `ExportService#notifyRequester` e teste `services/ExportUserEventIT` (observer `AFTER_SUCCESS`).
|
|
158
|
+
|
|
159
|
+
```java
|
|
160
|
+
import br.com.seedgrid.commons.events.SgUserEvent;
|
|
161
|
+
import jakarta.enterprise.context.ApplicationScoped;
|
|
162
|
+
import jakarta.enterprise.event.Observes;
|
|
163
|
+
import jakarta.enterprise.event.TransactionPhase;
|
|
164
|
+
|
|
165
|
+
@ApplicationScoped
|
|
166
|
+
public class BackupFinishedListener {
|
|
167
|
+
|
|
168
|
+
void on(@Observes(during = TransactionPhase.AFTER_SUCCESS) SgUserEvent event) {
|
|
169
|
+
if (!"backup".equals(event.channel())) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// event.event(): "backup.finished.success" ou "backup.finished.error"
|
|
173
|
+
String jobId = (String) event.data().get("exportPublicId");
|
|
174
|
+
String status = (String) event.data().get("status"); // "DONE" ou "FAILED"
|
|
175
|
+
String user = event.userPublicId();
|
|
176
|
+
// ex.: empurrar notificação realtime ao usuário
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 6. Trocar o canal de notificação (`ExportNotificationService`)
|
|
182
|
+
|
|
183
|
+
Fonte: `spi/ExportNotificationService.java`; default `EmailExportNotificationService` é `@DefaultBean`, então basta declarar outro bean. O `NotificationSchedulerService` só chama `notifyReady` quando `isEnabled()` e `seedgrid.backup.notification.enabled` são `true`; exceção → `notificationError` gravado e nova tentativa após `retry-delay`, até `max-retries`.
|
|
184
|
+
|
|
185
|
+
```java
|
|
186
|
+
import br.com.seedgrid.backup.entities.ExportJob;
|
|
187
|
+
import br.com.seedgrid.backup.spi.ExportNotificationService;
|
|
188
|
+
import jakarta.enterprise.context.ApplicationScoped;
|
|
189
|
+
|
|
190
|
+
@ApplicationScoped
|
|
191
|
+
public class WebhookExportNotificationService implements ExportNotificationService {
|
|
192
|
+
|
|
193
|
+
@Override
|
|
194
|
+
public void notifyReady(ExportJob job) throws Exception {
|
|
195
|
+
String jobId = job.getPublicId();
|
|
196
|
+
String requester = job.getCreateUserPublicId();
|
|
197
|
+
// enviar para o canal desejado; lançar exceção para provocar retry
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 7. Template do e-mail
|
|
203
|
+
|
|
204
|
+
Fonte: `spi/impl/DefaultTemplateBackupProvider.java`. Sem código: coloque no classpath do host `templates/backup/ready-notification.html` (tem prioridade sobre `templates/backup-default/html/ready-notification.html`). Placeholders substituídos por `String.replace`: `{{jobId}}`, `{{format}}`, `{{scope}}`, `{{sizeBytes}}`, `{{finishedAt}}`.
|
|
205
|
+
|
|
206
|
+
Ou implemente `TemplateBackupProvider#readyNotification(ExportJob)` em um bean próprio.
|
|
207
|
+
|
|
208
|
+
## 8. Configuração
|
|
209
|
+
|
|
210
|
+
Exemplos de `application.properties` (mínimo, completo e receitas) estão em [[SeedGrid/Extensions/backup/Configuracao|Configuração do backup]].
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, backup, rust]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-backup
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# backup — porte Rust (`seedgrid-rust-crate-backup`)
|
|
10
|
+
|
|
11
|
+
Porte da extensão Quarkus `seedgrid-quarkus-ext-backup`. Lado Java: [[SeedGrid/Extensions/backup/Visao-geral|Visão geral do backup (Java)]] · [[SeedGrid/Extensions/backup/Configuracao|Configuração do backup (Java)]]. Configuração Rust: [[SeedGrid/Extensions/backup/Configuracao-Rust|Configuração Rust do backup]].
|
|
12
|
+
|
|
13
|
+
Motor de **export** de dados de tenant: dump do Postgres para CSV compactado em ZIP, rastreio de jobs no banco, storage plugável (via filemanagement), auditoria (via audit), rate limit no create (via resilience) e notificação por e-mail. **Não** é backup de arquivos/SO e **não** tem restore. **Confirmado** (`src/lib.rs`).
|
|
14
|
+
|
|
15
|
+
## Identificação
|
|
16
|
+
| Item | Valor |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Pacote Cargo | `seedgrid-rust-crate-backup` (lib `seedgrid_backup`) |
|
|
19
|
+
| Versão | workspace `2026.10.14` |
|
|
20
|
+
| Edição / MSRV | 2021 / 1.82 |
|
|
21
|
+
| Features Cargo | nenhuma |
|
|
22
|
+
| Dependências SeedGrid | `seedgrid-rust-crate-filemanagent` (lib `seedgrid_filemanagement`), `seedgrid-rust-crate-audit`, `seedgrid-rust-crate-resilience`, `seedgrid-rust-crate-cache`, `seedgrid-runtime` (eventos `UserEventSink`) |
|
|
23
|
+
|
|
24
|
+
## Fluxo
|
|
25
|
+
1. `ExportService::create_export_job` grava o job `QUEUED`; com `async_enabled`, dispara worker `tokio`: claim (`RUNNING`) → exporter → `DONE` (ou `FAILED`).
|
|
26
|
+
2. `ExtractDataService`: escopo **RAW** lê `information_schema.tables` (exclui `flyway_%` e tabelas internas `export_jobs`, `export_artifacts`, `audit_log*`) e faz `SELECT <col>::text`; **DOMAIN** usa o SPI `DomainDatasetProvider` do host (default vazio); **CUSTOM** gera erro.
|
|
27
|
+
3. `CsvZipExporter` (único exporter): ZIP nível 9 com `manifest.json`, `checksums.txt` (formato `sha256sum`) e `data/<nome>.csv` por dataset não vazio.
|
|
28
|
+
4. Retenção: `expires_at = agora + retention_days`; `BackupScheduler::clean_expired_exports` apaga expirados.
|
|
29
|
+
5. `BackupScheduler::spawn` roda `process_queued_exports` (a cada `queue_poll_interval`, respeita `max_concurrent_exports`) e `process_notifications` (a cada `notification.poll_interval`, com `max_retries`/`retry_delay`).
|
|
30
|
+
6. Notificação `EmailExportNotificationService`: `is_enabled = notification.enabled && mailer.from && mailer.host`; envio pelo SPI `Mailer` (default `LoggingMailer`; `SmtpMailer::from_config` para SMTP real via lettre).
|
|
31
|
+
|
|
32
|
+
Fonte: `src/service.rs`, `src/extract.rs`, `src/exporter.rs`, `src/scheduler.rs`, `src/notification.rs`, `src/email_smtp.rs`.
|
|
33
|
+
|
|
34
|
+
## API pública principal
|
|
35
|
+
| Símbolo | Papel |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `BackupConfig` | config ([[SeedGrid/Extensions/backup/Configuracao-Rust\|Configuração Rust]]) |
|
|
38
|
+
| `BackupPlatform::assemble(Option<&PgPool>, BackupOverrides)` → `Option<Arc<BackupAssembly>>` | montagem a partir do ambiente (opt-in + migrations) |
|
|
39
|
+
| `BackupAssembly::build_service(pool)` / `config()` | `ExportService` por banco (single-DB ou por tenant) |
|
|
40
|
+
| `BackupOverrides { domain_provider, require_opt_in, auditor, user_events }` | seams do host; `Default`: `EmptyDomainDatasetProvider`, `require_opt_in = true`, `NoopAuditor`, sink no-op |
|
|
41
|
+
| `ExportService` | `create_export_job`, `get_export_status`, `list_export_jobs`, `cancel_export_job`, `delete_export_job`, `download_export_file`, `execute_export_async`… |
|
|
42
|
+
| `BackupScheduler` | `spawn`, `clean_expired_exports`, `process_queued_exports`, `process_notifications` |
|
|
43
|
+
| `router(BackupApiState)` / `router_with_resolver(...)` | rotas `/exports` |
|
|
44
|
+
| `rest::export_create_rate_limit()` | `SeedGridRateLimit` (`export-create`, 10/hora) para o host acoplar |
|
|
45
|
+
| `migrate(&PgPool)` / `MIGRATOR` | migrations `0400`–`0402`, histórico `_sqlx_migrations_backup` |
|
|
46
|
+
| `openapi()` | spec utoipa |
|
|
47
|
+
| SPIs: `BackupExporter`, `DomainDatasetProvider`, `TenantProvider` (default `SingleTenantBackupProvider` → `public`), `CurrentUserProvider`, `PermissionGuard` (default `AllowAllPermissionGuard`), `ExportNotificationService`, `Mailer`, `TemplateBackupProvider`, `UserContactProvider` | `src/spi.rs`, `src/rest.rs` |
|
|
48
|
+
|
|
49
|
+
## Endpoints
|
|
50
|
+
| Método | Path | Permissão (host-enforced via `PermissionGuard`) |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| POST | `/exports` | `BACKUP_CREATE` (+ rate limit `export-create`) |
|
|
53
|
+
| GET | `/exports?page&size` | `BACKUP_READ` |
|
|
54
|
+
| GET | `/exports/{jobId}` | `BACKUP_READ` |
|
|
55
|
+
| DELETE | `/exports/{jobId}` | `BACKUP_DELETE` |
|
|
56
|
+
| GET | `/exports/{jobId}/download` | `BACKUP_DOWNLOAD` (410 para terminal expirado/falho) |
|
|
57
|
+
|
|
58
|
+
Fonte: `src/rest.rs` → `router`. O guard default (`AllowAllPermissionGuard`) libera tudo; as permissões `BACKUP_*` são aplicadas pelo host.
|
|
59
|
+
|
|
60
|
+
## Exemplo (de `rust/examples/seedgrid-backup-example/src/main.rs`)
|
|
61
|
+
```rust
|
|
62
|
+
let mut config = BackupConfig { async_enabled, storage: "filesystem".to_string(), ..BackupConfig::default() };
|
|
63
|
+
config.filesystem.base_path = base_path.to_string();
|
|
64
|
+
let config = Arc::new(config);
|
|
65
|
+
let fs_registry = Arc::new(FileStorageRegistry::new(BuiltInStorageFactories::all()).expect("storage registry"));
|
|
66
|
+
let extract = Arc::new(ExtractDataService::new(pool.clone(), Arc::new(EmptyDomainDatasetProvider)));
|
|
67
|
+
let exporter = Arc::new(CsvZipExporter::new(fs_registry.clone(), extract, config.clone()));
|
|
68
|
+
let exporter_registry = Arc::new(BackupExporterRegistry::new(vec![exporter as Arc<dyn BackupExporter>]).expect("exporter registry"));
|
|
69
|
+
let service = ExportService::new(exporter_registry, ExportJobRepository::new(pool), fs_registry,
|
|
70
|
+
Arc::new(SingleTenantBackupProvider::new()), config, Arc::new(NoopAuditor));
|
|
71
|
+
```
|
|
72
|
+
O exemplo constrói `BackupConfig` à mão (não chama `from_env`).
|
|
73
|
+
|
|
74
|
+
## Testes
|
|
75
|
+
- Unitários em `src/*` (checksum, manifest, CSV/ZIP, config/durações).
|
|
76
|
+
- ITs `tests/csv_zip_exporter_it.rs`, `export_async_flow_it.rs`, `export_resource_it.rs`, `extract_data_it.rs`, `user_event_it.rs` com gate `BACKUP_TEST_DATABASE_URL` (`tests/common/mod.rs`).
|
|
77
|
+
- E2E Testcontainers: `rust/examples/seedgrid-backup-example/tests/`.
|
|
78
|
+
- **Não executados.**
|
|
79
|
+
|
|
80
|
+
## Limitações conhecidas
|
|
81
|
+
|
|
82
|
+
- `SQL_DUMP_ZIP` não tem exporter e `CUSTOM` retorna erro.
|
|
83
|
+
- `includeAttachments` é ignorado e `appVersion` é fixo em `1.0.0`.
|
|
84
|
+
- O mailer de notificação vem ligado por padrão.
|
|
85
|
+
|
|
86
|
+
## Enums
|
|
87
|
+
Equivalentes Java: [[SeedGrid/Extensions/backup/Enums|Enums do backup (Java)]].
|
|
88
|
+
|
|
89
|
+
| Enum | Arquivo | Java equivalente |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `ExportStatus` | `src/enums.rs` | [[SeedGrid/Extensions/backup/Enums#ExportStatus\|ExportStatus]] |
|
|
92
|
+
| `ExportScope` | `src/enums.rs` | [[SeedGrid/Extensions/backup/Enums#ExportScope\|ExportScope]] |
|
|
93
|
+
| `BackupFormat` | `src/enums.rs` | [[SeedGrid/Extensions/backup/Enums#BackupFormat\|BackupFormat]] |
|
|
94
|
+
| `ArtifactType` | `src/enums.rs` | [[SeedGrid/Extensions/backup/Enums#ArtifactType\|ArtifactType]] (aninhado em `ExportArtifact`/`ExportResult` no Java) |
|
|
95
|
+
| `ExportError` | `src/error.rs` | exceções do backup |
|
|
96
|
+
|
|
97
|
+
Todos usam `#[serde(rename_all = "SCREAMING_SNAKE_CASE")]` (JSON igual ao nome Java) e são gravados como `VARCHAR` com o nome em maiúsculas (`as_str()`; leitura por `from_db`, que falha em valor desconhecido). `code()`/`from_code()` usam o código curto (`"done-notified"`, `"csv-zip"`…), case-insensitive.
|
|
98
|
+
|
|
99
|
+
### ExportStatus
|
|
100
|
+
| Valor | `as_str` / `code` | Efeito no Rust |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `Requested` | `REQUESTED` / `requested` | estado inicial da entidade; o claim aceita `Requested` ou `Queued` (`service.rs`) |
|
|
103
|
+
| `Queued` | `QUEUED` / `queued` | gravado por `create_export_job`; `process_queued_exports` lê `status='QUEUED'` |
|
|
104
|
+
| `Running` | `RUNNING` / `running` | gravado no claim; `max_concurrent_exports` conta `status='RUNNING'` |
|
|
105
|
+
| `Done` | `DONE` / `done` | fim com sucesso; `process_notifications` lê `status='DONE'`; baixável |
|
|
106
|
+
| `DoneNotified` | `DONE_NOTIFIED` / `done-notified` | gravado pelo scheduler após o e-mail; baixável e terminal |
|
|
107
|
+
| `Failed` | `FAILED` / `failed` | falha no export; terminal |
|
|
108
|
+
| `Expired` | `EXPIRED` / `expired` | **existe no enum, mas nenhum código o atribui** (a limpeza de retenção apaga o job); terminal |
|
|
109
|
+
| `Cancelled` | `CANCELLED` / `cancelled` | gravado por `cancel_export_job`; terminal |
|
|
110
|
+
|
|
111
|
+
Métodos: `is_downloadable` (`Done`, `DoneNotified`), `is_terminal` (`DoneNotified`, `Failed`, `Expired`, `Cancelled`), `is_in_progress` (`Requested`, `Queued`, `Running`), `display_name`. Coluna `export_jobs.status VARCHAR(20)` (o comentário da migration lista os mesmos 8 valores; **sem CHECK constraint**). Valores iguais ao Java.
|
|
112
|
+
|
|
113
|
+
```mermaid
|
|
114
|
+
stateDiagram-v2
|
|
115
|
+
[*] --> Queued: create_export_job
|
|
116
|
+
Queued --> Running: claim
|
|
117
|
+
Running --> Done: sucesso
|
|
118
|
+
Running --> Failed: erro
|
|
119
|
+
Done --> DoneNotified: e-mail enviado
|
|
120
|
+
Queued --> Cancelled: cancel
|
|
121
|
+
Running --> Cancelled: cancel
|
|
122
|
+
```
|
|
123
|
+
`cancel_export_job` cancela qualquer job em andamento (`Requested`, `Queued` ou `Running`); fora disso devolve `false`. Transições conferidas em `service.rs` e `scheduler.rs`.
|
|
124
|
+
|
|
125
|
+
### ExportScope
|
|
126
|
+
`Domain` (`DOMAIN`/`domain`), `Raw` (`RAW`/`raw`), `Custom` (`CUSTOM`/`custom`). `Domain` usa o `DomainDatasetProvider` do host; `Raw` dumpa as tabelas do schema; `Custom` falha com `CUSTOM scope not implemented` (`exporter.rs`). Coluna `export_jobs.scope VARCHAR(20)`. Iguais ao Java.
|
|
127
|
+
|
|
128
|
+
### BackupFormat
|
|
129
|
+
`CsvZip` (`CSV_ZIP`/`csv-zip`), `SqlDumpZip` (`SQL_DUMP_ZIP`/`sql-dump-zip`); `mime_type()` sempre `application/zip`. `SqlDumpZip` existe, mas não há exporter registrado (o `BackupExporterRegistry` falha se pedido). Coluna `export_jobs.format VARCHAR(20)`. Iguais ao Java.
|
|
130
|
+
|
|
131
|
+
### ArtifactType
|
|
132
|
+
`Zip`, `Manifest`, `Checksums`, `Log` (`ZIP`, `MANIFEST`, `CHECKSUMS`, `LOG`); coluna `export_artifacts.artifact_type VARCHAR(20)`. Só `Zip` é criado (`exporter.rs`) e consultado no download (`service.rs`); os demais existem no enum e no schema, sem código que os produza. Iguais ao Java.
|
|
133
|
+
|
|
134
|
+
### ExportError
|
|
135
|
+
`Export` → HTTP 500; `Validation` → 422; `Retrieval`, `Checksum`, `Storage`, `Database`, `Serde`, `Io` (mapeamento HTTP em `rest.rs`).
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, backup]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-backup
|
|
4
|
+
branch: main
|
|
5
|
+
commit: 3bed4075ea
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Backup (extension Quarkus)
|
|
10
|
+
|
|
11
|
+
Extensão Quarkus para **exportação/backup de dados por tenant e por usuário** (portabilidade LGPD/GDPR): recebe pedidos via REST, cria jobs de export, executa-os de forma assíncrona, gera um ZIP (dados + `manifest.json` + `checksums.txt`), grava o artefato num storage plugável (via `seedgrid-filemanagement`), notifica o solicitante e expira o artefato após um período de retenção.
|
|
12
|
+
|
|
13
|
+
- Configuração: [[SeedGrid/Extensions/backup/Configuracao|Configuração do backup]]
|
|
14
|
+
- Exemplos: [[SeedGrid/Extensions/backup/Exemplos|Exemplos do backup]]
|
|
15
|
+
- Enums: [[SeedGrid/Extensions/backup/Enums|Enums do backup]] (`ExportStatus`, `ExportScope`, `BackupFormat`, `ArtifactType`)
|
|
16
|
+
- [[SeedGrid/Extensions/backup/Rust|Porte Rust]] (crate `rust/seedgrid-rust-crate-backup`)
|
|
17
|
+
|
|
18
|
+
## Funcionalidades (Confirmado)
|
|
19
|
+
|
|
20
|
+
| Funcionalidade | Onde |
|
|
21
|
+
|---|---|
|
|
22
|
+
| REST `/exports` (criar, listar, status, download, cancelar/excluir) | `runtime/.../controllers/ExportController.java` |
|
|
23
|
+
| Ciclo de vida do job `QUEUED → RUNNING → DONE/DONE_NOTIFIED/FAILED/CANCELLED` (`REQUESTED` e `EXPIRED` existem no enum, ver [[SeedGrid/Extensions/backup/Enums#ExportStatus|ExportStatus]]) | `domains/ExportStatus.java`, `services/ExportService.java` |
|
|
24
|
+
| Execução assíncrona em thread de plataforma daemon por job (`Thread.ofPlatform().daemon()`), com transações curtas (claim → export sem transação → gravação final) | `ExportService#createExportJob`, `ExportService#executeExport` |
|
|
25
|
+
| Fila: jobs `QUEUED` iniciados pelo scheduler respeitando teto global de jobs `RUNNING` | `schedulers/BackupSchedulerService#processQueuedExports` |
|
|
26
|
+
| Retenção: limpeza diária (cron fixo `0 1 0 * * ?`, 00:01) de jobs com `expiresAt` vencido + artefatos | `BackupSchedulerService#cleanExpiredExports`, `ExportJobRepositoryImpl#findExpiredJobs` |
|
|
27
|
+
| Notificação "backup pronto" por e-mail (Vert.x Mail) com retry | `schedulers/NotificationSchedulerService`, `services/EmailExportNotificationService` |
|
|
28
|
+
| Evento CDI `SgUserEvent` (canal `backup`, eventos `backup.finished.success` / `backup.finished.error`) disparado dentro da transação final (observers `AFTER_SUCCESS` recebem após o commit) | `ExportService#notifyRequester`, teste `ExportUserEventIT` |
|
|
29
|
+
| Exporters embutidos `CSV_ZIP` e `SQL_DUMP_ZIP` (INSERTs por tabela) | `exporters/CsvZipExporter.java`, `exporters/SqlDumpZipExporter.java` |
|
|
30
|
+
| Escopos `DOMAIN` (entidades JPA do metamodel) e `RAW` (tabelas do schema via `information_schema`) | `services/ExtractDataService.java`, `validate()` dos exporters |
|
|
31
|
+
| Isolamento por dono: status/download/cancel/delete/listagem filtram por `createUserPublicId` → não-dono recebe 404 | `ExportService#findOwnedJob`, `ExportJobRepository#findByPublicIdAndUser` |
|
|
32
|
+
| Rate limit no `POST /exports`: `@SeedGridRateLimit(configKey = "export-create", permits = 10, window = 1, windowUnit = HOURS)` | `ExportController#createExport` |
|
|
33
|
+
| Auditoria `@Audit` em criar/cancelar/excluir/download | `ExportService` |
|
|
34
|
+
| Mapeamento de exceções: `ExportValidationException` → 422, `ExportException` → 500 (Problem Details) | `exceptions/BackupExceptionExtension.java` |
|
|
35
|
+
|
|
36
|
+
## Módulos Maven e coordenadas (Confirmado — `pom.xml`)
|
|
37
|
+
|
|
38
|
+
| Módulo | groupId:artifactId | Versão |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| parent (pom) | `br.com.seedgrid:seedgrid-backup-parent` | `2026.10.09` |
|
|
41
|
+
| runtime | `br.com.seedgrid:seedgrid-backup` | `2026.10.09` |
|
|
42
|
+
| deployment | `br.com.seedgrid:seedgrid-backup-deployment` | `2026.10.09` |
|
|
43
|
+
|
|
44
|
+
Parent: `br.com.seedgrid:seedgrid-parent:2026.07.02`. O host depende só do runtime; o deployment é ligado via `quarkus-extension-maven-plugin` (`META-INF/quarkus-extension.properties`).
|
|
45
|
+
|
|
46
|
+
## Dependências SeedGrid (Confirmado — `runtime/pom.xml`)
|
|
47
|
+
|
|
48
|
+
| Artefato | Versão | Uso |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `seedgrid-commons` | 2026.10.08 | `CurrentUserProvider`, `UserContactProvider`, `BaseEntity`, `PageReq`, `SgUserEvent`, `ApiExceptionExtension` |
|
|
51
|
+
| `seedgrid-privacy` | 2026.07.08 | fixa convergência de versão (comentário no pom) |
|
|
52
|
+
| `seedgrid-filemanagement` | 2026.07.08 | `FileStorageRegistry`, `FileStorage`, `StorageKey`, `StorageOptions` |
|
|
53
|
+
| `seedgrid-resilience-core` (+ `-deployment` no deployment) | 2026.07.08 | `@SeedGridRateLimit` |
|
|
54
|
+
| `seedgrid-audit-core` | 2026.07.08 | `@Audit` (o provider de persistência de auditoria é escolha do host) |
|
|
55
|
+
| `seedgrid-audit-postgresql` | 2026.07.08 | **somente `test`** |
|
|
56
|
+
|
|
57
|
+
Links: [[SeedGrid/Extensions/filemanagement/Visao-geral|filemanagement]], [[SeedGrid/Extensions/resilience/Visao-geral|resilience]], [[SeedGrid/Extensions/audit/Visao-geral|audit]], [[SeedGrid/Extensions/commons/Visao-geral|commons]].
|
|
58
|
+
|
|
59
|
+
Quarkus/terceiros: `quarkus-arc`, `vertx-mail-client`, `quarkus-qute`, `quarkus-hibernate-orm-panache`, `quarkus-jdbc-postgresql`, `quarkus-flyway`, `quarkus-rest-jackson`, `quarkus-scheduler`, `quarkus-hibernate-validator`, `quarkus-smallrye-openapi`, `commons-csv 1.11.0`, `commons-compress 1.26.0`, Lombok (provided). O e-mail usa `vertx-mail-client` diretamente (não há `quarkus-mailer`).
|
|
60
|
+
|
|
61
|
+
## Deployment (Confirmado — `deployment/.../BackupProcessor.java`)
|
|
62
|
+
|
|
63
|
+
- Feature `seedgrid-backup`.
|
|
64
|
+
- `ConfigMappingBuildItem(BackupConfig.class, "seedgrid.backup")`.
|
|
65
|
+
- Beans unremovable: `ExportService`, `ExtractDataService`, `BackupSchedulerService`, `NotificationSchedulerService`, `EmailExportNotificationService`, `BackupExporterRegistry`, `CsvZipExporter`, `SqlDumpZipExporter`, `DefaultTemplateBackupProvider`, `SingleTenantBackupProvider`, `ExportController`.
|
|
66
|
+
- Recurso nativo: `templates/backup-default/html/ready-notification.html`.
|
|
67
|
+
- Não há `*BuildTimeConfig`/`@ConfigRoot`.
|
|
68
|
+
|
|
69
|
+
## Arquitetura e fluxo
|
|
70
|
+
|
|
71
|
+
```mermaid
|
|
72
|
+
sequenceDiagram
|
|
73
|
+
participant C as Cliente
|
|
74
|
+
participant API as ExportController (/exports)
|
|
75
|
+
participant S as ExportService
|
|
76
|
+
participant W as Thread daemon / BackupSchedulerService
|
|
77
|
+
participant E as BackupExporter (CSV_ZIP / SQL_DUMP_ZIP)
|
|
78
|
+
participant FS as FileStorageRegistry (filemanagement)
|
|
79
|
+
participant N as NotificationSchedulerService
|
|
80
|
+
C->>API: POST /exports {format, scope}
|
|
81
|
+
API->>S: createExportJob (grava QUEUED)
|
|
82
|
+
alt seedgrid.backup.async-enabled=true
|
|
83
|
+
S->>W: thread daemon executeExportAsync
|
|
84
|
+
else false
|
|
85
|
+
W->>S: processQueuedExports (a cada queue-poll-interval)
|
|
86
|
+
end
|
|
87
|
+
W->>S: claimJob → RUNNING
|
|
88
|
+
S->>E: validate + export(ExportContext)
|
|
89
|
+
E->>FS: store(zip) em <schema>/exports
|
|
90
|
+
S->>S: DONE, expiresAt = agora + retention-days, SgUserEvent
|
|
91
|
+
N->>C: e-mail "backup pronto" (retry) → DONE_NOTIFIED
|
|
92
|
+
C->>API: GET /exports/{jobId}/download
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Observação (Confirmado): mesmo com `async-enabled=true`, o scheduler de fila também enxerga jobs `QUEUED`; `claimJob` só executa jobs em `REQUESTED`/`QUEUED`, o que evita dupla execução sequencial, mas não há lock pessimista explícito — concorrência entre os dois caminhos é **Não confirmado**.
|
|
96
|
+
|
|
97
|
+
## APIs públicas e pontos de integração
|
|
98
|
+
|
|
99
|
+
### Endpoints REST (Confirmado — `ExportController`, `RestControllerPath`)
|
|
100
|
+
|
|
101
|
+
| Método | Path | Permissão (`@PermissionsAllowed`) | Respostas |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| POST | `/exports` | `BACKUP_CREATE` | 201 + `ExportResponse`; rate limit `export-create` |
|
|
104
|
+
| GET | `/exports?page=&size=` | `BACKUP_READ` | 200 lista do usuário corrente |
|
|
105
|
+
| GET | `/exports/{jobId}` | `BACKUP_READ` | 200 / 404 |
|
|
106
|
+
| GET | `/exports/{jobId}/download` | `BACKUP_DOWNLOAD` | 200 `application/zip` / 404 (não pronto ou não-dono) / 410 (terminal não baixável) |
|
|
107
|
+
| DELETE | `/exports/{jobId}` | `BACKUP_DELETE` | 204 / 404 (cancela se em progresso; senão exclui job + artefatos) |
|
|
108
|
+
|
|
109
|
+
### SPIs e beans substituíveis (Confirmado)
|
|
110
|
+
|
|
111
|
+
| Tipo | Default | Como substituir |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `spi.BackupExporter` | `CsvZipExporter` (`CSV_ZIP`), `SqlDumpZipExporter` (`SQL_DUMP_ZIP`) | novo bean CDI; `BackupExporterRegistry` falha no startup se houver 2 para o mesmo `BackupFormat` |
|
|
114
|
+
| `spi.TenantProvider` | `configs.SingleTenantBackupProvider` (`@DefaultBean`, tenant fixo `"public"`) | bean próprio (hosts multitenant) |
|
|
115
|
+
| `spi.ExportNotificationService` | `services.EmailExportNotificationService` (`@DefaultBean`) | bean próprio |
|
|
116
|
+
| `spi.TemplateBackupProvider` | `spi.impl.DefaultTemplateBackupProvider` (`@DefaultBean`; usa `templates/backup/ready-notification.html` do host, senão `templates/backup-default/html/ready-notification.html`; placeholders `{{jobId}}`, `{{format}}`, `{{scope}}`, `{{sizeBytes}}`, `{{finishedAt}}`) | bean próprio ou template no classpath do host |
|
|
117
|
+
| `commons.persistence.spi.CurrentUserProvider` | nenhum na extensão | **o host deve fornecer** |
|
|
118
|
+
| `commons.spi.UserContactProvider` | nenhum na extensão | necessário para o e-mail (destinatário via `provideByPublicId`) — Inferência: o host/commons fornece |
|
|
119
|
+
|
|
120
|
+
### Eventos
|
|
121
|
+
- `SgUserEvent(userPublicId, "backup", "backup.finished.success" | "backup.finished.error", {exportPublicId, status})` — só quando o job tem `createUserPublicId`.
|
|
122
|
+
|
|
123
|
+
## Persistência e migrations (Confirmado)
|
|
124
|
+
|
|
125
|
+
`runtime/src/main/resources/db/migration/backup/`, tabela de histórico Flyway `flyway_schema_history_backup` (via `microprofile-config.properties`):
|
|
126
|
+
|
|
127
|
+
| Versão | Conteúdo |
|
|
128
|
+
|---|---|
|
|
129
|
+
| V400 | `export_jobs`, `export_artifacts` (PostgreSQL, `TIMESTAMPTZ`, FK `ON DELETE CASCADE`) |
|
|
130
|
+
| V401 | Insere permissões `BACKUP_CREATE/READ/DOWNLOAD/DELETE` em `permissions` e vincula ao papel `ADMIN` (`roles`, `role_permissions`) — exige tabelas da extensão de segurança |
|
|
131
|
+
| V402 | Coluna `active` nas duas tabelas |
|
|
132
|
+
| V403 | `audience = null` nas permissões de backup (se `permissions` existir) |
|
|
133
|
+
|
|
134
|
+
## Testes (não executados)
|
|
135
|
+
|
|
136
|
+
`runtime/src/test/java/br/com/seedgrid/backup/` (Quarkus DevServices PostgreSQL 16, migrations de teste em `db/testdata/backup`):
|
|
137
|
+
- `controllers/ExportResourceIT` — endpoints REST; `controllers/ExportAsyncFlowIT` — pipeline assíncrono real com `SingleTenantBackupProvider` (perfil com `async-enabled=true`).
|
|
138
|
+
- `exporters/CsvZipExporterIT`, `exporters/SqlDumpZipExporterIT` — geração de ZIP.
|
|
139
|
+
- `services/ExtractDataServiceIT` — extração RAW/DOMAIN e exclusões; `services/ExportUserEventIT` — `SgUserEvent` após commit (sucesso/falha).
|
|
140
|
+
- `configs/SingleTenantBackupProviderTest`, `utils/ChecksumUtilTest` — unitários.
|
|
141
|
+
- Suporte: `TestTenantProvider` (`@Alternative @Priority(1)`), `TestCurrentUserProvider`, `support/SampleDomainEntity`.
|
|
142
|
+
|
|
143
|
+
## Limitações
|
|
144
|
+
|
|
145
|
+
- `options` do `ExportRequest` (mapa livre) é serializado no job e repassado ao `ExportContext` (`getOptions()`/`getOption(key, default)`); os exporters embutidos não leem nenhuma opção — só exporters customizados podem usá-lo. **Confirmado** (`ExportService#buildExportContext`).
|
|
146
|
+
- Limpeza por retenção tem cron fixo (`0 1 0 * * ?`), não configurável. **Confirmado**.
|
|
147
|
+
- Banco: PostgreSQL (migrations, `information_schema`, `gen_random_uuid()`).
|
|
148
|
+
- `generateDownloadUrl` (URL assinada) lança `UnsupportedOperationException` no adapter padrão; download passa os bytes pela API.
|
|
149
|
+
- Notificação por e-mail fica **ativa por padrão** apontando para `smtp.gmail.com` sem credenciais (fallbacks do `microprofile-config.properties`) — ver [[SeedGrid/Extensions/backup/Configuracao|Configuração]].
|
|
150
|
+
- `appVersion("1.0.0")` fixo no manifest (TODO no código).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, billing, rust, configuracao]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-billing
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# billing — Configuração Rust
|
|
10
|
+
|
|
11
|
+
Visão do crate: [[SeedGrid/Extensions/billing/Rust|Porte Rust do billing]] · Java: [[SeedGrid/Extensions/billing/Configuracao|Configuração do billing (Java)]].
|
|
12
|
+
|
|
13
|
+
## Cabeçalho
|
|
14
|
+
| Item | Valor |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Struct | `StripeConfig` (prefixo Java `seedgrid.billing.stripe`) — `rust/seedgrid-rust-crate-billing/src/config.rs` |
|
|
17
|
+
| Mecanismo | `StripeConfig::from_env()` (`std::env::var`), ou struct montada pelo host |
|
|
18
|
+
| Quem chama | `BillingPlatform::assemble` chama `StripeConfig::from_env()` |
|
|
19
|
+
| Leitura | no boot (uma vez) |
|
|
20
|
+
|
|
21
|
+
Helpers: `opt(name)` faz `trim` e trata vazio como ausente; `opt_any(names)` devolve o primeiro não vazio (primário antes do alias). `from_env` nunca falha: `api_key`/`webhook_secret` ausentes viram `""`.
|
|
22
|
+
|
|
23
|
+
## Stripe
|
|
24
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
25
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
26
|
+
| 🔒 `SEEDGRID_BILLING_STRIPE_APIKEY` / alias `SEEDGRID_BILLING_STRIPE_API_KEY` (Java `seedgrid.billing.stripe.apiKey`) | String | chave secreta Stripe | `""` | Sim para habilitar via `BillingPlatform` (vazio → `Ok(None)`, billing desligado) | `Authorization: Bearer`; prefixo `sk_test` habilita Test Clock | `stripe/provider.rs` (transporte, Test Clock), `platform.rs` | `test_clock_enabled` | `StripeConfig::from_env()` | `config.rs`; `platform.rs` → `assemble` |
|
|
27
|
+
| 🔒 `SEEDGRID_BILLING_STRIPE_WEBHOOK_SECRET` (Java `webhookSecret`) | String | segredo `whsec_...` | `""` | Sim (na prática): sem ele a verificação de assinatura falha | verifica assinatura do webhook | `stripe/provider.rs` → `signature::construct_event` | — | `from_env()` | `config.rs`, `stripe/signature.rs` |
|
|
28
|
+
| `SEEDGRID_BILLING_STRIPE_DEFAULT_SUCCESS_URL` / alias `SEEDGRID_BILLING_STRPE_DEFAULT_SUCCESS_URL` (Java `defaultSuccessUrl`) | String | URL | `""` | Não | usada no checkout quando o request não traz URL | `stripe/provider.rs` | grafia correta tem precedência (teste `default_success_url_accepts_strpe_typo_alias_with_stripe_precedence`) | `from_env()` | `config.rs` |
|
|
29
|
+
| `SEEDGRID_BILLING_STRIPE_DEFAULT_CANCEL_URL` (Java `defaultCancelUrl`) | String | URL | `""` | Não | idem para cancelamento | `stripe/provider.rs` | — | `from_env()` | `config.rs` |
|
|
30
|
+
| `SEEDGRID_BILLING_STRIPE_TEST_CLOCK_ENABLED` (Java `test-clock-enabled`) | bool | `true`/`false` (parse `bool`, após `trim`) | `true` | Não | com chave `sk_test`, cria a assinatura sob um Test Clock | `stripe/provider.rs` | `api_key` | `from_env()` | `config.rs`, `provider.rs` |
|
|
31
|
+
| `SEEDGRID_BILLING_STRIPE_PRODUCT` (Java `seedgrid.billing.stripe.product`) | `Option<String>` | id de produto | — | Não | `ensure_product_bootstrap` garante o produto se definido | `stripe/bootstrap.rs` (host precisa chamar) | `product_name` | `from_env()` | `config.rs`, `bootstrap.rs` |
|
|
32
|
+
| `SEEDGRID_BILLING_STRIPE_PRODUCT_NAME` (Java `product-name`) | `Option<String>` | texto | — | Não | nome do produto no bootstrap | `stripe/bootstrap.rs` | `product` | `from_env()` | idem |
|
|
33
|
+
| `SEEDGRID_BILLING_STRIPE_API_BASE` | String | URL | `https://api.stripe.com` (`DEFAULT_STRIPE_API_BASE`) | Não | base da API (útil em testes/mocks) | `stripe/provider.rs` | sem equivalente Java | `from_env()` | `config.rs` |
|
|
34
|
+
|
|
35
|
+
Mapeamento Java ↔ env: os nomes Java vêm de `@ConfigProperty` em `java/seedgrid-quarkus-ext-billing/seedgrid-billing-stripe/runtime/.../StripeBillingProvider.java` e `StripeProductBootstrap.java` (**Confirmado**). Os nomes de env do Rust **não** seguem exatamente a regra MicroProfile para chaves camelCase (ex.: `apiKey` → `SEEDGRID_BILLING_STRIPE_APIKEY`), são convenção do projeto (doc de `config.rs`).
|
|
36
|
+
|
|
37
|
+
## Structs
|
|
38
|
+
| Campo | `Default` |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `StripeConfig.api_key`, `webhook_secret`, `default_success_url`, `default_cancel_url` | `""` |
|
|
41
|
+
| `StripeConfig.test_clock_enabled` | `true` |
|
|
42
|
+
| `StripeConfig.product`, `product_name` | `None` |
|
|
43
|
+
| `StripeConfig.api_base` | `https://api.stripe.com` |
|
|
44
|
+
|
|
45
|
+
## Features Cargo
|
|
46
|
+
| Feature | Padrão | Efeito |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `postgres` | sim | `PgBillingEventRepository`, `migrate`, `MIGRATOR` |
|
|
49
|
+
| `stripe` | sim | módulo `stripe` (provider, assinatura, bootstrap) |
|
|
50
|
+
| `postgres` + `stripe` | — | habilitam `BillingPlatform`/`BillingOverrides` |
|
|
51
|
+
|
|
52
|
+
## Configuração não-env
|
|
53
|
+
- `BillingApiStateBuilder::authorizer(...)` (default `AllowAllBillingAuthorizer`).
|
|
54
|
+
- Rate limits fixos em código (`checkout_rate_limit`, `portal_rate_limit`, `webhook_rate_limit`); ver [[SeedGrid/Extensions/resilience/Configuracao-Rust|Configuração Rust do resilience]].
|
|
55
|
+
|
|
56
|
+
## Somente testes
|
|
57
|
+
| Variável | Onde |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `BILLING_IT_PG_URL` | `tests/pg_billing_events_it.rs` |
|
|
60
|
+
| `BILLING_STRIPE_IT_BASE`, 🔒 `BILLING_STRIPE_IT_KEY` | `tests/stripe_transport_it.rs` |
|
|
61
|
+
|
|
62
|
+
## Configuração mínima
|
|
63
|
+
```dotenv
|
|
64
|
+
SEEDGRID_BILLING_STRIPE_APIKEY=<SEGREDO:stripe-api-key>
|
|
65
|
+
SEEDGRID_BILLING_STRIPE_WEBHOOK_SECRET=<SEGREDO:stripe-webhook-secret>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Configuração completa comentada
|
|
69
|
+
```dotenv
|
|
70
|
+
SEEDGRID_BILLING_STRIPE_APIKEY=<SEGREDO:stripe-api-key> # alias: SEEDGRID_BILLING_STRIPE_API_KEY
|
|
71
|
+
SEEDGRID_BILLING_STRIPE_WEBHOOK_SECRET=<SEGREDO:stripe-webhook-secret>
|
|
72
|
+
SEEDGRID_BILLING_STRIPE_DEFAULT_SUCCESS_URL=https://<app>/assinatura?ok=1 # alias legado: ..._STRPE_...
|
|
73
|
+
SEEDGRID_BILLING_STRIPE_DEFAULT_CANCEL_URL=https://<app>/assinatura?cancel=1
|
|
74
|
+
SEEDGRID_BILLING_STRIPE_TEST_CLOCK_ENABLED=true # só tem efeito com chave sk_test
|
|
75
|
+
SEEDGRID_BILLING_STRIPE_PRODUCT=<id-produto> # bootstrap (host chama ensure_product_bootstrap)
|
|
76
|
+
SEEDGRID_BILLING_STRIPE_PRODUCT_NAME=<nome>
|
|
77
|
+
# SEEDGRID_BILLING_STRIPE_API_BASE=https://api.stripe.com
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Receitas
|
|
81
|
+
- **Habilitar com Stripe**: definir a API key e o webhook secret; `BillingPlatform::assemble(Some(&pool), BillingOverrides::default())`; montar `router(state)` e acoplar os rate limits.
|
|
82
|
+
- **Testes E2E com tempo avançado**: chave `sk_test_...` e `SEEDGRID_BILLING_STRIPE_TEST_CLOCK_ENABLED=true`.
|
|
83
|
+
- **Mock do Stripe**: `SEEDGRID_BILLING_STRIPE_API_BASE=http://localhost:<porta>`.
|
|
84
|
+
|
|
85
|
+
## Dúvidas e lacunas
|
|
86
|
+
- Grupos de config do billing-core Java atual (`trial`, `catalog`, `checkout`, `portal`, `access-gate`, `feature-gate`, `reconciliation`, `api`, `business-timezone`, `currency`, …) **não existem** no Rust.
|