@baruk/core 0.4.2 → 0.6.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.
Files changed (576) hide show
  1. package/.baruk-provenance.json +4 -4
  2. package/CHANGELOG.md +42 -0
  3. package/dist/audit/repository.d.ts +33 -1
  4. package/dist/audit/repository.d.ts.map +1 -1
  5. package/dist/audit/repository.js +41 -7
  6. package/dist/audit/repository.js.map +1 -1
  7. package/dist/auth/service.d.ts +21 -0
  8. package/dist/auth/service.d.ts.map +1 -1
  9. package/dist/auth/service.js +46 -1
  10. package/dist/auth/service.js.map +1 -1
  11. package/dist/billing/ar-repository.d.ts +41 -1
  12. package/dist/billing/ar-repository.d.ts.map +1 -1
  13. package/dist/billing/ar-repository.js +82 -6
  14. package/dist/billing/ar-repository.js.map +1 -1
  15. package/dist/billing/provider-account.d.ts +38 -0
  16. package/dist/billing/provider-account.d.ts.map +1 -1
  17. package/dist/billing/provider-account.js +58 -2
  18. package/dist/billing/provider-account.js.map +1 -1
  19. package/dist/billing/repository.d.ts +44 -0
  20. package/dist/billing/repository.d.ts.map +1 -1
  21. package/dist/billing/repository.js +49 -5
  22. package/dist/billing/repository.js.map +1 -1
  23. package/dist/cjs/audit/repository.js +41 -7
  24. package/dist/cjs/audit/repository.js.map +1 -1
  25. package/dist/cjs/auth/service.js +46 -1
  26. package/dist/cjs/auth/service.js.map +1 -1
  27. package/dist/cjs/billing/ar-repository.js +82 -6
  28. package/dist/cjs/billing/ar-repository.js.map +1 -1
  29. package/dist/cjs/billing/provider-account.js +60 -1
  30. package/dist/cjs/billing/provider-account.js.map +1 -1
  31. package/dist/cjs/billing/repository.js +51 -5
  32. package/dist/cjs/billing/repository.js.map +1 -1
  33. package/dist/cjs/clients/ibge.js +117 -0
  34. package/dist/cjs/clients/ibge.js.map +1 -0
  35. package/dist/cjs/clients/registry/http.js +157 -0
  36. package/dist/cjs/clients/registry/http.js.map +1 -0
  37. package/dist/cjs/clients/registry/ibge-municipios.js +28 -0
  38. package/dist/cjs/clients/registry/ibge-municipios.js.map +1 -0
  39. package/dist/cjs/clients/registry/ibge.js +63 -0
  40. package/dist/cjs/clients/registry/ibge.js.map +1 -0
  41. package/dist/cjs/clients/registry/lookup.js +191 -0
  42. package/dist/cjs/clients/registry/lookup.js.map +1 -0
  43. package/dist/cjs/clients/registry/provider.js +34 -0
  44. package/dist/cjs/clients/registry/provider.js.map +1 -0
  45. package/dist/cjs/clients/registry/resolve.js +47 -0
  46. package/dist/cjs/clients/registry/resolve.js.map +1 -0
  47. package/dist/cjs/clients/registry/serpro.js +149 -0
  48. package/dist/cjs/clients/registry/serpro.js.map +1 -0
  49. package/dist/cjs/clients/registry/service.js +230 -0
  50. package/dist/cjs/clients/registry/service.js.map +1 -0
  51. package/dist/cjs/clients/registry/synthetic.js +165 -0
  52. package/dist/cjs/clients/registry/synthetic.js.map +1 -0
  53. package/dist/cjs/clients/repository.js +190 -9
  54. package/dist/cjs/clients/repository.js.map +1 -1
  55. package/dist/cjs/collection/branding.js +190 -0
  56. package/dist/cjs/collection/branding.js.map +1 -1
  57. package/dist/cjs/collection/clearance-store.js +74 -0
  58. package/dist/cjs/collection/clearance-store.js.map +1 -0
  59. package/dist/cjs/collection/communication-runtime.js +65 -2
  60. package/dist/cjs/collection/communication-runtime.js.map +1 -1
  61. package/dist/cjs/collection/engine.js +20 -0
  62. package/dist/cjs/collection/engine.js.map +1 -1
  63. package/dist/cjs/collection/policy.js +29 -1
  64. package/dist/cjs/collection/policy.js.map +1 -1
  65. package/dist/cjs/communication/clearance.js +18 -0
  66. package/dist/cjs/communication/clearance.js.map +1 -0
  67. package/dist/cjs/communication/dry-run-scenario.js +5 -0
  68. package/dist/cjs/communication/dry-run-scenario.js.map +1 -1
  69. package/dist/cjs/communication/engine.js +12 -0
  70. package/dist/cjs/communication/engine.js.map +1 -1
  71. package/dist/cjs/communication/policy.js.map +1 -1
  72. package/dist/cjs/competence/business-days.js +155 -0
  73. package/dist/cjs/competence/business-days.js.map +1 -0
  74. package/dist/cjs/competence/catalog-validation.js +174 -0
  75. package/dist/cjs/competence/catalog-validation.js.map +1 -0
  76. package/dist/cjs/competence/obligation-preview.js +190 -0
  77. package/dist/cjs/competence/obligation-preview.js.map +1 -0
  78. package/dist/cjs/competence/repository.js +330 -17
  79. package/dist/cjs/competence/repository.js.map +1 -1
  80. package/dist/cjs/dashboard/pilot-panel.js +90 -0
  81. package/dist/cjs/dashboard/pilot-panel.js.map +1 -0
  82. package/dist/cjs/dashboard/repository.js +11 -1
  83. package/dist/cjs/dashboard/repository.js.map +1 -1
  84. package/dist/cjs/db/client.js +17 -11
  85. package/dist/cjs/db/client.js.map +1 -1
  86. package/dist/cjs/db/provision-e2e-identity.js +116 -0
  87. package/dist/cjs/db/provision-e2e-identity.js.map +1 -0
  88. package/dist/cjs/fiscal/applicability.js +164 -0
  89. package/dist/cjs/fiscal/applicability.js.map +1 -0
  90. package/dist/cjs/fiscal/collection/authorization.js +186 -0
  91. package/dist/cjs/fiscal/collection/authorization.js.map +1 -0
  92. package/dist/cjs/fiscal/collection/competence.js +97 -0
  93. package/dist/cjs/fiscal/collection/competence.js.map +1 -0
  94. package/dist/cjs/fiscal/collection/first-contact.js +204 -0
  95. package/dist/cjs/fiscal/collection/first-contact.js.map +1 -0
  96. package/dist/cjs/fiscal/collection/plan.js +122 -0
  97. package/dist/cjs/fiscal/collection/plan.js.map +1 -0
  98. package/dist/cjs/fiscal/conditions.js +198 -0
  99. package/dist/cjs/fiscal/conditions.js.map +1 -0
  100. package/dist/cjs/fiscal/contracts/nfse-adn-contract.js +390 -0
  101. package/dist/cjs/fiscal/contracts/nfse-adn-contract.js.map +1 -0
  102. package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js +108 -0
  103. package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
  104. package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js +220 -0
  105. package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
  106. package/dist/cjs/fiscal/coverage/model.js +137 -0
  107. package/dist/cjs/fiscal/coverage/model.js.map +1 -0
  108. package/dist/cjs/fiscal/coverage/requests.js +99 -0
  109. package/dist/cjs/fiscal/coverage/requests.js.map +1 -0
  110. package/dist/cjs/fiscal/credentials/inspect.js +182 -0
  111. package/dist/cjs/fiscal/credentials/inspect.js.map +1 -0
  112. package/dist/cjs/fiscal/credentials/material.js +168 -0
  113. package/dist/cjs/fiscal/credentials/material.js.map +1 -0
  114. package/dist/cjs/fiscal/credentials/onboarding.js +266 -0
  115. package/dist/cjs/fiscal/credentials/onboarding.js.map +1 -0
  116. package/dist/cjs/fiscal/credentials/readiness.js +190 -0
  117. package/dist/cjs/fiscal/credentials/readiness.js.map +1 -0
  118. package/dist/cjs/fiscal/eligibility.js +199 -0
  119. package/dist/cjs/fiscal/eligibility.js.map +1 -0
  120. package/dist/cjs/fiscal/enrollment.js +134 -0
  121. package/dist/cjs/fiscal/enrollment.js.map +1 -0
  122. package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js +128 -0
  123. package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
  124. package/dist/cjs/fiscal/ingestion/adn-transport.js +229 -0
  125. package/dist/cjs/fiscal/ingestion/adn-transport.js.map +1 -0
  126. package/dist/cjs/fiscal/ingestion/direction.js +36 -0
  127. package/dist/cjs/fiscal/ingestion/direction.js.map +1 -0
  128. package/dist/cjs/fiscal/ingestion/nfse-adn.js +228 -0
  129. package/dist/cjs/fiscal/ingestion/nfse-adn.js.map +1 -0
  130. package/dist/cjs/fiscal/ingestion/pipeline.js +704 -0
  131. package/dist/cjs/fiscal/ingestion/pipeline.js.map +1 -0
  132. package/dist/cjs/fiscal/ingestion/provider.js +51 -0
  133. package/dist/cjs/fiscal/ingestion/provider.js.map +1 -0
  134. package/dist/cjs/fiscal/ingestion/repository.js +132 -0
  135. package/dist/cjs/fiscal/ingestion/repository.js.map +1 -0
  136. package/dist/cjs/fiscal/ingestion/synthetic-provider.js +103 -0
  137. package/dist/cjs/fiscal/ingestion/synthetic-provider.js.map +1 -0
  138. package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js +13 -0
  139. package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
  140. package/dist/cjs/fiscal/ingestion/synthetic-transport.js +61 -0
  141. package/dist/cjs/fiscal/ingestion/synthetic-transport.js.map +1 -0
  142. package/dist/cjs/fiscal/ingestion/xml-reader.js +121 -0
  143. package/dist/cjs/fiscal/ingestion/xml-reader.js.map +1 -0
  144. package/dist/cjs/fiscal/repository.js +470 -0
  145. package/dist/cjs/fiscal/repository.js.map +1 -0
  146. package/dist/cjs/fiscal/sync/circuit.js +124 -0
  147. package/dist/cjs/fiscal/sync/circuit.js.map +1 -0
  148. package/dist/cjs/fiscal/sync/intervention.js +140 -0
  149. package/dist/cjs/fiscal/sync/intervention.js.map +1 -0
  150. package/dist/cjs/fiscal/sync/lease.js +146 -0
  151. package/dist/cjs/fiscal/sync/lease.js.map +1 -0
  152. package/dist/cjs/fiscal/sync/observability.js +244 -0
  153. package/dist/cjs/fiscal/sync/observability.js.map +1 -0
  154. package/dist/cjs/fiscal/sync/orchestrator.js +490 -0
  155. package/dist/cjs/fiscal/sync/orchestrator.js.map +1 -0
  156. package/dist/cjs/fiscal/sync/policy.js +143 -0
  157. package/dist/cjs/fiscal/sync/policy.js.map +1 -0
  158. package/dist/cjs/fiscal/sync/reprocess.js +241 -0
  159. package/dist/cjs/fiscal/sync/reprocess.js.map +1 -0
  160. package/dist/cjs/fiscal/sync/retry.js +183 -0
  161. package/dist/cjs/fiscal/sync/retry.js.map +1 -0
  162. package/dist/cjs/fiscal/sync/secret-boundary.js +123 -0
  163. package/dist/cjs/fiscal/sync/secret-boundary.js.map +1 -0
  164. package/dist/cjs/fiscal/transport/https.js +309 -0
  165. package/dist/cjs/fiscal/transport/https.js.map +1 -0
  166. package/dist/cjs/fiscal/transport/synthetic-tls.js +380 -0
  167. package/dist/cjs/fiscal/transport/synthetic-tls.js.map +1 -0
  168. package/dist/cjs/fiscal/transport/types.js +93 -0
  169. package/dist/cjs/fiscal/transport/types.js.map +1 -0
  170. package/dist/cjs/import/br-documents.js +85 -0
  171. package/dist/cjs/import/br-documents.js.map +1 -0
  172. package/dist/cjs/import/clients-import.js +347 -40
  173. package/dist/cjs/import/clients-import.js.map +1 -1
  174. package/dist/cjs/index.js +461 -73
  175. package/dist/cjs/index.js.map +1 -1
  176. package/dist/cjs/legal/documents.js +164 -19
  177. package/dist/cjs/legal/documents.js.map +1 -1
  178. package/dist/cjs/legal/index.js +3 -1
  179. package/dist/cjs/legal/index.js.map +1 -1
  180. package/dist/cjs/legal/types.js.map +1 -1
  181. package/dist/cjs/onboarding/persistence.js +4 -4
  182. package/dist/cjs/onboarding/persistence.js.map +1 -1
  183. package/dist/cjs/pilot/go-live-checklist.js +212 -0
  184. package/dist/cjs/pilot/go-live-checklist.js.map +1 -0
  185. package/dist/cjs/pilot/milestone.js +79 -0
  186. package/dist/cjs/pilot/milestone.js.map +1 -0
  187. package/dist/cjs/platform/capabilities.js +173 -0
  188. package/dist/cjs/platform/capabilities.js.map +1 -0
  189. package/dist/cjs/platform/job-contract.js +411 -0
  190. package/dist/cjs/platform/job-contract.js.map +1 -0
  191. package/dist/cjs/rbac/catalog.js +110 -0
  192. package/dist/cjs/rbac/catalog.js.map +1 -1
  193. package/dist/cjs/subscription-billing/index.js +9 -1
  194. package/dist/cjs/subscription-billing/index.js.map +1 -1
  195. package/dist/cjs/subscription-billing/platform-exemption.js +121 -0
  196. package/dist/cjs/subscription-billing/platform-exemption.js.map +1 -0
  197. package/dist/cjs/subscription-billing/service.js +246 -78
  198. package/dist/cjs/subscription-billing/service.js.map +1 -1
  199. package/dist/cjs/tenancy/features.js +131 -0
  200. package/dist/cjs/tenancy/features.js.map +1 -0
  201. package/dist/cjs/tenancy/settings.js +224 -0
  202. package/dist/cjs/tenancy/settings.js.map +1 -0
  203. package/dist/cjs/users/repository.js +24 -1
  204. package/dist/cjs/users/repository.js.map +1 -1
  205. package/dist/cjs/vault/repository.js +92 -5
  206. package/dist/cjs/vault/repository.js.map +1 -1
  207. package/dist/clients/ibge.d.ts +17 -0
  208. package/dist/clients/ibge.d.ts.map +1 -0
  209. package/dist/clients/ibge.js +112 -0
  210. package/dist/clients/ibge.js.map +1 -0
  211. package/dist/clients/registry/http.d.ts +61 -0
  212. package/dist/clients/registry/http.d.ts.map +1 -0
  213. package/dist/clients/registry/http.js +151 -0
  214. package/dist/clients/registry/http.js.map +1 -0
  215. package/dist/clients/registry/ibge-municipios.d.ts +25 -0
  216. package/dist/clients/registry/ibge-municipios.d.ts.map +1 -0
  217. package/dist/clients/registry/ibge-municipios.js +25 -0
  218. package/dist/clients/registry/ibge-municipios.js.map +1 -0
  219. package/dist/clients/registry/ibge.d.ts +62 -0
  220. package/dist/clients/registry/ibge.d.ts.map +1 -0
  221. package/dist/clients/registry/ibge.js +57 -0
  222. package/dist/clients/registry/ibge.js.map +1 -0
  223. package/dist/clients/registry/lookup.d.ts +94 -0
  224. package/dist/clients/registry/lookup.d.ts.map +1 -0
  225. package/dist/clients/registry/lookup.js +184 -0
  226. package/dist/clients/registry/lookup.js.map +1 -0
  227. package/dist/clients/registry/provider.d.ts +124 -0
  228. package/dist/clients/registry/provider.d.ts.map +1 -0
  229. package/dist/clients/registry/provider.js +39 -0
  230. package/dist/clients/registry/provider.js.map +1 -0
  231. package/dist/clients/registry/resolve.d.ts +36 -0
  232. package/dist/clients/registry/resolve.d.ts.map +1 -0
  233. package/dist/clients/registry/resolve.js +44 -0
  234. package/dist/clients/registry/resolve.js.map +1 -0
  235. package/dist/clients/registry/serpro.d.ts +57 -0
  236. package/dist/clients/registry/serpro.d.ts.map +1 -0
  237. package/dist/clients/registry/serpro.js +143 -0
  238. package/dist/clients/registry/serpro.js.map +1 -0
  239. package/dist/clients/registry/service.d.ts +59 -0
  240. package/dist/clients/registry/service.d.ts.map +1 -0
  241. package/dist/clients/registry/service.js +225 -0
  242. package/dist/clients/registry/service.js.map +1 -0
  243. package/dist/clients/registry/synthetic.d.ts +30 -0
  244. package/dist/clients/registry/synthetic.d.ts.map +1 -0
  245. package/dist/clients/registry/synthetic.js +161 -0
  246. package/dist/clients/registry/synthetic.js.map +1 -0
  247. package/dist/clients/repository.d.ts +158 -0
  248. package/dist/clients/repository.d.ts.map +1 -1
  249. package/dist/clients/repository.js +186 -9
  250. package/dist/clients/repository.js.map +1 -1
  251. package/dist/collection/branding.d.ts +65 -0
  252. package/dist/collection/branding.d.ts.map +1 -1
  253. package/dist/collection/branding.js +186 -0
  254. package/dist/collection/branding.js.map +1 -1
  255. package/dist/collection/clearance-store.d.ts +39 -0
  256. package/dist/collection/clearance-store.d.ts.map +1 -0
  257. package/dist/collection/clearance-store.js +69 -0
  258. package/dist/collection/clearance-store.js.map +1 -0
  259. package/dist/collection/communication-runtime.d.ts +37 -0
  260. package/dist/collection/communication-runtime.d.ts.map +1 -1
  261. package/dist/collection/communication-runtime.js +63 -1
  262. package/dist/collection/communication-runtime.js.map +1 -1
  263. package/dist/collection/engine.d.ts +23 -0
  264. package/dist/collection/engine.d.ts.map +1 -1
  265. package/dist/collection/engine.js +20 -0
  266. package/dist/collection/engine.js.map +1 -1
  267. package/dist/collection/policy.d.ts +25 -0
  268. package/dist/collection/policy.d.ts.map +1 -1
  269. package/dist/collection/policy.js +27 -0
  270. package/dist/collection/policy.js.map +1 -1
  271. package/dist/communication/clearance.d.ts +53 -0
  272. package/dist/communication/clearance.d.ts.map +1 -0
  273. package/dist/communication/clearance.js +15 -0
  274. package/dist/communication/clearance.js.map +1 -0
  275. package/dist/communication/dry-run-scenario.d.ts.map +1 -1
  276. package/dist/communication/dry-run-scenario.js +5 -0
  277. package/dist/communication/dry-run-scenario.js.map +1 -1
  278. package/dist/communication/engine.d.ts +10 -0
  279. package/dist/communication/engine.d.ts.map +1 -1
  280. package/dist/communication/engine.js +12 -0
  281. package/dist/communication/engine.js.map +1 -1
  282. package/dist/communication/policy.d.ts +16 -0
  283. package/dist/communication/policy.d.ts.map +1 -1
  284. package/dist/communication/policy.js.map +1 -1
  285. package/dist/competence/business-days.d.ts +51 -0
  286. package/dist/competence/business-days.d.ts.map +1 -0
  287. package/dist/competence/business-days.js +145 -0
  288. package/dist/competence/business-days.js.map +1 -0
  289. package/dist/competence/catalog-validation.d.ts +86 -0
  290. package/dist/competence/catalog-validation.d.ts.map +1 -0
  291. package/dist/competence/catalog-validation.js +168 -0
  292. package/dist/competence/catalog-validation.js.map +1 -0
  293. package/dist/competence/obligation-preview.d.ts +103 -0
  294. package/dist/competence/obligation-preview.d.ts.map +1 -0
  295. package/dist/competence/obligation-preview.js +184 -0
  296. package/dist/competence/obligation-preview.js.map +1 -0
  297. package/dist/competence/repository.d.ts +139 -1
  298. package/dist/competence/repository.d.ts.map +1 -1
  299. package/dist/competence/repository.js +325 -17
  300. package/dist/competence/repository.js.map +1 -1
  301. package/dist/dashboard/pilot-panel.d.ts +100 -0
  302. package/dist/dashboard/pilot-panel.d.ts.map +1 -0
  303. package/dist/dashboard/pilot-panel.js +87 -0
  304. package/dist/dashboard/pilot-panel.js.map +1 -0
  305. package/dist/dashboard/repository.d.ts.map +1 -1
  306. package/dist/dashboard/repository.js +11 -1
  307. package/dist/dashboard/repository.js.map +1 -1
  308. package/dist/db/client.d.ts +45 -0
  309. package/dist/db/client.d.ts.map +1 -1
  310. package/dist/db/client.js +16 -11
  311. package/dist/db/client.js.map +1 -1
  312. package/dist/db/migrate.d.ts +36 -1
  313. package/dist/db/migrate.d.ts.map +1 -1
  314. package/dist/db/migrate.js +199 -32
  315. package/dist/db/migrate.js.map +1 -1
  316. package/dist/db/provision-e2e-identity.d.ts +2 -0
  317. package/dist/db/provision-e2e-identity.d.ts.map +1 -0
  318. package/dist/db/provision-e2e-identity.js +114 -0
  319. package/dist/db/provision-e2e-identity.js.map +1 -0
  320. package/dist/fiscal/applicability.d.ts +73 -0
  321. package/dist/fiscal/applicability.d.ts.map +1 -0
  322. package/dist/fiscal/applicability.js +160 -0
  323. package/dist/fiscal/applicability.js.map +1 -0
  324. package/dist/fiscal/collection/authorization.d.ts +152 -0
  325. package/dist/fiscal/collection/authorization.d.ts.map +1 -0
  326. package/dist/fiscal/collection/authorization.js +178 -0
  327. package/dist/fiscal/collection/authorization.js.map +1 -0
  328. package/dist/fiscal/collection/competence.d.ts +66 -0
  329. package/dist/fiscal/collection/competence.d.ts.map +1 -0
  330. package/dist/fiscal/collection/competence.js +90 -0
  331. package/dist/fiscal/collection/competence.js.map +1 -0
  332. package/dist/fiscal/collection/first-contact.d.ts +103 -0
  333. package/dist/fiscal/collection/first-contact.d.ts.map +1 -0
  334. package/dist/fiscal/collection/first-contact.js +201 -0
  335. package/dist/fiscal/collection/first-contact.js.map +1 -0
  336. package/dist/fiscal/collection/plan.d.ts +74 -0
  337. package/dist/fiscal/collection/plan.d.ts.map +1 -0
  338. package/dist/fiscal/collection/plan.js +119 -0
  339. package/dist/fiscal/collection/plan.js.map +1 -0
  340. package/dist/fiscal/conditions.d.ts +99 -0
  341. package/dist/fiscal/conditions.d.ts.map +1 -0
  342. package/dist/fiscal/conditions.js +190 -0
  343. package/dist/fiscal/conditions.js.map +1 -0
  344. package/dist/fiscal/contracts/nfse-adn-contract.d.ts +315 -0
  345. package/dist/fiscal/contracts/nfse-adn-contract.d.ts.map +1 -0
  346. package/dist/fiscal/contracts/nfse-adn-contract.js +386 -0
  347. package/dist/fiscal/contracts/nfse-adn-contract.js.map +1 -0
  348. package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts +13 -0
  349. package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts.map +1 -0
  350. package/dist/fiscal/contracts/nfse-adn-endpoint.js +103 -0
  351. package/dist/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
  352. package/dist/fiscal/contracts/nfse-adn-envelope.d.ts +77 -0
  353. package/dist/fiscal/contracts/nfse-adn-envelope.d.ts.map +1 -0
  354. package/dist/fiscal/contracts/nfse-adn-envelope.js +215 -0
  355. package/dist/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
  356. package/dist/fiscal/coverage/model.d.ts +114 -0
  357. package/dist/fiscal/coverage/model.d.ts.map +1 -0
  358. package/dist/fiscal/coverage/model.js +130 -0
  359. package/dist/fiscal/coverage/model.js.map +1 -0
  360. package/dist/fiscal/coverage/requests.d.ts +70 -0
  361. package/dist/fiscal/coverage/requests.d.ts.map +1 -0
  362. package/dist/fiscal/coverage/requests.js +95 -0
  363. package/dist/fiscal/coverage/requests.js.map +1 -0
  364. package/dist/fiscal/credentials/inspect.d.ts +114 -0
  365. package/dist/fiscal/credentials/inspect.d.ts.map +1 -0
  366. package/dist/fiscal/credentials/inspect.js +178 -0
  367. package/dist/fiscal/credentials/inspect.js.map +1 -0
  368. package/dist/fiscal/credentials/material.d.ts +81 -0
  369. package/dist/fiscal/credentials/material.d.ts.map +1 -0
  370. package/dist/fiscal/credentials/material.js +164 -0
  371. package/dist/fiscal/credentials/material.js.map +1 -0
  372. package/dist/fiscal/credentials/onboarding.d.ts +119 -0
  373. package/dist/fiscal/credentials/onboarding.d.ts.map +1 -0
  374. package/dist/fiscal/credentials/onboarding.js +259 -0
  375. package/dist/fiscal/credentials/onboarding.js.map +1 -0
  376. package/dist/fiscal/credentials/readiness.d.ts +119 -0
  377. package/dist/fiscal/credentials/readiness.d.ts.map +1 -0
  378. package/dist/fiscal/credentials/readiness.js +186 -0
  379. package/dist/fiscal/credentials/readiness.js.map +1 -0
  380. package/dist/fiscal/eligibility.d.ts +106 -0
  381. package/dist/fiscal/eligibility.d.ts.map +1 -0
  382. package/dist/fiscal/eligibility.js +194 -0
  383. package/dist/fiscal/eligibility.js.map +1 -0
  384. package/dist/fiscal/enrollment.d.ts +91 -0
  385. package/dist/fiscal/enrollment.d.ts.map +1 -0
  386. package/dist/fiscal/enrollment.js +126 -0
  387. package/dist/fiscal/enrollment.js.map +1 -0
  388. package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts +57 -0
  389. package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts.map +1 -0
  390. package/dist/fiscal/ingestion/__fixtures__/nfse.js +121 -0
  391. package/dist/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
  392. package/dist/fiscal/ingestion/adn-transport.d.ts +123 -0
  393. package/dist/fiscal/ingestion/adn-transport.d.ts.map +1 -0
  394. package/dist/fiscal/ingestion/adn-transport.js +220 -0
  395. package/dist/fiscal/ingestion/adn-transport.js.map +1 -0
  396. package/dist/fiscal/ingestion/direction.d.ts +60 -0
  397. package/dist/fiscal/ingestion/direction.d.ts.map +1 -0
  398. package/dist/fiscal/ingestion/direction.js +32 -0
  399. package/dist/fiscal/ingestion/direction.js.map +1 -0
  400. package/dist/fiscal/ingestion/nfse-adn.d.ts +91 -0
  401. package/dist/fiscal/ingestion/nfse-adn.d.ts.map +1 -0
  402. package/dist/fiscal/ingestion/nfse-adn.js +222 -0
  403. package/dist/fiscal/ingestion/nfse-adn.js.map +1 -0
  404. package/dist/fiscal/ingestion/pipeline.d.ts +168 -0
  405. package/dist/fiscal/ingestion/pipeline.d.ts.map +1 -0
  406. package/dist/fiscal/ingestion/pipeline.js +699 -0
  407. package/dist/fiscal/ingestion/pipeline.js.map +1 -0
  408. package/dist/fiscal/ingestion/provider.d.ts +206 -0
  409. package/dist/fiscal/ingestion/provider.d.ts.map +1 -0
  410. package/dist/fiscal/ingestion/provider.js +47 -0
  411. package/dist/fiscal/ingestion/provider.js.map +1 -0
  412. package/dist/fiscal/ingestion/repository.d.ts +82 -0
  413. package/dist/fiscal/ingestion/repository.d.ts.map +1 -0
  414. package/dist/fiscal/ingestion/repository.js +127 -0
  415. package/dist/fiscal/ingestion/repository.js.map +1 -0
  416. package/dist/fiscal/ingestion/synthetic-provider.d.ts +92 -0
  417. package/dist/fiscal/ingestion/synthetic-provider.d.ts.map +1 -0
  418. package/dist/fiscal/ingestion/synthetic-provider.js +99 -0
  419. package/dist/fiscal/ingestion/synthetic-provider.js.map +1 -0
  420. package/dist/fiscal/ingestion/synthetic-transport-types.d.ts +19 -0
  421. package/dist/fiscal/ingestion/synthetic-transport-types.d.ts.map +1 -0
  422. package/dist/fiscal/ingestion/synthetic-transport-types.js +9 -0
  423. package/dist/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
  424. package/dist/fiscal/ingestion/synthetic-transport.d.ts +55 -0
  425. package/dist/fiscal/ingestion/synthetic-transport.d.ts.map +1 -0
  426. package/dist/fiscal/ingestion/synthetic-transport.js +57 -0
  427. package/dist/fiscal/ingestion/synthetic-transport.js.map +1 -0
  428. package/dist/fiscal/ingestion/xml-reader.d.ts +55 -0
  429. package/dist/fiscal/ingestion/xml-reader.d.ts.map +1 -0
  430. package/dist/fiscal/ingestion/xml-reader.js +112 -0
  431. package/dist/fiscal/ingestion/xml-reader.js.map +1 -0
  432. package/dist/fiscal/repository.d.ts +220 -0
  433. package/dist/fiscal/repository.d.ts.map +1 -0
  434. package/dist/fiscal/repository.js +449 -0
  435. package/dist/fiscal/repository.js.map +1 -0
  436. package/dist/fiscal/sync/circuit.d.ts +86 -0
  437. package/dist/fiscal/sync/circuit.d.ts.map +1 -0
  438. package/dist/fiscal/sync/circuit.js +118 -0
  439. package/dist/fiscal/sync/circuit.js.map +1 -0
  440. package/dist/fiscal/sync/intervention.d.ts +81 -0
  441. package/dist/fiscal/sync/intervention.d.ts.map +1 -0
  442. package/dist/fiscal/sync/intervention.js +135 -0
  443. package/dist/fiscal/sync/intervention.js.map +1 -0
  444. package/dist/fiscal/sync/lease.d.ts +118 -0
  445. package/dist/fiscal/sync/lease.d.ts.map +1 -0
  446. package/dist/fiscal/sync/lease.js +139 -0
  447. package/dist/fiscal/sync/lease.js.map +1 -0
  448. package/dist/fiscal/sync/observability.d.ts +148 -0
  449. package/dist/fiscal/sync/observability.d.ts.map +1 -0
  450. package/dist/fiscal/sync/observability.js +239 -0
  451. package/dist/fiscal/sync/observability.js.map +1 -0
  452. package/dist/fiscal/sync/orchestrator.d.ts +132 -0
  453. package/dist/fiscal/sync/orchestrator.d.ts.map +1 -0
  454. package/dist/fiscal/sync/orchestrator.js +487 -0
  455. package/dist/fiscal/sync/orchestrator.js.map +1 -0
  456. package/dist/fiscal/sync/policy.d.ts +87 -0
  457. package/dist/fiscal/sync/policy.d.ts.map +1 -0
  458. package/dist/fiscal/sync/policy.js +136 -0
  459. package/dist/fiscal/sync/policy.js.map +1 -0
  460. package/dist/fiscal/sync/reprocess.d.ts +76 -0
  461. package/dist/fiscal/sync/reprocess.d.ts.map +1 -0
  462. package/dist/fiscal/sync/reprocess.js +237 -0
  463. package/dist/fiscal/sync/reprocess.js.map +1 -0
  464. package/dist/fiscal/sync/retry.d.ts +82 -0
  465. package/dist/fiscal/sync/retry.d.ts.map +1 -0
  466. package/dist/fiscal/sync/retry.js +176 -0
  467. package/dist/fiscal/sync/retry.js.map +1 -0
  468. package/dist/fiscal/sync/secret-boundary.d.ts +169 -0
  469. package/dist/fiscal/sync/secret-boundary.d.ts.map +1 -0
  470. package/dist/fiscal/sync/secret-boundary.js +116 -0
  471. package/dist/fiscal/sync/secret-boundary.js.map +1 -0
  472. package/dist/fiscal/transport/https.d.ts +86 -0
  473. package/dist/fiscal/transport/https.d.ts.map +1 -0
  474. package/dist/fiscal/transport/https.js +303 -0
  475. package/dist/fiscal/transport/https.js.map +1 -0
  476. package/dist/fiscal/transport/synthetic-tls.d.ts +99 -0
  477. package/dist/fiscal/transport/synthetic-tls.d.ts.map +1 -0
  478. package/dist/fiscal/transport/synthetic-tls.js +374 -0
  479. package/dist/fiscal/transport/synthetic-tls.js.map +1 -0
  480. package/dist/fiscal/transport/types.d.ts +134 -0
  481. package/dist/fiscal/transport/types.d.ts.map +1 -0
  482. package/dist/fiscal/transport/types.js +88 -0
  483. package/dist/fiscal/transport/types.js.map +1 -0
  484. package/dist/import/br-documents.d.ts +26 -0
  485. package/dist/import/br-documents.d.ts.map +1 -0
  486. package/dist/import/br-documents.js +78 -0
  487. package/dist/import/br-documents.js.map +1 -0
  488. package/dist/import/clients-import.d.ts +122 -4
  489. package/dist/import/clients-import.d.ts.map +1 -1
  490. package/dist/import/clients-import.js +341 -41
  491. package/dist/import/clients-import.js.map +1 -1
  492. package/dist/index.d.ts +145 -13
  493. package/dist/index.d.ts.map +1 -1
  494. package/dist/index.js +120 -7
  495. package/dist/index.js.map +1 -1
  496. package/dist/legal/documents.d.ts +12 -1
  497. package/dist/legal/documents.d.ts.map +1 -1
  498. package/dist/legal/documents.js +162 -18
  499. package/dist/legal/documents.js.map +1 -1
  500. package/dist/legal/index.d.ts +2 -2
  501. package/dist/legal/index.d.ts.map +1 -1
  502. package/dist/legal/index.js +1 -1
  503. package/dist/legal/index.js.map +1 -1
  504. package/dist/legal/types.d.ts +114 -2
  505. package/dist/legal/types.d.ts.map +1 -1
  506. package/dist/legal/types.js.map +1 -1
  507. package/dist/onboarding/persistence.d.ts +10 -1
  508. package/dist/onboarding/persistence.d.ts.map +1 -1
  509. package/dist/onboarding/persistence.js +4 -4
  510. package/dist/onboarding/persistence.js.map +1 -1
  511. package/dist/pilot/go-live-checklist.d.ts +41 -0
  512. package/dist/pilot/go-live-checklist.d.ts.map +1 -0
  513. package/dist/pilot/go-live-checklist.js +209 -0
  514. package/dist/pilot/go-live-checklist.js.map +1 -0
  515. package/dist/pilot/milestone.d.ts +56 -0
  516. package/dist/pilot/milestone.d.ts.map +1 -0
  517. package/dist/pilot/milestone.js +74 -0
  518. package/dist/pilot/milestone.js.map +1 -0
  519. package/dist/platform/capabilities.d.ts +88 -0
  520. package/dist/platform/capabilities.d.ts.map +1 -0
  521. package/dist/platform/capabilities.js +169 -0
  522. package/dist/platform/capabilities.js.map +1 -0
  523. package/dist/platform/job-contract.d.ts +232 -0
  524. package/dist/platform/job-contract.d.ts.map +1 -0
  525. package/dist/platform/job-contract.js +403 -0
  526. package/dist/platform/job-contract.js.map +1 -0
  527. package/dist/rbac/catalog.d.ts.map +1 -1
  528. package/dist/rbac/catalog.js +110 -0
  529. package/dist/rbac/catalog.js.map +1 -1
  530. package/dist/subscription-billing/index.d.ts +8 -5
  531. package/dist/subscription-billing/index.d.ts.map +1 -1
  532. package/dist/subscription-billing/index.js +4 -3
  533. package/dist/subscription-billing/index.js.map +1 -1
  534. package/dist/subscription-billing/platform-exemption.d.ts +89 -0
  535. package/dist/subscription-billing/platform-exemption.d.ts.map +1 -0
  536. package/dist/subscription-billing/platform-exemption.js +113 -0
  537. package/dist/subscription-billing/platform-exemption.js.map +1 -0
  538. package/dist/subscription-billing/service.d.ts +74 -0
  539. package/dist/subscription-billing/service.d.ts.map +1 -1
  540. package/dist/subscription-billing/service.js +182 -16
  541. package/dist/subscription-billing/service.js.map +1 -1
  542. package/dist/tenancy/features.d.ts +69 -0
  543. package/dist/tenancy/features.d.ts.map +1 -0
  544. package/dist/tenancy/features.js +123 -0
  545. package/dist/tenancy/features.js.map +1 -0
  546. package/dist/tenancy/settings.d.ts +63 -0
  547. package/dist/tenancy/settings.d.ts.map +1 -0
  548. package/dist/tenancy/settings.js +218 -0
  549. package/dist/tenancy/settings.js.map +1 -0
  550. package/dist/users/repository.d.ts +16 -1
  551. package/dist/users/repository.d.ts.map +1 -1
  552. package/dist/users/repository.js +24 -1
  553. package/dist/users/repository.js.map +1 -1
  554. package/dist/vault/repository.d.ts +69 -1
  555. package/dist/vault/repository.d.ts.map +1 -1
  556. package/dist/vault/repository.js +88 -5
  557. package/dist/vault/repository.js.map +1 -1
  558. package/package.json +10 -2
  559. package/src/db/migrations/0045_role_write_scope.sql +122 -0
  560. package/src/db/migrations/0046_pilot_activation_model.sql +184 -0
  561. package/src/db/migrations/0047_recipient_clearance.sql +89 -0
  562. package/src/db/migrations/0048_item_type_note.sql +16 -0
  563. package/src/db/migrations/0049_national_fiscal_engine.sql +279 -0
  564. package/src/db/migrations/0050_fiscal_vocabulary_readonly.sql +29 -0
  565. package/src/db/migrations/0051_seed_rules_from_catalog.sql +72 -0
  566. package/src/db/migrations/0052_fiscal_rule_delete_scope.sql +57 -0
  567. package/src/db/migrations/0053_rule_validity_lower_bound.sql +44 -0
  568. package/src/db/migrations/0054_tenant_profile_and_rule_source.sql +89 -0
  569. package/src/db/migrations/0055_job_capability_contract.sql +300 -0
  570. package/src/db/migrations/0056_fiscal_document_ingestion.sql +337 -0
  571. package/src/db/migrations/0057_fiscal_pending_event_inbox.sql +228 -0
  572. package/src/db/migrations/0058_fiscal_operational_engine.sql +516 -0
  573. package/src/db/migrations/0059_fiscal_contract_version.sql +59 -0
  574. package/src/db/migrations/0060_fiscal_credential_vault_and_run_authorization.sql +321 -0
  575. package/src/db/migrations/0061_client_official_registry_provenance.sql +193 -0
  576. package/src/db/migrations/0062_first_contact_and_capability_truth.sql +119 -0
@@ -0,0 +1,72 @@
1
+ -- 0051 — os 17 seeds viram regras, SEM ganhar precisão que não têm.
2
+ --
3
+ -- ═══ O risco que esta migration precisa não correr ═════════════════════════
4
+ --
5
+ -- É tentador aproveitar a estrutura nova para "melhorar" o seed: dar UF ao ISS,
6
+ -- marcar as federais como validadas, escrever condição de folha nos itens
7
+ -- trabalhistas. Cada uma dessas seria legislação inventada por quem não tem
8
+ -- competência para inventá-la — e escrita num lugar em que passaria a parecer
9
+ -- fonte.
10
+ --
11
+ -- Então esta migration converte o que existe, e **nada mais**:
12
+ --
13
+ -- • toda regra nasce `pending_validation`. Nenhuma vira `validated`: ninguém
14
+ -- conferiu nada ainda, e o CHECK do banco exige autor para validar;
15
+ -- • toda condição nasce `{"op":"always"}` — a aplicabilidade que o seed de
16
+ -- fato tem hoje é por regime, e o regime já é filtrado por
17
+ -- `applies_to_regime` no tipo de item. Não invento condição de folha;
18
+ -- • os dois itens de esfera local viram `not_configured`, porque **não se
19
+ -- sabe de qual UF nem de qual município eles são**. Dar-lhes uma
20
+ -- jurisdição seria escolher um estado por conta própria.
21
+ --
22
+ -- `valid_from` é a data desta migration: é honesto dizer "esta regra existe no
23
+ -- sistema desde hoje", e desonesto dizer que ela vale desde sempre.
24
+
25
+ DO $$
26
+ DECLARE
27
+ r record;
28
+ hoje date := CURRENT_DATE;
29
+ BEGIN
30
+ FOR r IN
31
+ SELECT id, key, sphere, due_rule, note
32
+ FROM recurring_item_type
33
+ WHERE tenant_id IS NULL AND deleted_at IS NULL
34
+ LOOP
35
+ -- Idempotente: reexecutar não duplica.
36
+ IF EXISTS (SELECT 1 FROM fiscal_rule WHERE item_type_id = r.id AND tenant_id IS NULL) THEN
37
+ CONTINUE;
38
+ END IF;
39
+
40
+ IF r.sphere IN ('estadual', 'municipal') THEN
41
+ -- Marcador honesto: o item existe, a regra não. Sem UF, sem município e
42
+ -- sem vencimento — o motor devolve RULE_NOT_CONFIGURED e ninguém gera
43
+ -- obrigação local por engano.
44
+ --
45
+ -- Fica como `federal` no campo de escopo apenas porque o CHECK exige
46
+ -- jurisdição completa para state/municipal, e completá-la seria inventar.
47
+ -- O `status` é quem carrega a verdade: não configurada.
48
+ INSERT INTO fiscal_rule (
49
+ id, tenant_id, item_type_id, jurisdiction_scope, version, valid_from,
50
+ status, conditions, due_rule, note
51
+ ) VALUES (
52
+ gen_random_uuid(), NULL, r.id, 'federal', 1, hoje,
53
+ 'not_configured', '{"op":"always"}'::jsonb, NULL,
54
+ coalesce(r.note || ' ', '') ||
55
+ '[N1] Item de esfera ' || r.sphere || ' sem jurisdição definida. ' ||
56
+ 'Cadastre uma regra por UF (ou por município) antes de gerar.'
57
+ );
58
+ ELSE
59
+ INSERT INTO fiscal_rule (
60
+ id, tenant_id, item_type_id, jurisdiction_scope, version, valid_from,
61
+ status, conditions, due_rule, note
62
+ ) VALUES (
63
+ gen_random_uuid(), NULL, r.id, 'federal', 1, hoje,
64
+ 'pending_validation', '{"op":"always"}'::jsonb, r.due_rule,
65
+ coalesce(r.note, '')
66
+ );
67
+ END IF;
68
+ END LOOP;
69
+ END $$;
70
+
71
+ COMMENT ON TABLE fiscal_rule IS
72
+ 'Regra fiscal versionada por jurisdição. As 17 primeiras vieram do seed inicial e nascem PENDING_VALIDATION ou NOT_CONFIGURED — nenhuma foi conferida por pessoa, e nenhuma ganhou jurisdição ou prazo que o seed não tinha.';
@@ -0,0 +1,57 @@
1
+ -- 0052 — fechar o DELETE da regra fiscal GLOBAL.
2
+ --
3
+ -- ═══ O defeito, encontrado pelo teste antes do deploy ══════════════════════
4
+ --
5
+ -- A 0049 criou uma política única para `fiscal_rule`:
6
+ --
7
+ -- USING (tenant_id IS NULL OR tenant_id = current_tenant)
8
+ -- WITH CHECK (tenant_id = current_tenant)
9
+ --
10
+ -- Esse par fecha INSERT e UPDATE — e **não fecha DELETE**. `WITH CHECK` só
11
+ -- governa a linha que passa a existir; quem decide o que um DELETE alcança é o
12
+ -- `USING`. Com o ramo `IS NULL` ali, qualquer escritório apagava regra fiscal
13
+ -- nacional: as regras de todos os outros escritórios do país.
14
+ --
15
+ -- É a mesma forma do P0-A da Fase 4 — o ramo `IS NULL` no lugar errado — com
16
+ -- um agravante: lá a barreira de privilégio segurava, porque `role` teve
17
+ -- INSERT/UPDATE/DELETE revogados do runtime. Aqui não dá para revogar: o
18
+ -- escritório precisa escrever as PRÓPRIAS regras. A separação tem de vir da
19
+ -- política.
20
+ --
21
+ -- ═══ A correção ════════════════════════════════════════════════════════════
22
+ --
23
+ -- Uma política por comando, em vez de uma para tudo. Ler o catálogo nacional é
24
+ -- direito de todos; alterá-lo, de ninguém que opere como escritório.
25
+
26
+ DROP POLICY IF EXISTS fiscal_rule_visibility ON fiscal_rule;
27
+
28
+ CREATE POLICY fiscal_rule_read ON fiscal_rule
29
+ FOR SELECT
30
+ USING (tenant_id IS NULL OR tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
31
+
32
+ CREATE POLICY fiscal_rule_insert ON fiscal_rule
33
+ FOR INSERT
34
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
35
+
36
+ CREATE POLICY fiscal_rule_update ON fiscal_rule
37
+ FOR UPDATE
38
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
39
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
40
+
41
+ CREATE POLICY fiscal_rule_delete ON fiscal_rule
42
+ FOR DELETE
43
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
44
+
45
+ COMMENT ON POLICY fiscal_rule_read ON fiscal_rule IS
46
+ 'Leitura: catálogo nacional + regras do próprio escritório.';
47
+ COMMENT ON POLICY fiscal_rule_delete ON fiscal_rule IS
48
+ 'Apagar SOMENTE as próprias. A política única da 0049 deixava o DELETE alcançar a regra global, porque WITH CHECK não governa DELETE — só o USING governa.';
49
+
50
+ -- ── A mesma pergunta, feita às policies vizinhas ───────────────────────────
51
+ --
52
+ -- `role` e `role_permission` têm o mesmo formato desde a 0045 e, no papel,
53
+ -- o mesmo buraco no DELETE. Lá a segunda barreira segura: a 0045 revogou
54
+ -- INSERT, UPDATE e DELETE do runtime, e `migrate.ts` repete o REVOKE a cada
55
+ -- deploy. Fica registrado aqui porque a próxima pessoa a ler aquela policy vai
56
+ -- fazer esta pergunta — e a resposta é "o privilégio segura", não "a política
57
+ -- está certa".
@@ -0,0 +1,44 @@
1
+ -- 0053 — `valid_from` descreve a REGRA, não o dia em que a linha foi criada.
2
+ --
3
+ -- ═══ O erro da 0051, e por que ele parecia certo ═══════════════════════════
4
+ --
5
+ -- A 0051 gravou `valid_from = CURRENT_DATE` nas regras do seed, com a
6
+ -- justificativa de que é honesto dizer "esta regra existe no sistema desde
7
+ -- hoje". A frase é verdadeira e a modelagem estava errada: `valid_from` não
8
+ -- descreve quando o REGISTRO nasceu — descreve desde quando a REGRA vale.
9
+ --
10
+ -- O efeito apareceu no primeiro teste: um escritório que abre a competência de
11
+ -- agosto em setembro — que é o normal da profissão, não a exceção — não
12
+ -- recebia obrigação nenhuma, porque nenhuma regra era candidata para agosto.
13
+ --
14
+ -- ═══ Por que uma data antiga é mais honesta que hoje ══════════════════════
15
+ --
16
+ -- Não se sabe desde quando cada obrigação do seed está em vigor; várias são
17
+ -- anteriores ao produto. As duas opções eram:
18
+ --
19
+ -- hoje → afirma que a regra não valia em agosto. É falso.
20
+ -- limite baixo → afirma que ela vale desde antes de o sistema existir, sem
21
+ -- dizer desde quando. É verdadeiro e incompleto.
22
+ --
23
+ -- A segunda é a correta: `2000-01-01` aqui não é uma data legal, é a ausência
24
+ -- de início declarado. Declarar o início de verdade faz parte de validar a
25
+ -- regra, e as regras do seed continuam `pending_validation` justamente porque
26
+ -- ninguém as validou.
27
+ --
28
+ -- Nada disso relaxa a barreira: uma regra pendente não gera obrigação. O que
29
+ -- muda é que ela passa a ser CANDIDATA e a aparecer na prévia com o motivo
30
+ -- certo — "aguarda conferência" em vez de "não existe regra", que mandaria o
31
+ -- escritório procurar o que já está lá.
32
+
33
+ UPDATE fiscal_rule
34
+ SET valid_from = DATE '2000-01-01',
35
+ note = coalesce(note || ' ', '') ||
36
+ '[N1] Início de vigência não declarado: a data é um limite inferior, não uma afirmação legal.',
37
+ updated_at = now()
38
+ WHERE tenant_id IS NULL
39
+ AND deleted_at IS NULL
40
+ AND valid_from > DATE '2000-01-01'
41
+ AND status IN ('pending_validation', 'not_configured');
42
+
43
+ COMMENT ON COLUMN fiscal_rule.valid_from IS
44
+ 'Desde quando a REGRA vale — não quando a linha foi criada. Regra sem início declarado usa um limite inferior antigo, e declarar o início real faz parte de validá-la.';
@@ -0,0 +1,89 @@
1
+ -- 0054 — a identidade do escritório vira dado do produto, e a regra fiscal
2
+ -- passa a citar a fonte.
3
+ --
4
+ -- ═══ Por que estas duas coisas na mesma migration ══════════════════════════
5
+ --
6
+ -- As duas nascem do mesmo achado da auditoria C360: o produto tinha caminho de
7
+ -- LEITURA e não tinha caminho de ESCRITA. A marca do escritório vivia em
8
+ -- `tenant.settings` e só era gravável por `UPDATE` manual no banco; a regra
9
+ -- fiscal tinha `source_reference` em texto livre e nenhum lugar canônico para o
10
+ -- endereço da norma. Nos dois casos o efeito é o mesmo: um escritório novo
11
+ -- exigia desenvolvedor.
12
+ --
13
+ -- Nenhuma tabela nova. Nenhum GRANT novo: `tenant` e `fiscal_rule` já estão na
14
+ -- allowlist do runtime, e GRANT em Postgres é por tabela — coluna nova nasce
15
+ -- alcançável pelo mesmo privilégio.
16
+
17
+ -- ── 1 · Identidade do escritório ───────────────────────────────────────────
18
+ --
19
+ -- `display_name` e `legal_name` já existiam. Faltavam o documento e o fuso, e
20
+ -- os dois têm consumidor concreto e próximo:
21
+ --
22
+ -- documento → o escritório é ele mesmo um contribuinte. A onda de ingestão
23
+ -- fiscal precisa do CNPJ dele para o certificado da própria casa
24
+ -- (`digital_certificate.client_id IS NULL` já prevê esse caso).
25
+ -- fuso → todo vencimento hoje é calculado em data, sem hora. No dia em
26
+ -- que houver corte por horário (janela de envio, D-0 às 18h), a
27
+ -- ausência do fuso vira erro de um dia para metade do país.
28
+ --
29
+ -- Só dígitos, como em `client.document_number`: máscara é apresentação, e duas
30
+ -- representações do mesmo documento não se encontram em nenhuma busca.
31
+ ALTER TABLE tenant ADD COLUMN IF NOT EXISTS document_number text;
32
+ ALTER TABLE tenant ADD COLUMN IF NOT EXISTS timezone text NOT NULL DEFAULT 'America/Sao_Paulo';
33
+
34
+ DO $$
35
+ BEGIN
36
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'tenant_document_format') THEN
37
+ ALTER TABLE tenant ADD CONSTRAINT tenant_document_format
38
+ CHECK (document_number IS NULL OR document_number ~ '^[0-9]{11}$' OR document_number ~ '^[0-9]{14}$');
39
+ END IF;
40
+
41
+ -- Fuso: a lista dos fusos BRASILEIROS, não um texto livre.
42
+ --
43
+ -- `CHECK` não enxerga `pg_timezone_names`, então a alternativa seria aceitar
44
+ -- qualquer string e descobrir o erro na primeira conversão. O produto é
45
+ -- nacional; enumerar os dezesseis fusos do país é a restrição honesta e
46
+ -- fecha a porta para `'GMT-3'`, `'Brasilia'` e afins, que parecem certos e
47
+ -- não são identificadores IANA.
48
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'tenant_timezone_br') THEN
49
+ ALTER TABLE tenant ADD CONSTRAINT tenant_timezone_br
50
+ CHECK (timezone IN (
51
+ 'America/Sao_Paulo','America/Bahia','America/Fortaleza','America/Recife',
52
+ 'America/Belem','America/Araguaina','America/Maceio','America/Campo_Grande',
53
+ 'America/Cuiaba','America/Santarem','America/Manaus','America/Porto_Velho',
54
+ 'America/Boa_Vista','America/Rio_Branco','America/Eirunepe','America/Noronha'
55
+ ));
56
+ END IF;
57
+ END $$;
58
+
59
+ COMMENT ON COLUMN tenant.document_number IS
60
+ 'CNPJ (14) ou CPF (11) do próprio escritório, só dígitos. O escritório é contribuinte de si mesmo — a ingestão fiscal precisa deste número para o certificado da casa.';
61
+ COMMENT ON COLUMN tenant.timezone IS
62
+ 'Fuso IANA do escritório. Restrito aos fusos brasileiros: o produto é nacional e um texto livre aceitaria identificadores que não existem.';
63
+
64
+ -- ── 2 · A regra fiscal cita a fonte ────────────────────────────────────────
65
+ --
66
+ -- `source_reference` continua sendo a referência humana ("IN RFB 2.005/2021,
67
+ -- art. 3º"). `source_url` é o ENDEREÇO oficial, separado de propósito: uma URL
68
+ -- misturada com texto livre não pode ser verificada, aberta na tela nem
69
+ -- comparada entre versões.
70
+ --
71
+ -- Só https. A regra fiscal aparece numa tela de conferência e o endereço vira
72
+ -- link; `javascript:` e `data:` num campo editável seriam XSS armazenado com a
73
+ -- assinatura do escritório.
74
+ --
75
+ -- Isto NÃO valida a regra. Citar a fonte é o insumo da conferência humana, e
76
+ -- `status` continua exigindo `validated_by` e `validated_at` para sair de
77
+ -- `pending_validation`.
78
+ ALTER TABLE fiscal_rule ADD COLUMN IF NOT EXISTS source_url text;
79
+
80
+ DO $$
81
+ BEGIN
82
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'fiscal_rule_source_url_https') THEN
83
+ ALTER TABLE fiscal_rule ADD CONSTRAINT fiscal_rule_source_url_https
84
+ CHECK (source_url IS NULL OR source_url ~ '^https://[^\s"''<>]+$');
85
+ END IF;
86
+ END $$;
87
+
88
+ COMMENT ON COLUMN fiscal_rule.source_url IS
89
+ 'Endereço oficial da norma, https. Insumo da conferência humana — citar a fonte não valida a regra.';
@@ -0,0 +1,300 @@
1
+ -- 0055 — o contrato de capacidade dos JOBS, e a elegibilidade fiscal default-deny.
2
+ --
3
+ -- ═══ O que a Onda A fechou, e o que ficou aberto ═══════════════════════════
4
+ --
5
+ -- A Onda A fechou o skew de release entre a tela e a API: `GET /v1/capabilities`
6
+ -- declara o que aquele build serve, o console exige o que vai usar, e a
7
+ -- requisição condenada não parte (0054 / docs/architecture/141).
8
+ --
9
+ -- Isso protege a superfície HTTP. Não protege NADA que roda sem navegador.
10
+ --
11
+ -- Os dois crons deste produto (`baruk-collection-cron`, `baruk-billing-cron`)
12
+ -- publicam na Render como serviços SEPARADOS do serviço web, a partir da mesma
13
+ -- imagem mas com deploys independentes — e as migrations rodam no
14
+ -- `preDeployCommand` do serviço WEB, não no cron. A ordem entre "a imagem nova
15
+ -- do cron subiu" e "o schema novo foi aplicado" não é garantida por nada.
16
+ --
17
+ -- Então existem os dois lados da janela:
18
+ --
19
+ -- worker NOVO + schema VELHO → o job depende de coluna/tabela que ainda não
20
+ -- existe. Hoje isso aparece como exceção no meio do loop, DEPOIS de já ter
21
+ -- escrito no tenant anterior — estado parcial, que é exatamente o que a
22
+ -- ingestão fiscal não pode produzir.
23
+ --
24
+ -- worker VELHO + schema NOVO → o job escreve linhas sem o que o schema novo
25
+ -- passou a esperar. Aditivo sobrevive; obrigatório não.
26
+ --
27
+ -- ═══ Por que capacidade, e não SHA — de novo, e por outro motivo ═══════════
28
+ --
29
+ -- Para a tela, a contraparte é a API. Para um worker, a contraparte é o BANCO:
30
+ -- é a única superfície que os dois lados enxergam. Comparar o commit da imagem
31
+ -- do cron com o commit do serviço web acoplaria o job ao processo de release e
32
+ -- reprovaria um hotfix inofensivo.
33
+ --
34
+ -- Por isso o registro vive AQUI, no banco, e quem o escreve é a MIGRATION —
35
+ -- isto é, o mesmo ato que cria a capacidade. Uma capacidade não pode ser
36
+ -- declarada por quem a consome: `baruk_app` recebe apenas SELECT nesta tabela
37
+ -- (ver `db/migrate.ts`). Autoridade escrita pelo controlado não é autoridade,
38
+ -- e um worker que pudesse declarar a própria capacidade teria um portão com a
39
+ -- chave do lado de dentro.
40
+
41
+ -- ── 1 · Registro de capacidades da PLATAFORMA ──────────────────────────────
42
+ --
43
+ -- Global, sem `tenant_id`: a capacidade é do schema, não do escritório. Sem RLS
44
+ -- pelo mesmo motivo que `fiscal_attribute_definition` — e, como lá, a proteção
45
+ -- é o privilégio, não a policy.
46
+ --
47
+ -- Chave IMUTÁVEL, igual ao contrato HTTP: mudança incompatível ganha `.v2`, e a
48
+ -- `.v1` só sai quando nenhum worker em produção ainda a exigir. É essa regra
49
+ -- que faz `worker velho + schema novo` ser seguro: o registro só CRESCE, e
50
+ -- compatibilidade é continência de conjunto.
51
+ CREATE TABLE IF NOT EXISTS platform_capability (
52
+ key text PRIMARY KEY,
53
+ label text NOT NULL,
54
+ -- Versão do FORMATO do contrato, não da capacidade. Um worker que não
55
+ -- reconhece a versão trata tudo como indisponível: fail-closed é a única
56
+ -- leitura segura de um contrato que não se sabe ler.
57
+ contract_version int NOT NULL,
58
+ -- Qual migration declarou. Não é decoração: é como se responde "desde qual
59
+ -- deploy esta capacidade existe?" sem depender de git em tempo de execução.
60
+ declared_by_migration text NOT NULL,
61
+ declared_at timestamptz NOT NULL DEFAULT now(),
62
+ CONSTRAINT platform_capability_key_format
63
+ CHECK (key ~ '^[a-z0-9]+(-[a-z0-9]+)*(\.[a-z0-9]+(-[a-z0-9]+)*)+\.v[0-9]+$')
64
+ );
65
+
66
+ COMMENT ON TABLE platform_capability IS
67
+ 'O que ESTE schema sabe fazer. Escrito só por migration (baruk_app tem apenas SELECT): quem consome a capacidade não pode declará-la.';
68
+
69
+ INSERT INTO platform_capability (key, label, contract_version, declared_by_migration) VALUES
70
+ ('office.job-contract.v1',
71
+ 'Contrato de capacidade para jobs e workers', 1, '0055'),
72
+ ('office.collection-cycle.v1',
73
+ 'Ciclo diário de cobrança: geração de recebíveis da competência + régua', 1, '0055'),
74
+ ('office.saas-billing-cycle.v1',
75
+ 'Ciclo do Billing SaaS: trial, renovação, régua e suspensão', 1, '0055')
76
+ ON CONFLICT (key) DO NOTHING;
77
+
78
+ -- ── 2 · Cursor do job, por tenant ──────────────────────────────────────────
79
+ --
80
+ -- Existe para que "não consumir cursor irreversivelmente" seja uma propriedade
81
+ -- verificável, e não uma promessa. O cursor só avança quando o lote INTEIRO
82
+ -- termina sob um contrato compatível; run bloqueado não o toca.
83
+ --
84
+ -- `contract_version` grava sob qual contrato aquela posição foi alcançada. Um
85
+ -- worker que leia um cursor gravado sob contrato que ele não reconhece PARA —
86
+ -- em vez de reinterpretar a posição com semântica diferente.
87
+ CREATE TABLE IF NOT EXISTS job_cursor (
88
+ id uuid PRIMARY KEY,
89
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
90
+ job_name text NOT NULL,
91
+ position text NOT NULL,
92
+ contract_version int NOT NULL,
93
+ updated_at timestamptz NOT NULL DEFAULT now(),
94
+ CONSTRAINT job_cursor_tenant_id_uq UNIQUE (tenant_id, id)
95
+ );
96
+
97
+ CREATE UNIQUE INDEX IF NOT EXISTS job_cursor_uq ON job_cursor (tenant_id, job_name);
98
+
99
+ ALTER TABLE job_cursor ENABLE ROW LEVEL SECURITY;
100
+ ALTER TABLE job_cursor FORCE ROW LEVEL SECURITY;
101
+ CREATE POLICY job_cursor_tenant_isolation ON job_cursor
102
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
103
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
104
+
105
+ -- ── 3 · Trilha de execução do job ──────────────────────────────────────────
106
+ --
107
+ -- Um job bloqueado por incompatibilidade não pode falhar em silêncio. Esta
108
+ -- tabela é o registro nomeado do bloqueio: qual job, qual versão, o que exigia,
109
+ -- o que o schema declarava, e quando.
110
+ --
111
+ -- Sem PII e sem segredo por construção: só nomes de capacidade e contadores.
112
+ CREATE TABLE IF NOT EXISTS job_run (
113
+ id uuid PRIMARY KEY,
114
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
115
+ job_name text NOT NULL,
116
+ job_version int NOT NULL,
117
+ -- Os cinco estados. `TEMPORARILY_UNAVAILABLE` é deliberadamente separado de
118
+ -- `INCOMPATIBLE`: o primeiro volta sozinho e merece retry; o segundo exige um
119
+ -- deploy, e insistir nele é gastar orçamento contra uma parede.
120
+ readiness text NOT NULL CHECK (readiness IN (
121
+ 'READY', 'TEMPORARILY_UNAVAILABLE', 'INCOMPATIBLE',
122
+ 'DISABLED', 'BLOCKED_BY_TENANT_CONFIG')),
123
+ status text NOT NULL CHECK (status IN ('completed', 'blocked', 'failed')),
124
+ contract_version int,
125
+ required_capabilities text[] NOT NULL DEFAULT '{}',
126
+ observed_capabilities text[] NOT NULL DEFAULT '{}',
127
+ missing_capabilities text[] NOT NULL DEFAULT '{}',
128
+ mutations int NOT NULL DEFAULT 0 CHECK (mutations >= 0),
129
+ cursor_advanced boolean NOT NULL DEFAULT false,
130
+ detail text,
131
+ started_at timestamptz NOT NULL DEFAULT now(),
132
+ finished_at timestamptz,
133
+ CONSTRAINT job_run_tenant_id_uq UNIQUE (tenant_id, id),
134
+ -- O fail-closed vira invariante do BANCO, não promessa do TypeScript: é
135
+ -- impossível registrar um run bloqueado que tenha mutado ou avançado cursor.
136
+ -- Um refactor futuro que erre a ordem das operações não passa daqui.
137
+ CONSTRAINT job_run_blocked_is_inert
138
+ CHECK (status <> 'blocked' OR (mutations = 0 AND cursor_advanced = false)),
139
+ -- `READY` e bloqueio são mutuamente exclusivos: um run bloqueado tem de dizer
140
+ -- POR QUE, e 'READY' não é um motivo.
141
+ CONSTRAINT job_run_blocked_has_reason
142
+ CHECK (status <> 'blocked' OR readiness <> 'READY')
143
+ );
144
+
145
+ CREATE INDEX IF NOT EXISTS job_run_tenant_job_idx
146
+ ON job_run (tenant_id, job_name, started_at DESC);
147
+
148
+ ALTER TABLE job_run ENABLE ROW LEVEL SECURITY;
149
+ ALTER TABLE job_run FORCE ROW LEVEL SECURITY;
150
+ CREATE POLICY job_run_tenant_isolation ON job_run
151
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
152
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
153
+
154
+ COMMENT ON CONSTRAINT job_run_blocked_is_inert ON job_run IS
155
+ 'Fail-closed como invariante de banco: run bloqueado com mutação ou cursor avançado não é gravável.';
156
+
157
+ -- ═══ 4 · Elegibilidade fiscal — default deny em três camadas ════════════════
158
+ --
159
+ -- O achado que motiva isto: hoje NADA no produto distingue "cliente que existe"
160
+ -- de "cliente que pode entrar em automação fiscal". Um job futuro que
161
+ -- selecionasse por `deleted_at IS NULL` alcançaria, no tenant da SC, dois
162
+ -- cadastros que foram criados em teste — e alcançaria a carteira real inteira
163
+ -- no dia seguinte a uma importação.
164
+ --
165
+ -- É a mesma lição da 0047 (liberação do destinatário), aplicada a documento
166
+ -- fiscal em vez de e-mail: a ausência tem de ser a barreira. Um default "entra
167
+ -- quem ninguém proibiu" transforma omissão em autorização — e omissão é o
168
+ -- estado natural de todo cliente que acabou de entrar.
169
+ --
170
+ -- Três camadas, porque três coisas diferentes podem estar erradas:
171
+ -- tenant → o ESCRITÓRIO ligou automação fiscal? em qual ambiente?
172
+ -- cliente → ESTE cliente foi inscrito, para ESTE tipo de documento?
173
+ -- credencial → existe insumo para operar em nome dele? verificado?
174
+ --
175
+ -- E uma quarta, que não é tabela: o estado de operação real
176
+ -- (`tenant_pilot_milestone.real_pilot_start`, 0047). Ambiente `production`
177
+ -- exige o marco declarado; `synthetic` não — é o que mantém desenvolvimento e
178
+ -- homologação possíveis sem abrir a porta da carteira real.
179
+
180
+ -- ── 4.1 · O escritório liga a automação, e declara em qual ambiente ────────
181
+ --
182
+ -- Ausência de linha = `disabled`. Não existe valor que signifique "herda".
183
+ --
184
+ -- `mode` é ambiente E chave ao mesmo tempo, de propósito: separá-los criaria o
185
+ -- estado `enabled=true, environment=null`, que alguém teria de interpretar — e
186
+ -- interpretação é onde documento de homologação vira documento real.
187
+ CREATE TABLE IF NOT EXISTS tenant_fiscal_automation (
188
+ tenant_id uuid PRIMARY KEY REFERENCES tenant(id),
189
+ mode text NOT NULL DEFAULT 'disabled'
190
+ CHECK (mode IN ('disabled', 'synthetic', 'production')),
191
+ enabled_at timestamptz,
192
+ enabled_by uuid REFERENCES "user"(id),
193
+ note text,
194
+ updated_at timestamptz NOT NULL DEFAULT now(),
195
+ -- Ligar exige autor e data: "quem ligou isto?" é a única pergunta que a
196
+ -- linha existe para responder, e ela não pode ficar sem resposta.
197
+ CONSTRAINT tenant_fiscal_automation_enable_coherent
198
+ CHECK (mode = 'disabled' OR (enabled_at IS NOT NULL AND enabled_by IS NOT NULL))
199
+ );
200
+
201
+ ALTER TABLE tenant_fiscal_automation ENABLE ROW LEVEL SECURITY;
202
+ ALTER TABLE tenant_fiscal_automation FORCE ROW LEVEL SECURITY;
203
+ CREATE POLICY tenant_fiscal_automation_tenant_isolation ON tenant_fiscal_automation
204
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
205
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
206
+
207
+ COMMENT ON TABLE tenant_fiscal_automation IS
208
+ 'Ausência de linha = automação fiscal desligada. Nenhuma migration liga escritório nenhum; ligar é ato humano com autor e data.';
209
+
210
+ -- ── 4.2 · A inscrição do cliente, por tipo de documento ────────────────────
211
+ --
212
+ -- Por TIPO, e não um booleano no cliente: um escritório pode acompanhar a NFS-e
213
+ -- de um cliente sem tocar na NF-e dele, e o inverso. Um booleano forçaria tudo
214
+ -- ou nada, e "tudo" é sempre a escolha errada quando o insumo é documento
215
+ -- fiscal de terceiro.
216
+ --
217
+ -- Revogação é lógica e mantém o histórico: quem esteve inscrito e saiu é um
218
+ -- fato que a trilha precisa preservar.
219
+ CREATE TABLE IF NOT EXISTS client_fiscal_enrollment (
220
+ id uuid PRIMARY KEY,
221
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
222
+ client_id uuid NOT NULL,
223
+ document_type text NOT NULL CHECK (document_type IN ('nfe', 'nfse', 'cte', 'nfce')),
224
+ enrolled_at timestamptz NOT NULL DEFAULT now(),
225
+ enrolled_by uuid REFERENCES "user"(id),
226
+ revoked_at timestamptz,
227
+ revoked_by uuid REFERENCES "user"(id),
228
+ note text,
229
+ CONSTRAINT client_fiscal_enrollment_tenant_id_uq UNIQUE (tenant_id, id),
230
+ FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
231
+ CONSTRAINT client_fiscal_enrollment_revoke_coherent
232
+ CHECK ((revoked_at IS NULL) = (revoked_by IS NULL))
233
+ );
234
+
235
+ -- Uma inscrição VIVA por (cliente, tipo). Revogadas coexistem: são histórico.
236
+ CREATE UNIQUE INDEX IF NOT EXISTS client_fiscal_enrollment_live_uq
237
+ ON client_fiscal_enrollment (tenant_id, client_id, document_type)
238
+ WHERE revoked_at IS NULL;
239
+
240
+ ALTER TABLE client_fiscal_enrollment ENABLE ROW LEVEL SECURITY;
241
+ ALTER TABLE client_fiscal_enrollment FORCE ROW LEVEL SECURITY;
242
+ CREATE POLICY client_fiscal_enrollment_tenant_isolation ON client_fiscal_enrollment
243
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
244
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
245
+
246
+ -- ── 4.3 · Prontidão da credencial ──────────────────────────────────────────
247
+ --
248
+ -- Esta fase NÃO exige certificado A1. Ela define o conceito e o lugar.
249
+ --
250
+ -- O estado `no_credential` não está no CHECK de propósito: ele é a AUSÊNCIA de
251
+ -- linha, como em `client.communication_cleared_at`. Um enum com `no_credential`
252
+ -- permitiria a linha existir dizendo "não tem" — e daí alguém a criaria por
253
+ -- conveniência, e "não tem" viraria um estado configurável em vez do estado
254
+ -- natural de todo cliente.
255
+ --
256
+ -- `secret_ref` é referência do cofre (`vault://<nome>`), nunca o segredo. O
257
+ -- certificado é do CLIENTE, não do escritório e nem nosso: o que guardamos é
258
+ -- para onde apontar.
259
+ CREATE TABLE IF NOT EXISTS client_fiscal_credential (
260
+ id uuid PRIMARY KEY,
261
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
262
+ client_id uuid NOT NULL,
263
+ kind text NOT NULL CHECK (kind IN ('certificate_a1', 'municipal_portal')),
264
+ status text NOT NULL
265
+ CHECK (status IN ('configured_not_verified', 'verified', 'expired', 'revoked')),
266
+ secret_ref text,
267
+ verified_at timestamptz,
268
+ expires_on date,
269
+ updated_at timestamptz NOT NULL DEFAULT now(),
270
+ CONSTRAINT client_fiscal_credential_tenant_id_uq UNIQUE (tenant_id, id),
271
+ FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
272
+ -- `verified` sem data de verificação é uma afirmação sem prova.
273
+ CONSTRAINT client_fiscal_credential_verified_coherent
274
+ CHECK (status <> 'verified' OR verified_at IS NOT NULL),
275
+ -- Referência do cofre, jamais material. Um `-----BEGIN` aqui é acidente
276
+ -- grave; o banco recusa antes de virar um vazamento em backup.
277
+ CONSTRAINT client_fiscal_credential_ref_is_reference
278
+ CHECK (secret_ref IS NULL OR secret_ref ~ '^vault://[A-Za-z0-9_.:-]+$')
279
+ );
280
+
281
+ CREATE UNIQUE INDEX IF NOT EXISTS client_fiscal_credential_uq
282
+ ON client_fiscal_credential (tenant_id, client_id, kind);
283
+
284
+ ALTER TABLE client_fiscal_credential ENABLE ROW LEVEL SECURITY;
285
+ ALTER TABLE client_fiscal_credential FORCE ROW LEVEL SECURITY;
286
+ CREATE POLICY client_fiscal_credential_tenant_isolation ON client_fiscal_credential
287
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
288
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
289
+
290
+ COMMENT ON COLUMN client_fiscal_credential.secret_ref IS
291
+ 'Referência do cofre (vault://…). NUNCA o certificado nem a senha dele — o material é do cliente e não passa por aqui.';
292
+
293
+ -- ── 5 · Nenhum cliente existente nasce elegível ────────────────────────────
294
+ --
295
+ -- Não há UPDATE, INSERT ou backfill nesta migration que torne alguém elegível.
296
+ -- É a afirmação central do gate e ela é verificável: as três tabelas acima
297
+ -- nascem VAZIAS, e vazio significa negado nas três camadas.
298
+ --
299
+ -- Vale para os 13 registros da SC e para os tenants sintéticos de certificação
300
+ -- pelo mesmo motivo — nenhum deles é mencionado, então nenhum deles é ligado.