@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.
Files changed (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -2
  3. package/dist/adapters/claude.js +114 -0
  4. package/dist/adapters/codex.js +108 -0
  5. package/dist/adapters/index.js +17 -0
  6. package/dist/adapters/shared.js +142 -0
  7. package/dist/adapters/types.js +1 -0
  8. package/dist/cli.js +209 -0
  9. package/dist/commands/common.js +98 -0
  10. package/dist/commands/doctor.js +290 -0
  11. package/dist/commands/init.js +9 -0
  12. package/dist/commands/install.js +107 -0
  13. package/dist/commands/remove.js +54 -0
  14. package/dist/commands/review.js +127 -0
  15. package/dist/commands/selfinstall.js +63 -0
  16. package/dist/commands/status.js +73 -0
  17. package/dist/commands/update.js +8 -0
  18. package/dist/commands/validate.js +27 -0
  19. package/dist/core/apply.js +181 -0
  20. package/dist/core/blocks.js +64 -0
  21. package/dist/core/content.js +528 -0
  22. package/dist/core/env.js +40 -0
  23. package/dist/core/frontmatter.js +29 -0
  24. package/dist/core/hash.js +14 -0
  25. package/dist/core/inspect.js +51 -0
  26. package/dist/core/lock.js +124 -0
  27. package/dist/core/paths.js +65 -0
  28. package/dist/core/plan.js +242 -0
  29. package/dist/core/tools.js +62 -0
  30. package/dist/core/types.js +11 -0
  31. package/dist/core/updates.js +121 -0
  32. package/docs/arquitetura.md +80 -0
  33. package/docs/compatibilidade.md +50 -0
  34. package/docs/formato.md +155 -0
  35. package/docs/instalacao.md +105 -0
  36. package/docs/manutencao.md +115 -0
  37. package/package.json +43 -4
  38. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
  39. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
  40. package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
  41. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
  42. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
  43. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
  44. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
  45. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
  46. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
  47. package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
  48. package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
  49. package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
  50. package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
  51. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
  52. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
  53. package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
  54. package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
  55. package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
  56. package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
  57. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
  58. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
  59. package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
  60. package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
  61. package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
  62. package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
  63. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
  64. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
  65. package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
  66. package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
  67. package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
  68. package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
  69. package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
  70. package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
  71. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
  72. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
  73. package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
  74. package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
  75. package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
  76. package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
  77. package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
  78. package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
  79. package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
  80. package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
  81. package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
  82. package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
  83. package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
  84. package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
  85. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
  86. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
  87. package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
  88. package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
  89. package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
  90. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
  91. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
  92. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
  93. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
  94. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
  95. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
  96. package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
  97. package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
  98. package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
  99. package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
  100. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
  101. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
  102. package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
  103. package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
  104. package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
  105. package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
  106. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
  107. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
  108. package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
  109. package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
  110. package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
  111. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
  112. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
  113. package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
  114. package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
  115. package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
  116. package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
  117. package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
  118. package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
  119. package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
  120. package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
  121. package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
  122. package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
  123. package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
  124. package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
  125. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
  126. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
  127. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
  128. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
  129. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
  130. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
  131. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
  132. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
  133. package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
  134. package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
  135. package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
  136. package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
  137. package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
  138. package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
  139. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
  140. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
  141. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
  142. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
  143. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
  144. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
  145. package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
  146. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
  147. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
  148. package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
  149. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
  150. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
  151. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
  152. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
  153. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
  154. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
  155. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
  156. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
  157. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
  158. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
  159. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
  160. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
  161. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
  162. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
  163. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
  164. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
  165. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
  166. package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
  167. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
  168. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
  169. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
  170. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
  171. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
  172. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
  173. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
  174. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
  175. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
  176. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
  177. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
  178. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
  179. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
  180. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
  181. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
  182. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
  183. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
  184. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
  185. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
  186. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
  187. package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
  188. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
  189. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
  190. package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
  191. package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
  192. package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
  193. package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
  194. package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
  195. package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
  196. package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
  197. package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
  198. package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
  199. package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
  200. package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
  201. package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
  202. package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
  203. package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
  204. package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
  205. package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
  206. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
  207. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
  208. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
  209. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
  210. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
  211. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
  212. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
  213. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
  214. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
  215. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
  216. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
  217. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
  218. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
  219. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
  220. package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
  221. package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
  222. package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
  223. package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
  224. package/seedgridKB/SeedGrid/Versoes.md +64 -0
  225. package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
  226. package/seedgridKB/manifest.json +142 -0
@@ -0,0 +1,345 @@
1
+ ---
2
+ tags: [seedgrid, extension, subdomain-tenancy, configuracao]
3
+ fonte: java/seedgrid-quarkus-ext-subdomain-tenancy
4
+ branch: main
5
+ commit: fe62530a29
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # subdomain-tenancy — Configuração (Quarkus)
10
+
11
+ Visão geral: [[SeedGrid/Extensions/subdomain-tenancy/Visao-geral|Visão geral do subdomain-tenancy]] · Exemplos: [[SeedGrid/Extensions/subdomain-tenancy/Exemplos|Exemplos do subdomain-tenancy]] · Porte Rust: [[SeedGrid/Extensions/subdomain-tenancy/Rust|Porte Rust]]
12
+
13
+ > [!info] Fonte da verdade
14
+ > Tudo abaixo foi lido no código (commit `fe62530a29`). Só estão listadas as chaves que têm efeito. O `README.md` e os `docs/` da extension foram revisados contra o código em 2026-10-14; os relatórios de auditoria na raiz do repositório são históricos.
15
+
16
+ ## 1. Cabeçalho
17
+
18
+ **Abreviações usadas na coluna Origem** (todas relativas a `seedgrid-platform`):
19
+ - `RT/` = `java/seedgrid-quarkus-ext-subdomain-tenancy/runtime/src/main/java/br/com/seedgrid/subdomaintenancy/`
20
+ - `MPC` = `java/seedgrid-quarkus-ext-subdomain-tenancy/runtime/src/main/resources/META-INF/microprofile-config.properties`
21
+ - `PROC` = `java/seedgrid-quarkus-ext-subdomain-tenancy/deployment/src/main/java/br/com/seedgrid/subdomaintenancy/deployment/SubdomainTenancyProcessor.java`
22
+
23
+ | Item | Valor |
24
+ |---|---|
25
+ | Prefixo principal | `seedgrid.subdomain-tenancy` |
26
+ | Prefixos secundários | `seedgrid.subdomain-tenancy.admin-user`, `seedgrid.subdomain-tenancy.mailer`, `database.master` |
27
+ | Classes `@ConfigMapping` | `RT/configs/SubdomainTenancyBridgeConfig` (prefixo `seedgrid.subdomain-tenancy`, cobre quase tudo), `RT/configs/SubdomainTenancyAdminUserConfig` (`…admin-user`). As chaves `…mailer.*` e `database.master.*` têm efeito só via expansão de config (ver 2.2 e 2.7) |
28
+ | `@ConfigProperty` | `RT/configs/SubdomainTenancyConfig` (bean `@ApplicationScoped` com campos públicos) e injeção direta em construtores: `TenantConnectionResolverImpl`, `TenantMigrationCoordinator`, `TenantMigrationGateFilter`, `MigrationService`, `Migrations`, `TenantService`, `TenantProvisioningService`, `TenantOpenApiController`, `TenantAuditScopeProvider`, `TenantAwareMongoProducer` |
29
+ | Leitura programática | `Config#getOptionalValue` em `RT/resolvers/TenantConnectionResolverImpl#getTenantUsername/#getTenantPassword` e `RT/mongodb/MongoTenantResolverImpl` (construtor) |
30
+ | Defaults publicados | `MPC` (ordinal 100 — o `application.properties` do host vence) e `RunTimeConfigurationDefaultBuildItem` em `PROC#registerDatasourceDefaults` |
31
+ | `@ConfigRoot` / `*BuildTimeConfig` | **Não existem** (o `deployment` não declara config própria) |
32
+ | `@IfBuildProperty` / `@LookupIfProperty` / `@UnlessBuildProperty` | **Não usados** (o comentário em `RT/flyway/MigrationService` explica que a decisão é em runtime) |
33
+ | Fase | Todas as propriedades próprias são **runtime**, exceto `master.entity-packages` e `tenant.entity-packages`, que só são consumidas por expansão em `quarkus.hibernate-orm[.master].packages` (config de **build** do Hibernate ORM — Inferência baseada no comportamento do Quarkus) |
34
+
35
+ **Dupla declaração.** Muitas chaves aparecem ao mesmo tempo no `SubdomainTenancyBridgeConfig` (que, segundo o Javadoc, existe para "evitar avisos de chaves desconhecidas") **e** num `@ConfigProperty` com `defaultValue` próprio. Quando o consumidor real é o `@ConfigProperty`, o padrão efetivo é o do `MPC` (se houver) ou o do `defaultValue`; o `@WithDefault` do mapping só importa onde o mapping é lido. Os valores coincidem em todos os casos verificados.
36
+
37
+ **Variáveis de ambiente.** O `MPC` define a maioria das chaves como `${SEEDGRID_SUBDOMAIN_TENANCY_…:padrão}` — esses nomes de env var são lidos **explicitamente** (Confirmado) e aparecem na coluna Comportamento. Nomes curtos como `…_MASTER_DB_URL` **não** seguem a regra automática do MicroProfile; a regra automática (`SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DATASOURCE_JDBC_URL`) também funciona, porque env var (ordinal 300) vence o `MPC`.
38
+
39
+ ## 2. Propriedades da extension
40
+
41
+ ### 2.1 Resolução de tenant e rotas
42
+
43
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
44
+ |---|---|---|---|---|---|---|---|---|---|
45
+ | `seedgrid.subdomain-tenancy.domain-suffix` | `Optional<String>` | sufixo DNS sem ponto inicial, ex. `crm.seedgrid.com.br` | `—` (MPC: `${SEEDGRID_SUBDOMAIN_TENANCY_DOMAIN_SUFFIX:}` → vazio = ausente) | Condicional: sem ela **todo** request cai no tenant default (`master`) | `TenantHostExtractor` remove porta, põe em minúsculas, exige `host.endsWith(suffix)`, retira o sufixo e o ponto; o prefixo precisa casar `^[a-z0-9-]+$`, senão retorna `null` | Resolução do tenant por host (`X-Forwarded-Host` > `Host`), claim `subdomain` do JWT, validação do JWT contra o host, filtragem do OpenAPI | `default-tenant`; regex do signup (`^[a-z0-9_]{5,50}$`) é **diferente** — ver Dúvidas | runtime | Decl.: `RT/configs/SubdomainTenancyConfig#domainSuffix`, `SubdomainTenancyBridgeConfig#domainSuffix()`, `MPC`. Consumo: `RT/resolvers/TenantHostExtractor#extractTenantFromHost` |
46
+ | `seedgrid.subdomain-tenancy.tenant-header` | `Optional<String>` | nome de header HTTP | `—` | Não | Se presente e o header vier preenchido, `QuarkusTenantResolver` usa seu valor como tenant — mas só quando o `TenantContext` está vazio. Em requests JAX-RS o `TenantResolutionFilter` sempre grava um tenant (o do host ou `master`), então o header **não** tem efeito nelas; vale apenas para requests HTTP que não passam por esse filtro. Gate de migração, OpenAPI filtrado e JWT ignoram o header | `TenantResolver` do Hibernate (PU default) | Não declarada no `SubdomainTenancyBridgeConfig` | runtime | Decl.: `RT/configs/SubdomainTenancyConfig#tenantHeader`. Consumo: `RT/resolvers/QuarkusTenantResolver#resolveTenantId` |
47
+ | `seedgrid.subdomain-tenancy.default-tenant` | `String` | id de tenant | `master` | Não | Tenant devolvido quando nada é resolvido; também decide "contexto master" no OpenAPI e a claim `audience` (`platform` × `client`) do JWT | `QuarkusTenantResolver#getDefaultTenantId`, `TenantOpenApiController`, `SubdomainTenancyJwtTokenCustomizer#isPlatformTenant`, `MongoTenantResolverImpl` | Vários componentes usam o literal `"master"` fixo (`TenantResolutionFilter`, `TenantConnectionResolverImpl`, `TenantMigrationCoordinator`, controllers internos) — trocar o valor gera comportamento inconsistente (**Inferência**) | runtime | Decl.: `RT/configs/SubdomainTenancyConfig#defaultTenant` (`defaultValue="master"`), `SubdomainTenancyBridgeConfig#defaultTenant()`. Consumo: ver Uso |
48
+ | `seedgrid.subdomain-tenancy.product-prefix` | `Optional<String>` | identificador curto, ex. `kb` | `—` | Não (recomendada) | Nome do banco do tenant = `<prefix>_<tenant>` (sem prefixo: `<tenant>`). Também prefixa a chave de auditoria (`<prefix>/<tenant>`) e os bancos Mongo | `Utils#buildTenantDatabaseName` (resolver, provisionamento, coordinator), `TenantAuditScopeProvider#tenantKey`, `TenantAwareMongoProducer`, `MongoTenantResolverImpl` | Mudar depois de haver tenants provisionados aponta para outros bancos (**Inferência**) | runtime | Decl.: `SubdomainTenancyConfig#productPrefix`, `SubdomainTenancyBridgeConfig#productPrefix()`, `@ConfigProperty` em `TenantConnectionResolverImpl`, `TenantProvisioningService`, `TenantAuditScopeProvider`, `TenantAwareMongoProducer`; `getOptionalValue` em `MongoTenantResolverImpl` |
49
+ | `seedgrid.subdomain-tenancy.openapi.master-only-paths` | `List<String>` (CSV) | prefixos de path | `/admin` (MPC: `${SEEDGRID_SUBDOMAIN_TENANCY_OPENAPI_MASTER_ONLY_PATHS:/admin}`) | Não | Em contexto de tenant, `GET /public/tenant-openapi` remove os paths com esses prefixos (barra final removida), além das operações com tag `master-only` | `TenantOpenApiController#filterSpec` | Tags `master-only`/`tenant-only` (`@MasterOnly`/`@TenantOnly`) | runtime | Decl.: `SubdomainTenancyBridgeConfig.OpenApi#masterOnlyPaths()`, `@ConfigProperty` em `RT/controllers/TenantOpenApiController` (construtor), `MPC` |
50
+
51
+ ### 2.2 Datasource master
52
+
53
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
54
+ |---|---|---|---|---|---|---|---|---|---|
55
+ | `seedgrid.subdomain-tenancy.master.datasource.jdbc.url` | `Optional<String>` | URL JDBC PostgreSQL | MPC: `jdbc:postgresql://localhost:5432/master` (env `SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DB_URL`) | Sim em produção (o padrão aponta para localhost) | Copiada para `quarkus.datasource.master.jdbc.url`; usada para abrir um `SimpleDriverDataSource` próprio nas migrations do master e na listagem de tenants ativos. Se ausente no mapping, o código cai em `jdbc://postgress:localhost:5432/xxx_master` (URL inválida) | Datasource nomeado `master`, `MigrationService#masterMigrate`, `#listActiveTenantIdsPage` | `PROC` também registra default runtime `${seedgrid.subdomain-tenancy.master.datasource.jdbc.url:jdbc:postgresql://localhost:5432/master}` | runtime | Decl.: `SubdomainTenancyBridgeConfig.MasterJdbc#url()`, `MPC`. Consumo: `RT/flyway/MigrationService`, ponte `quarkus.datasource.master.jdbc.url` |
56
+ | `seedgrid.subdomain-tenancy.master.datasource.username` | `Optional<String>` | usuário do banco | MPC: `postgres` (env `SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DB_USERNAME`) | Sim em produção | Ponte para `quarkus.datasource.master.username`; fallback `postgres` no código | idem | — | runtime | Decl.: `SubdomainTenancyBridgeConfig.MasterDatasource#username()`, `MPC`. Consumo: `MigrationService` |
57
+ | 🔒 `seedgrid.subdomain-tenancy.master.datasource.password` | `Optional<String>` | segredo | MPC: `postgres` (env `SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DB_PASSWORD`) — valor de desenvolvimento | Sim em produção | Ponte para `quarkus.datasource.master.password`; fallback `postgres` no código | idem | — | runtime | Decl.: `SubdomainTenancyBridgeConfig.MasterDatasource#password()`, `MPC`. Consumo: `MigrationService` |
58
+ | `seedgrid.subdomain-tenancy.master.datasource.jdbc.min-size` | `Optional<Integer>` | ≥ 0 | MPC: `1` (env `SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DB_POOL_MIN`) | Não | Só é lida via ponte `quarkus.datasource.master.jdbc.min-size` | Pool Agroal do master | — | runtime | Decl.: `SubdomainTenancyBridgeConfig.MasterJdbc#minSize()`, `MPC` |
59
+ | `seedgrid.subdomain-tenancy.master.datasource.jdbc.max-size` | `Optional<Integer>` | ≥ 1 | MPC: `10` (env `SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DB_POOL_MAX`) | Não | Ponte `quarkus.datasource.master.jdbc.max-size` | Pool Agroal do master | — | runtime | Decl.: `SubdomainTenancyBridgeConfig.MasterJdbc#maxSize()`, `MPC` |
60
+ | `seedgrid.subdomain-tenancy.master.entity-packages` | `Optional<String>` | pacotes Java (CSV) | MPC: vazio (env `SEEDGRID_SUBDOMAIN_TENANCY_MASTER_ENTITY_PACKAGES`) | Não | Prefixada em `quarkus.hibernate-orm.master.packages=${…master.entity-packages},br.com.seedgrid.subdomaintenancy.entities,br.com.seedgrid.billing.entities,br.com.seedgrid.security.entities` | PU `master` | Se o host redefinir `quarkus.hibernate-orm.master.packages` (como o exemplo), esta chave só vale se ele a reutilizar | build (via expansão — Inferência) | Decl.: `SubdomainTenancyBridgeConfig.Master#entityPackages()`, `MPC` |
61
+ | `seedgrid.subdomain-tenancy.master.migrations.location.additional` | `Optional<String>` (CSV) | locations Flyway, ex. `classpath:db/migration/master-extra` | MPC: vazio | Não | Anexadas à base `classpath:db/migration/master` no mesmo history `flyway_schema_history_master`; versões precisam ser distintas da base | `Migrations#migrateMasterSchema` (startup) | Mesmo history → colisão de versão falha o Flyway | runtime | Decl.: `SubdomainTenancyBridgeConfig.Migrations#locationAdditional()` (`@WithName("location.additional")`), `SubdomainTenancyConfig#masterMigrationsLocationAdditional`, `MPC`. Consumo: `RT/flyway/Migrations` (construtor) |
62
+ | `database.master.subdomain` | `Optional<String>` | texto | MPC: `${PRODUCT_PREFIX:app}` | Não | Nenhum código da extension a lê (`DatabaseMasterConfig` não é injetado); é um valor auxiliar publicado para o host referenciar em expressões | Expressões `${database.master.subdomain}` no host | Lê a env `PRODUCT_PREFIX`; base de `database.master.name` | runtime | Decl.: `RT/configs/DatabaseMasterConfig#subdomain()`, `MPC` |
63
+ | `database.master.name` | `Optional<String>` | texto | MPC: `${database.master.subdomain}_master` | Não | Valor auxiliar para expressões do host; ex. real em `java/seedgrid-test-multitenancy/src/main/resources/application.properties`: `…master.datasource.jdbc.url=${SEEDGRID_SUBDOMAIN_TENANCY_MASTER_DB_URL:jdbc:postgresql://localhost:5439/${database.master.name}}` | Expressões do host | `database.master.subdomain` | runtime | Decl.: `RT/configs/DatabaseMasterConfig#name()`, `MPC` |
64
+
65
+ ### 2.3 Datasource dos tenants (pool, cache e limite)
66
+
67
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
68
+ |---|---|---|---|---|---|---|---|---|---|
69
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.url` | `Optional<String>` | URL JDBC base **sem** banco, ex. `jdbc:postgresql://host:5432` | `—` (sem `url` nem `url-pattern`: `jdbc:postgresql://localhost:5439/{tenant}`) | Condicional: uma entre `url` e `url-pattern` em produção | `getEffectiveUrlPattern()` remove `/` final e acrescenta `/{tenant}`; `{tenant}` vira o nome do banco (`<prefix>_<tenant>`) | `TenantConnectionResolverImpl`, `TenantProvisioningService#createTenantWithAdmin`, `TenantMigrationCoordinator` | `url-pattern` tem precedência; `product-prefix` | runtime | Decl.: `SubdomainTenancyBridgeConfig.TenantJdbc#url()`/`#getEffectiveUrlPattern()` |
70
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.url-pattern` | `Optional<String>` | URL com placeholder `{tenant}` | `—` | Condicional (ver acima) | Se não-vazia, usada como está (Javadoc: compatibilidade/legado) | idem | Vence `jdbc.url` | runtime | Decl.: `SubdomainTenancyBridgeConfig.TenantJdbc#urlPattern()` |
71
+ | `seedgrid.subdomain-tenancy.tenant.datasource.username` | `Optional<String>` | usuário do banco | `—` no MPC; fallback `postgres` no código | Sim em produção | Usuário de todos os bancos de tenant; também usado como `OWNER` no `CREATE DATABASE` (provisionamento) | Resolver (via `getOptionalValue`, vazio → `postgres`), provisionamento e coordinator (via mapping) | Precisa de permissão `CREATE DATABASE` | runtime | Decl.: `SubdomainTenancyBridgeConfig.TenantDatasource#username()`. Consumo: `TenantConnectionResolverImpl#getTenantUsername`, `TenantProvisioningService`, `TenantMigrationCoordinator` |
72
+ | 🔒 `seedgrid.subdomain-tenancy.tenant.datasource.password` | `Optional<String>` | segredo | `—` no MPC; fallback `postgres` no código | Sim em produção | idem | idem | — | runtime | Decl.: `SubdomainTenancyBridgeConfig.TenantDatasource#password()`. Consumo: `TenantConnectionResolverImpl#getTenantPassword`, `TenantProvisioningService`, `TenantMigrationCoordinator` |
73
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.driver` | `String` | FQCN de driver JDBC | `org.postgresql.Driver` | Não | `Class.forName(driver)` antes de criar o pool do tenant | `TenantConnectionResolverImpl#createDataSourceForTenant` | Provisionamento/coordinator não usam esta chave | runtime | Decl.: `@ConfigProperty` em `TenantConnectionResolverImpl` (construtor), `SubdomainTenancyBridgeConfig.TenantJdbc#driver()` |
74
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.min-size` | `Optional<Integer>` | ≥ 0 | MPC: `0` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DB_POOL_MIN`) | Não | Pool mínimo por tenant (`Math.max(0, v)`) | `TenantConnectionResolverImpl` | Também copiada para `quarkus.datasource.jdbc.min-size` (datasource default) | runtime | Decl.: `SubdomainTenancyBridgeConfig.TenantJdbc#minSize()`, `MPC` |
75
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.max-size` | `Optional<Integer>` | ≥ 1 | MPC: `5` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DB_POOL_MAX`) | Não | Pool máximo por tenant (`Math.max(1, v)`) | `TenantConnectionResolverImpl` | Também em `quarkus.datasource.jdbc.max-size`; conexões totais ≈ `max-size × max-active-datasources` (Inferência) | runtime | Decl.: `SubdomainTenancyBridgeConfig.TenantJdbc#maxSize()`, `MPC` |
76
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.idle-timeout` | `Duration` | ISO-8601, ex. `PT30M` | `PT30M` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DB_IDLE_TIMEOUT`) | Não | Idle timeout das conexões do pool do tenant | `SimpleDriverDataSource` criado pelo resolver | — | runtime | Decl.: `@ConfigProperty` em `TenantConnectionResolverImpl`, `SubdomainTenancyBridgeConfig.TenantJdbc#idleTimeout()` (`String`), `MPC` |
77
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.acquisition-timeout` | `Duration` | ISO-8601 | `PT30S` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DB_ACQUISITION_TIMEOUT`) | Não | Timeout para obter conexão do pool | idem | — | runtime | idem (`#acquisitionTimeout()`) |
78
+ | `seedgrid.subdomain-tenancy.tenant.datasource.max-active-datasources` | `int` | ≥ 1 (menor vira 1) | `200` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_MAX_ACTIVE_DATASOURCES`) | Não | Teto de pools de tenant em cache por instância. No teto, evicta o pool ocioso menos usado (LRU, só sem conexões ativas); sem candidato lança `TenantProvisioningException("Maximum active tenant datasources reached …")` | `TenantConnectionResolverImpl#getOrCreateTenantDataSource` | Métrica `seedgrid.subdomain-tenancy.tenant.datasource.evictions{reason=lru}` | runtime | Decl.: `@ConfigProperty` em `TenantConnectionResolverImpl`, `SubdomainTenancyBridgeConfig.TenantDatasource#maxActiveDatasources()`, `MPC` |
79
+ | `seedgrid.subdomain-tenancy.tenant.datasource.cache.idle-eviction` | `Duration` | ISO-8601 > 0 | `PT30M` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DS_CACHE_IDLE_EVICTION`) | Não | Pool sem acesso há esse tempo e sem conexões ativas é fechado (TTL). Valor ≤ 0 vira 30 min; mínimo efetivo 1 s | `TenantConnectionResolverImpl#evictExpiredIdleDataSourcesLocked` | `cleanup-interval`; métrica `…evictions{reason=ttl}` | runtime | Decl.: `@ConfigProperty` em `TenantConnectionResolverImpl`, `SubdomainTenancyBridgeConfig.Cache#idleEviction()`, `MPC` |
80
+ | `seedgrid.subdomain-tenancy.tenant.datasource.cache.cleanup-interval` | `Duration` | ISO-8601 > 0 | `PT1M` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DS_CACHE_CLEANUP_INTERVAL`) | Não | Período da thread daemon `tenant-datasource-cache-evictor`. ≤ 0 vira 1 min; mínimo efetivo 1 s | idem (construtor) | `idle-eviction` | runtime | Decl.: idem (`Cache#cleanupInterval()`) |
81
+ | `seedgrid.subdomain-tenancy.tenant.entity-packages` | `Optional<String>` | pacotes Java (CSV) | MPC: vazio (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_ENTITY_PACKAGES`) | Não | Prefixada em `quarkus.hibernate-orm.packages=${…tenant.entity-packages},br.com.seedgrid.security.entities,br.com.seedgrid.backup.entities,br.com.seedgrid.audit.entities` | PU default (multitenant) | O exemplo redefine `quarkus.hibernate-orm.packages` reaproveitando esta chave | build (via expansão — Inferência) | Decl.: `SubdomainTenancyBridgeConfig.Tenant#entityPackages()`, `MPC` |
82
+ | `seedgrid.subdomain-tenancy.tenant.migrations.location.additional` | `Optional<String>` (CSV) | locations Flyway | MPC: vazio | Não | Anexadas à base `classpath:db/migration/tenant` no history `flyway_schema_history_tenant` | `Migrations#migrateTenantSchema` (provisionamento e migração por tenant) | Rodam **depois** do schema security no banco do tenant | runtime | Decl.: `SubdomainTenancyBridgeConfig.Migrations#locationAdditional()`, `SubdomainTenancyConfig#tenantMigrationsLocationAdditional`, `MPC`. Consumo: `RT/flyway/Migrations` |
83
+
84
+ ### 2.4 Circuit breaker das conexões de tenant
85
+
86
+ Um `io.smallrye.faulttolerance.api.Guard` por tenant (`tenant-datasource-<tenant>`), `failOn(SQLException)`. Circuito aberto → `SQLTransientConnectionException` e métrica `seedgrid.subdomain-tenancy.tenant.datasource.connection.circuit.open`.
87
+
88
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
89
+ |---|---|---|---|---|---|---|---|---|---|
90
+ | `seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.failure-ratio` | `double` | (0, 1]; ≤ 0 vira `0.5`, ≥ 1 vira `1.0` | `0.5` (env `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DB_CB_FAILURE_RATIO`) | Não | Razão de falhas que abre o circuito | `TenantConnectionResolverImpl#buildTenantConnectionCircuitBreaker` | `request-volume-threshold` | runtime | Decl.: `@ConfigProperty` em `TenantConnectionResolverImpl`, `SubdomainTenancyBridgeConfig.CircuitBreaker#failureRatio()`, `MPC` |
91
+ | `seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.request-volume-threshold` | `int` | ≥ 2 (menor vira 2) | `6` (env `…_TENANT_DB_CB_REQUEST_VOLUME_THRESHOLD`) | Não | Janela mínima de chamadas para avaliar a razão | idem | — | runtime | idem (`#requestVolumeThreshold()`) |
92
+ | `seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.delay` | `Duration` | ISO-8601 > 0 (≤ 0 vira 30 s) | `PT30S` (env `…_TENANT_DB_CB_DELAY`) | Não | Tempo aberto antes de half-open | idem | — | runtime | idem (`#delay()`, `String` no mapping) |
93
+ | `seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.success-threshold` | `int` | ≥ 1 | `2` (env `…_TENANT_DB_CB_SUCCESS_THRESHOLD`) | Não | Sucessos em half-open para fechar | idem | — | runtime | idem (`#successThreshold()`) |
94
+
95
+ ### 2.5 Orquestração de migrations por tenant
96
+
97
+ Estado em `tenant_migration_state` (master), lock com fencing token e heartbeat. Ordem no banco do tenant: security → tenant (+ additional) → audit (se `seedgrid.audit.persistence.strategy=jpa`) → backup → apikeys.
98
+
99
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
100
+ |---|---|---|---|---|---|---|---|---|---|
101
+ | `seedgrid.subdomain-tenancy.migration.enabled` | `boolean` | `true`/`false` | `true` (env `SEEDGRID_SUBDOMAIN_TENANCY_MIGRATION_ENABLED`) | Não | `false`: o gate de login não age e o coordinator devolve "Migration bypassed" (READY) | `TenantMigrationCoordinator`, `TenantMigrationGateFilter` | Não afeta as migrations do master no startup | runtime | Decl.: `@ConfigProperty` em ambos os construtores, `SubdomainTenancyBridgeConfig.Migration#enabled()`, `MPC` |
102
+ | `seedgrid.subdomain-tenancy.migration.trigger-on-login` | `boolean` | `true`/`false` | `true` (env `…_MIGRATION_TRIGGER_ON_LOGIN`) | Não | Em request (não-`OPTIONS`) cujo path começa com um `login-paths`, para tenant ≠ master, garante a migração; se não estiver READY responde `503` + `Retry-After: 15` (`tenant_migration_in_progress`/`tenant_migration_failed`) | `TenantMigrationGateFilter#filter` | `enabled`, `login-paths` | runtime | Decl.: `@ConfigProperty` em `RT/filters/TenantMigrationGateFilter`, `Migration#triggerOnLogin()`, `MPC` |
103
+ | `seedgrid.subdomain-tenancy.migration.login-paths` | `String` (CSV) | prefixos de path | `/auth/login` (env `…_MIGRATION_LOGIN_PATHS`) | Não | Separado por vírgula, `trim`, match por `startsWith` | `TenantMigrationGateFilter` | `trigger-on-login` | runtime | idem (`Migration#loginPaths()`) |
104
+ | `seedgrid.subdomain-tenancy.migration.startup-migrate-all-tenants` | `boolean` | `true`/`false` | `false` (env `…_MIGRATION_STARTUP_ALL_TENANTS`) | Não | `true`: após migrar o master, enfileira (assíncrono) a migração de todos os tenants ativos, em páginas de 200 | `MigrationService#onStart` | `max-concurrency` | runtime | Decl.: `@ConfigProperty` em `RT/flyway/MigrationService`, `Migration#startupMigrateAllTenants()`, `MPC` |
105
+ | `seedgrid.subdomain-tenancy.migration.target-version` | `String` | rótulo livre | `v1` (env `…_MIGRATION_TARGET_VERSION`) | Não | Tenant só é "pronto" se `status=READY` e `targetVersion == currentVersion == target-version`; mudar o valor força nova migração no próximo gatilho | `TenantMigrationCoordinator#isAlreadyReady` | — | runtime | Decl.: `@ConfigProperty` em `TenantMigrationCoordinator`, `Migration#targetVersion()`, `MPC` |
106
+ | `seedgrid.subdomain-tenancy.migration.max-concurrency` | `int` | ≥ 1 | `3` (env `…_MIGRATION_MAX_CONCURRENCY`) | Não | Tamanho do pool `tenant-migration-login` e do semáforo; sem vaga devolve "Migration capacity reached" | `TenantMigrationCoordinator` | — | runtime | idem (`Migration#maxConcurrency()`) |
107
+ | `seedgrid.subdomain-tenancy.migration.lock-lease` | `Duration` | ISO-8601 | `PT10M` (env `…_MIGRATION_LOCK_LEASE`) | Não | Validade do lock; heartbeat a cada `lease/3` (mínimo 5 s) | `TenantMigrationCoordinator` | `instance-id` | runtime | Decl.: `@ConfigProperty` (`Duration`), `Migration#lockLease()` (`String`), `MPC` |
108
+ | `seedgrid.subdomain-tenancy.migration.instance-id` | `Optional<String>` | texto | `—` (MPC: `${…_MIGRATION_INSTANCE_ID:}` → vazio = ausente) | Não | Dono do lock; vazio → `instance-<UUID aleatório>` a cada boot | `TenantMigrationCoordinator` | — | runtime | Decl.: `@ConfigProperty` em `TenantMigrationCoordinator`, `Migration#instanceId()`, `MPC` |
109
+
110
+ ### 2.6 Bootstrap do admin global (banco master)
111
+
112
+ Executado por `MigrationService#masterMigrate` → `AdminUserBootstrapService#seedAdminUserIfNeeded` **somente** se a tabela `users` do master existir e estiver vazia.
113
+
114
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
115
+ |---|---|---|---|---|---|---|---|---|---|
116
+ | `seedgrid.subdomain-tenancy.admin-user.name` | `Optional<String>` | texto | MPC: vazio (env `SEEDGRID_SUBDOMAIN_TENANCY_ADMIN_NAME`) | Condicional: obrigatória quando `users` do master está vazia — senão `IllegalStateException("Missing required property: …")` derruba o startup | Nome do admin global | `AdminUserBootstrapService#seedAdminUserIfNeeded` | `email` | runtime | Decl.: `RT/configs/SubdomainTenancyAdminUserConfig#name()`, `SubdomainTenancyBridgeConfig.AdminUser#name()`, `MPC` |
117
+ | `seedgrid.subdomain-tenancy.admin-user.email` | `Optional<String>` | e-mail | MPC: vazio (env `SEEDGRID_SUBDOMAIN_TENANCY_ADMIN_EMAIL`) | Condicional (idem) | Normalizado (`trim().toLowerCase()`) | idem | — | runtime | idem (`#email()`) |
118
+ | 🔒 `seedgrid.subdomain-tenancy.admin-user.initial-password` | `Optional<String>` | senha que passe em `PasswordService#validate` (security) | MPC: vazio (env `SEEDGRID_SUBDOMAIN_TENANCY_ADMIN_INITIAL_PASSWORD`) | Não | Vazia → senha gerada por `PasswordGenerator` e enviada por e-mail de boas-vindas (se o e-mail falhar, o admin fica sem a senha) | `AdminUserBootstrapService#resolvePassword` | Política de senha do `seedgrid-security` | runtime | idem (`#initialPassword()`) |
119
+
120
+ ### 2.7 E-mail (mailer nomeado `subdomaintenancy`)
121
+
122
+ As chaves têm efeito via ponte do `MPC` para o mailer nomeado `quarkus.mailer."subdomaintenancy".*`, usado por `RT/spi/impl/MailerNotificationService` (`@MailerName("subdomaintenancy")`, `@DefaultBean`) para enviar o OTP. Nenhum código lê as chaves `seedgrid.subdomain-tenancy.mailer.*` diretamente.
123
+
124
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
125
+ |---|---|---|---|---|---|---|---|---|---|
126
+ | `seedgrid.subdomain-tenancy.mailer.from` | `Optional<String>` | e-mail | MPC: `noreply@example.com` (env `SEEDGRID_SUBDOMAIN_TENANCY_MAILER_FROM`) | Condicional (para envio real) | → `quarkus.mailer."subdomaintenancy".from` | Envio do OTP de validação | — | runtime | Decl.: `SubdomainTenancyMailerConfig#from()`, `SubdomainTenancyBridgeConfig.Mailer#from()`, `MPC` |
127
+ | `seedgrid.subdomain-tenancy.mailer.host` | `Optional<String>` | host SMTP | MPC: `smtp.gmail.com` (env `…_MAILER_HOST`) | Condicional | → `…".host` | idem | — | runtime | idem (`#host()`) |
128
+ | `seedgrid.subdomain-tenancy.mailer.port` | `Optional<Integer>` | porta | MPC: `587` (env `…_MAILER_PORT`) | Não | → `…".port` | idem | — | runtime | idem (`#port()`) |
129
+ | `seedgrid.subdomain-tenancy.mailer.start-tls` | `Optional<String>` | `DISABLED`/`OPTIONAL`/`REQUIRED` (valores do Quarkus Mailer) | MPC: `REQUIRED` (env `…_MAILER_START_TLS`) | Não | → `…".start-tls` | idem | — | runtime | idem (`#startTls()`) |
130
+ | `seedgrid.subdomain-tenancy.mailer.username` | `Optional<String>` | usuário SMTP | MPC: vazio (env `…_MAILER_USERNAME`) | Condicional (SMTP autenticado) | → `…".username` | idem | — | runtime | idem (`#username()`) |
131
+ | 🔒 `seedgrid.subdomain-tenancy.mailer.password` | `Optional<String>` | segredo | MPC: vazio (env `…_MAILER_PASSWORD`) | Condicional | → `…".password` | idem | — | runtime | idem (`#password()`) |
132
+ | `seedgrid.subdomain-tenancy.mailer.auth-methods` | `Optional<String>` | métodos SMTP AUTH separados por espaço | MPC: `PLAIN LOGIN` (env `…_MAILER_AUTH_METHODS`) | Não | → `…".auth-methods`; evita XOAUTH2 automático do Vert.x (Gmail) | idem | — | runtime | idem (`#authMethods()`) |
133
+
134
+ ### 2.8 Signup, OTP e limpeza
135
+
136
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
137
+ |---|---|---|---|---|---|---|---|---|---|
138
+ | `seedgrid.subdomain-tenancy.otp-expiry-minutes` | `int` | minutos > 0 | `10` | Não | Validade do código OTP de 6 dígitos (`TenantValidationToken.expiresAt`) e valor passado no `TenantValidationNotification.expiryMinutes` | `TenantService#sendValidationEmail` | Não declarada no `SubdomainTenancyBridgeConfig` | runtime | Decl./consumo: `@ConfigProperty` em `RT/services/TenantService` (construtor) |
139
+ | `seedgrid.subdomain-tenancy.cleanup.not-validated-ttl` | `String` | `48H`, `30M`, `7D`, `PT…` | `48H` (env `SEEDGRID_SUBDOMAIN_TENANCY_CLEANUP_NOT_VALIDATED_TTL`) | Não | Tenants não validados criados antes de `now - ttl` têm o registro removido do master. Parser próprio; erro → 48 h com warning | `TenantCleanupScheduler` (construtor) | O formato combinado `2D12H` citado no Javadoc vira `PT2D12H`, inválido para `Duration.parse` → cai em 48 h (**Inferência** pela gramática ISO-8601) | runtime | Decl.: `SubdomainTenancyBridgeConfig.Cleanup#notValidatedTtl()`, `MPC`. Consumo: `RT/schedulers/TenantCleanupScheduler#parseDuration` |
140
+ | `seedgrid.subdomain-tenancy.cleanup.not-validated-cron` | `String` | cron Quartz do Quarkus Scheduler | `0 0 * * * ?` (env `…_CLEANUP_NOT_VALIDATED_CRON`) | Não | Agenda `cleanupExpiredTenants` (só roda se `flyway_schema_history_subdomain_tenancy` existir) | `@Scheduled(cron = "{seedgrid.subdomain-tenancy.cleanup.not-validated-cron}")` | `not-validated-ttl` | runtime | Decl.: `SubdomainTenancyBridgeConfig.Cleanup#notValidatedCron()`, `MPC`. Consumo: `TenantCleanupScheduler#cleanupExpiredTenants` |
141
+
142
+ > O cleanup chama `TenantProvisioningService#deleteTenantConfigById`, que só remove a linha de `tenants`; **não** há `DROP DATABASE` nesse caminho (o Javadoc do scheduler diz "including their databases" — **Confirmado** que o código não faz isso).
143
+
144
+ ## 3. Propriedades de frameworks e de outras extensions
145
+
146
+ ### 3.1 Definidas pela extension no `MPC` (o host pode sobrescrever)
147
+
148
+ | Propriedade | Valor publicado | Observação |
149
+ |---|---|---|
150
+ | `quarkus.datasource.master.db-kind` | `postgresql` | Também `PROC` (runtime default) |
151
+ | `quarkus.datasource.master.jdbc.url` / `.username` / `.password` / `.jdbc.min-size` / `.jdbc.max-size` | `${seedgrid.subdomain-tenancy.master.datasource.…}` | Ponte do master; `PROC` registra url/username/password com fallback |
152
+ | `quarkus.datasource.db-kind` | `postgresql` | Datasource default (tenants); obrigatório com datasources nomeados (Quarkus 3.18+) |
153
+ | `quarkus.datasource.jdbc.min-size` / `.max-size` | `${seedgrid.subdomain-tenancy.tenant.datasource.jdbc.min-size/max-size}` | — |
154
+ | `quarkus.hibernate-orm.database.generation` | `none` | Também `PROC` |
155
+ | `quarkus.hibernate-orm.multitenant` | `DATABASE` | Também `PROC` |
156
+ | `quarkus.hibernate-orm.physical-naming-strategy` | `org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy` | idem para `.master.` |
157
+ | `quarkus.hibernate-orm.dialect` | `org.hibernate.dialect.PostgreSQLDialect` | — |
158
+ | `quarkus.hibernate-orm.log.sql` | `false` | — |
159
+ | `quarkus.hibernate-orm.packages` | `${…tenant.entity-packages},br.com.seedgrid.security.entities,br.com.seedgrid.backup.entities,br.com.seedgrid.audit.entities` | build time |
160
+ | `quarkus.hibernate-orm.master.datasource` / `.database.generation` / `.multitenant` | `master` / `none` / `NONE` | Também `PROC` |
161
+ | `quarkus.hibernate-orm.master.packages` | `${…master.entity-packages},br.com.seedgrid.subdomaintenancy.entities,br.com.seedgrid.billing.entities,br.com.seedgrid.security.entities` | build time |
162
+ | `quarkus.hibernate-orm.validate-in-dev-mode` / `.master.validate-in-dev-mode` | `false` | — |
163
+ | `quarkus.flyway.enabled` / `quarkus.flyway.migrate-at-start` | `false` / `false` | Flyway default desligado |
164
+ | `quarkus.flyway.master.migrate-at-start` / `.baseline-on-migrate` / `.out-of-order` / `.validate-on-migrate` | `true` / `true` / `false` / `true` | As migrations reais rodam por Flyway programático (`Migrations`) |
165
+ | `quarkus.mailer."subdomaintenancy".from/host/port/start-tls/username/password/auth-methods` | `${seedgrid.subdomain-tenancy.mailer.…}` | Ponte do mailer |
166
+ | `quarkus.swagger-ui.urls.default` | `/public/tenant-openapi` | Swagger aponta para o spec filtrado |
167
+ | `quarkus.swagger-ui.always-include` / `quarkus.swagger-ui.path` | `false` / `/swagger-ui` | — |
168
+ | `quarkus.http.auth.permission.tenant-openapi.paths` / `.policy` / `.methods` | `/public/tenant-openapi` / `permit` / `GET` | Endpoint do spec liberado |
169
+ | `quarkus.otel.enabled` / `quarkus.otel.traces.exporter` | `${SEEDGRID_SUBDOMAIN_TENANCY_OTEL_ENABLED:true}` / `${SEEDGRID_SUBDOMAIN_TENANCY_OTEL_TRACES_EXPORTER:none}` | Spans com `tenant_id` |
170
+ | `quarkus.micrometer.enabled` / `.export.prometheus.enabled` / `.binder.http-server.enabled` | `${SEEDGRID_SUBDOMAIN_TENANCY_METRICS_ENABLED:true}` / `${…_PROMETHEUS_ENABLED:true}` / `${…_HTTP_METRICS_ENABLED:true}` | Métricas de pool/evicção/circuito/migração |
171
+ | `seedgrid.billing.persistence-unit` | `master` | Billing mora no master |
172
+ | `seedgrid.ai-pricing.persistence-unit` / `seedgrid.exchange.persistence-unit` | `master` / `master` | Catálogos globais no master |
173
+
174
+ ### 3.2 Lidas pela extension, pertencentes a outras extensions/frameworks
175
+
176
+ | Propriedade | Padrão no consumo | Efeito aqui | Origem |
177
+ |---|---|---|---|
178
+ | `seedgrid.audit.persistence.strategy` | `—` | Só com `jpa` (case-insensitive) roda `db/migration/audit` no master e nos tenants | `RT/flyway/Migrations#migrateAuditSchema` |
179
+ | `seedgrid.ai-pricing.migration.enabled` | `false` | Roda `db/migration/ai-pricing` no master | `RT/flyway/MigrationService` |
180
+ | `seedgrid.exchange.migration.enabled` | `false` | Roda `db/migration/exchange` no master | `RT/flyway/MigrationService` |
181
+ | `quarkus.mongodb.database` | `default_db` | Sufixo dos bancos Mongo por tenant no `MongoTenantResolverImpl` | `RT/mongodb/MongoTenantResolverImpl` |
182
+ | `seedgrid.ratelimit.{tenant-signup\|tenant-validate-email\|tenant-resend-email}.{permits\|window\|enabled}` | anotação: 100/1 min, 10/1 min, 5/1 h; `enabled=true` | Overrides do `@SeedGridRateLimit` nos endpoints públicos (resilience) | `RT/controllers/TenantSignupController`; `java/seedgrid-quarkus-ext-resilience/.../SeedGridRateLimit.java` (Javadoc) |
183
+ | `seedgrid.security.frontend.base-url` | (do security) | Base dos links de e-mail; `TenantSecurityLinks` insere `<tenant>.` no host em contexto de tenant | `RT/security/TenantSecurityLinks` (via `SecurityFrontendConfig`) |
184
+ | `seedgrid.security.default-company.*` | (do security) | Empresa vinculada ao admin global no bootstrap | `RT/services/AdminUserBootstrapService` (via `DefaultCompanyConfig`) |
185
+ | `seedgrid.privacy.encryption.enabled`, `seedgrid.privacy.crypto.key` 🔒, `seedgrid.privacy.search.key` 🔒 | (do privacy) | Criptografia at-rest dos campos PII do `Tenant` (master) | ver [[SeedGrid/Extensions/privacy/Configuracao\|Configuração do privacy]] |
186
+
187
+ ## 4. Propriedades usadas só em testes / exemplos
188
+
189
+ `java/seedgrid-quarkus-ext-subdomain-tenancy/runtime/src/test/resources/application.properties`, `…/testsupport/SubdomainTenancyPostgresTestResource.java` e `TenantEncryptedFieldsTest.EncryptionOnProfile`:
190
+
191
+ | Propriedade | Valor/fonte no teste | Observação |
192
+ |---|---|---|
193
+ | `seedgrid.subdomain-tenancy.domain-suffix` | `test.com` | — |
194
+ | `seedgrid.subdomain-tenancy.default-tenant` | `master` | — |
195
+ | `seedgrid.subdomain-tenancy.admin-user.name` / `.email` / `.initial-password` 🔒 | valores de teste | — |
196
+ | `seedgrid.subdomain-tenancy.master.datasource.jdbc.url/username/password` 🔒 | Testcontainers | via `SubdomainTenancyPostgresTestResource` |
197
+ | `seedgrid.subdomain-tenancy.tenant.datasource.jdbc.url-pattern/username/password` 🔒 | Testcontainers | idem; `TenantRegisterResourceIntegrationTest` lê também `product-prefix` |
198
+ | `quarkus.datasource.master.*`, `quarkus.hibernate-orm.*`, `quarkus.hibernate-orm.master.*` | ver arquivo | Pacotes de entidades reduzidos |
199
+ | `quarkus.flyway.enabled=true`, `quarkus.flyway.master.locations` | security, billing, subdomain-tenancy | — |
200
+ | `quarkus.arc.exclude-types` | `…flyway.MigrationService,…security.services.FirstAdminBootstrapService` | Desliga o startup de migrations e o bootstrap do security |
201
+ | `quarkus.mailer.mock`, `quarkus.mailer."subdomaintenancy".mock` | `true` | — |
202
+ | `mp.jwt.verify.publickey.location` | `classpath:keys/public.pem` | — |
203
+ | `quarkus.http.test-port`, `quarkus.http.test-ssl-port` | `0` | — |
204
+ | `quarkus.log.level`, `quarkus.log.category."br.com.seedgrid".level` | `INFO` / `DEBUG` | — |
205
+ | `seedgrid.ratelimit.tenant-signup/tenant-validate-email/tenant-resend-email.enabled` | `false` | — |
206
+ | `seedgrid.security.encryption.key` 🔒, `seedgrid.security.default-company.cnpj/corporate-name/trade-name` | valores de teste | Exigidos pelo security |
207
+ | `seedgrid.privacy.encryption.enabled`, `seedgrid.privacy.crypto.key` 🔒, `seedgrid.privacy.search.key` 🔒 | perfil `EncryptionOnProfile` | — |
208
+
209
+ O app de exemplo (`java/examples/seedgrid-subdomain-tenancy-example`) usa, além das acima, `product-prefix=${PRODUCT_PREFIX:kb}`, `tenant.datasource.jdbc.url/username/password` via `SEEDGRID_SUBDOMAIN_TENANCY_TENANT_DB_*` (env vars **criadas pelo exemplo**, não pela lib) e `seedgrid.security.bootstrap.enabled=false`.
210
+
211
+ ## 5. Aliases, obsoletas e renomeações
212
+
213
+ Não há aliases ativos. A única forma alternativa é `…tenant.datasource.jdbc.url-pattern`, que vence `…jdbc.url` (Javadoc de `TenantJdbc#urlPattern()`: compatibilidade/legado; preferir `…jdbc.url`).
214
+
215
+
216
+ ## 6. Configuração mínima (`application.properties`)
217
+
218
+ ```properties
219
+ # Resolução por subdomínio: <tenant>.crm.example.com
220
+ seedgrid.subdomain-tenancy.domain-suffix=crm.example.com
221
+ seedgrid.subdomain-tenancy.product-prefix=crm
222
+
223
+ # Banco MASTER (catálogo de tenants, security, billing...)
224
+ seedgrid.subdomain-tenancy.master.datasource.jdbc.url=jdbc:postgresql://db.example.com:5432/crm_master
225
+ seedgrid.subdomain-tenancy.master.datasource.username=<usuario-master>
226
+ seedgrid.subdomain-tenancy.master.datasource.password=<SEGREDO:master-db-password>
227
+
228
+ # Bancos dos tenants (o nome do banco é acrescentado: /crm_<tenant>)
229
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.url=jdbc:postgresql://db.example.com:5432
230
+ seedgrid.subdomain-tenancy.tenant.datasource.username=<usuario-com-CREATE-DATABASE>
231
+ seedgrid.subdomain-tenancy.tenant.datasource.password=<SEGREDO:tenant-db-password>
232
+
233
+ # Admin global (obrigatório no 1º boot, quando a tabela users do master está vazia)
234
+ seedgrid.subdomain-tenancy.admin-user.name=<nome-admin>
235
+ seedgrid.subdomain-tenancy.admin-user.email=<email-admin>
236
+
237
+ # SMTP do OTP de validação
238
+ seedgrid.subdomain-tenancy.mailer.from=<remetente>
239
+ seedgrid.subdomain-tenancy.mailer.host=<smtp-host>
240
+ seedgrid.subdomain-tenancy.mailer.username=<smtp-user>
241
+ seedgrid.subdomain-tenancy.mailer.password=<SEGREDO:smtp-password>
242
+ ```
243
+
244
+ Além disso, o `seedgrid-security` exige as suas próprias chaves (JWT, `encryption.key`, `default-company.*`) — ver [[SeedGrid/Extensions/security/Configuracao|Configuração do security]].
245
+
246
+ ## 7. Configuração completa comentada
247
+
248
+ Valores abaixo são **exemplos válidos**, não padrões. Os padrões estão nas tabelas da seção 2.
249
+
250
+ ```properties
251
+ # --- Resolução de tenant ---
252
+ seedgrid.subdomain-tenancy.domain-suffix=crm.example.com
253
+ #seedgrid.subdomain-tenancy.tenant-header=X-Tenant # opcional; ver ressalva na tabela 2.1
254
+ seedgrid.subdomain-tenancy.default-tenant=master # manter "master" (literal fixo em vários pontos)
255
+ seedgrid.subdomain-tenancy.product-prefix=crm
256
+ seedgrid.subdomain-tenancy.openapi.master-only-paths=/admin,/backoffice
257
+
258
+ # --- Master ---
259
+ seedgrid.subdomain-tenancy.master.datasource.jdbc.url=jdbc:postgresql://db:5432/crm_master
260
+ seedgrid.subdomain-tenancy.master.datasource.username=<usuario-master>
261
+ seedgrid.subdomain-tenancy.master.datasource.password=<SEGREDO:master-db-password>
262
+ seedgrid.subdomain-tenancy.master.datasource.jdbc.min-size=1
263
+ seedgrid.subdomain-tenancy.master.datasource.jdbc.max-size=20
264
+ seedgrid.subdomain-tenancy.master.entity-packages=com.acme.crm.master.entities
265
+ seedgrid.subdomain-tenancy.master.migrations.location.additional=classpath:db/migration/master-extra
266
+
267
+ # --- Tenants: conexão ---
268
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.url=jdbc:postgresql://db:5432
269
+ #seedgrid.subdomain-tenancy.tenant.datasource.jdbc.url-pattern=jdbc:postgresql://db:5432/{tenant}?sslmode=require
270
+ seedgrid.subdomain-tenancy.tenant.datasource.username=<usuario-tenants>
271
+ seedgrid.subdomain-tenancy.tenant.datasource.password=<SEGREDO:tenant-db-password>
272
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.driver=org.postgresql.Driver
273
+ seedgrid.subdomain-tenancy.tenant.entity-packages=com.acme.crm.tenant.entities
274
+ seedgrid.subdomain-tenancy.tenant.migrations.location.additional=classpath:db/migration/tenant-extra
275
+
276
+ # --- Tenants: pool por tenant ---
277
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.min-size=0
278
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.max-size=5
279
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.idle-timeout=PT15M
280
+ seedgrid.subdomain-tenancy.tenant.datasource.jdbc.acquisition-timeout=PT10S
281
+
282
+ # --- Tenants: cache de pools ---
283
+ seedgrid.subdomain-tenancy.tenant.datasource.max-active-datasources=100
284
+ seedgrid.subdomain-tenancy.tenant.datasource.cache.idle-eviction=PT20M
285
+ seedgrid.subdomain-tenancy.tenant.datasource.cache.cleanup-interval=PT1M
286
+
287
+ # --- Tenants: circuit breaker ---
288
+ seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.failure-ratio=0.5
289
+ seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.request-volume-threshold=10
290
+ seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.delay=PT20S
291
+ seedgrid.subdomain-tenancy.tenant.datasource.circuit-breaker.success-threshold=2
292
+
293
+ # --- Migrations por tenant ---
294
+ seedgrid.subdomain-tenancy.migration.enabled=true
295
+ seedgrid.subdomain-tenancy.migration.trigger-on-login=true
296
+ seedgrid.subdomain-tenancy.migration.login-paths=/auth/login,/auth/2f
297
+ seedgrid.subdomain-tenancy.migration.startup-migrate-all-tenants=false
298
+ seedgrid.subdomain-tenancy.migration.target-version=v2
299
+ seedgrid.subdomain-tenancy.migration.max-concurrency=3
300
+ seedgrid.subdomain-tenancy.migration.lock-lease=PT10M
301
+ seedgrid.subdomain-tenancy.migration.instance-id=${HOSTNAME}
302
+
303
+ # --- Admin global ---
304
+ seedgrid.subdomain-tenancy.admin-user.name=<nome-admin>
305
+ seedgrid.subdomain-tenancy.admin-user.email=<email-admin>
306
+ #seedgrid.subdomain-tenancy.admin-user.initial-password=<SEGREDO:admin-initial-password> # vazio = gerada
307
+
308
+ # --- E-mail ---
309
+ seedgrid.subdomain-tenancy.mailer.from=<remetente>
310
+ seedgrid.subdomain-tenancy.mailer.host=<smtp-host>
311
+ seedgrid.subdomain-tenancy.mailer.port=587
312
+ seedgrid.subdomain-tenancy.mailer.start-tls=REQUIRED
313
+ seedgrid.subdomain-tenancy.mailer.username=<smtp-user>
314
+ seedgrid.subdomain-tenancy.mailer.password=<SEGREDO:smtp-password>
315
+ seedgrid.subdomain-tenancy.mailer.auth-methods=PLAIN LOGIN
316
+
317
+ # --- Signup / limpeza ---
318
+ seedgrid.subdomain-tenancy.otp-expiry-minutes=15
319
+ seedgrid.subdomain-tenancy.cleanup.not-validated-ttl=72H
320
+ seedgrid.subdomain-tenancy.cleanup.not-validated-cron=0 0 * * * ?
321
+
322
+ # --- Rate limit dos endpoints públicos (seedgrid-resilience) ---
323
+ seedgrid.ratelimit.tenant-signup.permits=50
324
+ seedgrid.ratelimit.tenant-signup.window=PT1M
325
+ ```
326
+
327
+ ## 8. Receitas
328
+
329
+ - **Desenvolvimento local com `*.localhost`**: `domain-suffix=localhost` (o extractor exige que o host termine no sufixo e que o prefixo case `^[a-z0-9-]+$`). Atrás de proxy, garanta `X-Forwarded-Host`.
330
+ - **Escalar muitos tenants por instância**: ajuste `max-active-datasources` × `jdbc.max-size` ao `max_connections` do Postgres; reduza `cache.idle-eviction` para liberar pools ociosos mais cedo.
331
+ - **Liberar nova versão de schema de tenant**: publique as migrations em `db/migration/tenant` (ou em `tenant.migrations.location.additional`) e troque `migration.target-version` (ex.: `v1` → `v2`). Os tenants migram no próximo login (`503` + `Retry-After` enquanto migram) ou manualmente via `POST /internal/migrations/tenants/{tenantId}/trigger?force=true`. Para migrar tudo no boot: `migration.startup-migrate-all-tenants=true`.
332
+ - **Desligar o gate de login** (ex.: migrações feitas por pipeline): `migration.trigger-on-login=false` ou `migration.enabled=false`.
333
+ - **Várias réplicas**: defina `migration.instance-id` estável por pod para facilitar diagnóstico do lock (sem ela, cada boot gera `instance-<UUID>`).
334
+ - **Esconder APIs administrativas do Swagger dos tenants**: acrescente prefixos em `openapi.master-only-paths` ou marque recursos com `@MasterOnly`.
335
+ - **Afrouxar/apertar rate limit do signup**: `seedgrid.ratelimit.tenant-signup.permits`/`.window`/`.enabled` (ver [[SeedGrid/Extensions/resilience/Configuracao|Configuração do resilience]]).
336
+
337
+ ## 9. Dúvidas e lacunas
338
+
339
+ 1. **Regex de subdomínio divergente** (Confirmado): signup aceita `^[a-z0-9_]{5,50}$` (`TenantSignupRequest`) e `TenantSecurityLinks` exige `[a-z0-9_]{5,50}`, mas `TenantHostExtractor` só aceita `^[a-z0-9-]+$` (o teste `shouldReturnNullForInvalidTenantFormat` confirma que `_` é rejeitado). Um tenant com `_` no nome não é resolvido pelo host e cai em `master`.
340
+ 2. `tenant-header` e `otp-expiry-minutes` não estão no `SubdomainTenancyBridgeConfig`, cujo Javadoc diz existir para evitar avisos de chave desconhecida. Se o Quarkus emite aviso para essas chaves **não foi confirmado**.
341
+ 3. `default-tenant` diferente de `master` não é suportado de forma consistente (literais `"master"` espalhados) — Inferência.
342
+ 4. Fallback de URL do master no `MigrationService` (`jdbc://postgress:localhost:5432/xxx_master`) é inválido; na prática o `MPC` sempre preenche a chave.
343
+ 5. `cleanup.not-validated-ttl` em formato `2D12H` (citado no Javadoc) cai no padrão de 48 h — Inferência pela gramática do `java.time.Duration`.
344
+ 6. `TenantCleanupScheduler` não apaga o banco do tenant, apesar do Javadoc.
345
+ 7. `quarkus.hibernate-orm.*packages` ser build-time (fase das chaves `entity-packages`) é Inferência baseada no Quarkus 3.30, não verificada nesta extension.
@@ -0,0 +1,117 @@
1
+ ---
2
+ tags: [seedgrid, extension, subdomain-tenancy, enum]
3
+ fonte: java/seedgrid-quarkus-ext-subdomain-tenancy
4
+ branch: main
5
+ commit: fe62530a29
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # subdomain-tenancy — Enums (Quarkus)
10
+
11
+ Visão geral: [[SeedGrid/Extensions/subdomain-tenancy/Visao-geral|Visão geral do subdomain-tenancy]] · Config: [[SeedGrid/Extensions/subdomain-tenancy/Configuracao|Configuração]] · [[SeedGrid/Extensions/subdomain-tenancy/Rust|Porte Rust]]
12
+
13
+ Nenhuma propriedade de configuração desta extension é tipada por enum (todas são `String`, `boolean`, números, `Duration`, `List`), portanto a `Configuracao.md` não tem links para esta nota.
14
+
15
+ ## Índice
16
+
17
+ | Enum | Pacote/arquivo | Usado em | Público? |
18
+ |---|---|---|---|
19
+ | [[#TenantMigrationStatus]] | `migration/TenantMigrationStatus.java` | coluna `tenant_migration_state.status`; JSON de `/internal/migrations`, `/internal/health`; resposta 503 do gate de login | Sim |
20
+ | [[#TenantMigrationDecision]] | `migration/TenantMigrationDecision.java` | retorno de `TenantMigrationCoordinator`; JSON de `POST /internal/migrations/tenants/{id}/trigger` | Sim |
21
+ | [[#TenantHealthStatus]] | `health/TenantHealthStatus.java` | JSON de `GET /internal/health/tenants/{id}` | Sim |
22
+ | [[#TenantHealthCode]] | `health/TenantHealthCode.java` | idem | Sim |
23
+ | [[#SignupOutcome]] | `services/TenantService.java` (aninhado) | JSON de `POST /public/tenants` | Sim |
24
+
25
+ Caminhos relativos a `java/seedgrid-quarkus-ext-subdomain-tenancy/runtime/src/main/java/br/com/seedgrid/subdomaintenancy/`.
26
+
27
+ ## TenantMigrationStatus
28
+
29
+ `br.com.seedgrid.subdomaintenancy.migration.TenantMigrationStatus`. Estado de migração de um tenant (**Confirmado**).
30
+
31
+ | Valor | Significado | Efeito / onde é tratado | Observações |
32
+ |---|---|---|---|
33
+ | `PENDING` | Estado inicial; ainda não migrado para a `target-version` | Gravado por `TenantMigrationStateStore#ensureStateExists`/`getOrCreate`; `TenantHealthService` devolve `MIGRATION_PENDING`; é o valor devolvido por `parseStatus` quando a coluna é nula, vazia ou inválida | `markPending(...)` existe no store, mas nenhum código o chama |
34
+ | `READY` | Tenant migrado | `TenantMigrationCoordinator#isAlreadyReady` exige `READY` **e** `target_version == current_version == migration.target-version`; gravado por `markReady` e `markReadyWithoutLock` (pós-provisionamento) | O master é representado em memória com `READY` (`buildMasterState`), sem linha na tabela |
35
+ | `MIGRATING` | Migração em andamento com lock | Gravado por `tryAcquireLock`; se outra instância tem lock ativo, o gate de login devolve 503 `tenant_migration_in_progress`; `TenantHealthService` → `MIGRATION_RUNNING` | — |
36
+ | `FAILED` | Última tentativa falhou | Gravado por `markFailed` (com `last_error`); gate devolve 503 `tenant_migration_failed`; health → `MIGRATION_FAILED` | Nova tentativa é permitida (login ou `trigger`) |
37
+
38
+ - **Persistência:** coluna `tenant_migration_state.status VARCHAR(20) NOT NULL DEFAULT 'PENDING'` (migration `V104`), gravada como `name()` por SQL direto (`TenantMigrationStateStore`, sem JPA). **Não há CHECK constraint**; a leitura é tolerante: `valueOf(status.trim().toUpperCase())`, qualquer valor desconhecido vira `PENDING`.
39
+ - **JSON:** `name()` em `status` (migrações, gate 503 — `UNKNOWN` quando não há estado) e `migrationStatus` (health, `null` se não há linha).
40
+ - **Transições** (confirmadas nas chamadas do coordinator/store):
41
+
42
+ ```mermaid
43
+ stateDiagram-v2
44
+ [*] --> PENDING: ensureStateExists / getOrCreate
45
+ PENDING --> MIGRATING: tryAcquireLock
46
+ FAILED --> MIGRATING: tryAcquireLock
47
+ READY --> MIGRATING: tryAcquireLock (force ou target-version mudou)
48
+ MIGRATING --> READY: markReady (lock e token válidos)
49
+ MIGRATING --> FAILED: markFailed
50
+ PENDING --> READY: markReadyWithoutLock (provisionamento)
51
+ ```
52
+
53
+ Que `tryAcquireLock` aceita partir de `READY`/`FAILED`/lock expirado é **Inferência** do uso (`force=true`, mudança de `target-version`, tentativa após falha); as condições SQL exatas não foram detalhadas aqui.
54
+ - **Usado em:** [[SeedGrid/Extensions/subdomain-tenancy/Configuracao|`migration.*`]]; endpoints `GET /internal/migrations/tenants/{id}/status`, `POST …/trigger`, `GET /internal/health/tenants/{id}`.
55
+
56
+ ## TenantMigrationDecision
57
+
58
+ `br.com.seedgrid.subdomaintenancy.migration.TenantMigrationDecision` — resultado de uma tentativa/consulta de migração (**Confirmado**). Criado pelas fábricas `TenantMigrationOutcome.ready/inProgress/failed`.
59
+
60
+ | Valor | Significado | Efeito / onde é tratado | Observações |
61
+ |---|---|---|---|
62
+ | `READY` | Tenant pronto (já estava, migrou agora, migração desligada ou é o master) | `TenantMigrationGateFilter` deixa o login passar; `TenantMigrationController` responde 200 | `migratedNow` indica se migrou nesta chamada |
63
+ | `IN_PROGRESS` | Migração enfileirada/rodando (capacidade esgotada, lock de outra instância, enfileirada em background) | Gate bloqueia com 503 + `Retry-After: 15`; controller responde 503 | — |
64
+ | `FAILED` | A migração falhou nesta tentativa | Marca o span OTel com erro; gate bloqueia com 503 (código `tenant_migration_failed` quando o status gravado é `FAILED`); controller responde 503 | — |
65
+
66
+ - **Serialização:** `name()` no campo `decision` do corpo de `POST /internal/migrations/tenants/{id}/trigger` e atributo de span `tenant_migration.decision`. Não é persistido.
67
+
68
+ ## TenantHealthStatus
69
+
70
+ `br.com.seedgrid.subdomaintenancy.health.TenantHealthStatus` (**Confirmado**).
71
+
72
+ | Valor | Significado | Efeito / onde é tratado | Observações |
73
+ |---|---|---|---|
74
+ | `UP` | Saudável | `TenantHealthReport#isUp` → HTTP 200 | Só com `code=OK` |
75
+ | `DOWN` | Indisponível ou inexistente | Usado para `INVALID_TENANT`, `TENANT_NOT_FOUND`, `DATABASE_UNREACHABLE` | HTTP 400/404/503 conforme o code |
76
+ | `OUT_OF_SERVICE` | Existe, mas não atende | Usado para `TENANT_INACTIVE`, `MIGRATION_FAILED`, `MIGRATION_PENDING`, `MIGRATION_RUNNING` | HTTP 503 |
77
+
78
+ - **JSON:** `name()` em `status`. Não persistido. O HTTP é decidido por `TenantHealthController#resolveHttpStatus` (up → 200; `INVALID_TENANT` → 400; `TENANT_NOT_FOUND` → 404; demais → 503).
79
+
80
+ ## TenantHealthCode
81
+
82
+ `br.com.seedgrid.subdomaintenancy.health.TenantHealthCode` (**Confirmado**). Ordem de avaliação em `TenantHealthService#checkTenant`: id inválido → tenant inexistente → inativo → banco inacessível → migração.
83
+
84
+ | Valor | Significado | Efeito / onde é tratado | Observações |
85
+ |---|---|---|---|
86
+ | `OK` | Tudo certo | `status=UP`, HTTP 200 | Fábrica `TenantHealthReport.up` |
87
+ | `INVALID_TENANT` | Id do tenant vazio/inválido | `status=DOWN`, HTTP 400 | — |
88
+ | `TENANT_NOT_FOUND` | Não existe em `tenants` | `status=DOWN`, HTTP 404 | — |
89
+ | `TENANT_INACTIVE` | Existe, mas `active=false` | `status=OUT_OF_SERVICE`, HTTP 503 | — |
90
+ | `DATABASE_UNREACHABLE` | `SELECT 1` no banco do tenant falhou | `status=DOWN`, HTTP 503 | Usa `TenantConnectionResolverImpl` (circuit breaker pode causar isto) |
91
+ | `MIGRATION_PENDING` | Estado de migração `PENDING` | `status=OUT_OF_SERVICE`, HTTP 503 | Não é emitido quando não há linha de estado (`migrationStatus=null` → `OK`) |
92
+ | `MIGRATION_RUNNING` | Estado `MIGRATING` | `status=OUT_OF_SERVICE`, HTTP 503 | — |
93
+ | `MIGRATION_FAILED` | Estado `FAILED` | `status=OUT_OF_SERVICE`, HTTP 503 | Inclui `migrationError` no JSON |
94
+
95
+ - **JSON:** `name()` em `code`. Não persistido.
96
+ - Estado `READY` gravado com `target_version` diferente do configurado **não** gera código próprio no health (retorna `OK`) — **Inferência** a partir de `checkTenant`, que só compara o status.
97
+
98
+ ## SignupOutcome
99
+
100
+ `br.com.seedgrid.subdomaintenancy.services.TenantService.SignupOutcome` (enum aninhado público; **Confirmado**).
101
+
102
+ | Valor | Significado | Efeito / onde é tratado | Observações |
103
+ |---|---|---|---|
104
+ | `CREATED` | Cadastro pendente novo | `TenantSignupController`: HTTP **201** | — |
105
+ | `UPDATED_PENDING` | Já existia cadastro pendente (e-mail não validado) com o mesmo `subdomain`; foi atualizado e o OTP reenviado | HTTP **200** | — |
106
+
107
+ - **JSON:** `name()` em `status` do corpo de `POST /public/tenants` (com `emailDelivered` e `result`). Não persistido.
108
+
109
+ ## Enums de outras bibliotecas expostos pela extension
110
+
111
+ | Enum | Origem | Onde aparece |
112
+ |---|---|---|
113
+ | `StateEnum` | `br.com.seedgrid.commons.core.enums.StateEnum` (lib commons) | `state` do endereço no body de `POST /public/tenants` (`TenantSignupRequest.AddressDTO`); no bootstrap/provisionamento é gravado por `name()` (`RawCompanies`) e lido com `StateEnum.valueOf(s.toUpperCase())` (`AdminUserBootstrapService`). Valores: ver a nota da lib commons |
114
+
115
+ ## Internos
116
+
117
+ Nenhum enum interno nos módulos `runtime` e `deployment` (todos os enums declarados estão listados acima).