@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,321 @@
1
+ -- 0060 — o cofre fiscal ganha classe de exposição, o certificado ganha
2
+ -- identidade, e a primeira consulta real ganha um portão que se consome.
3
+ --
4
+ -- ═══ O defeito que a primeira seção existe para tornar indizível ══════════
5
+ --
6
+ -- `vault_credential` (0012) guarda todo segredo do escritório sob uma única
7
+ -- regra de leitura: quem tem `vault.credential.decrypt` chama
8
+ -- `POST /v1/vault/credentials/:id/reveal` e recebe o texto em claro. Para uma
9
+ -- chave de API isso é o comportamento desejado — o operador precisa colá-la
10
+ -- noutro sistema.
11
+ --
12
+ -- Para o material de um certificado digital, é a porta dos fundos do cofre. O
13
+ -- envelope que a Fase 2 definiu carrega a CHAVE PRIVADA do cliente em base64;
14
+ -- revelá-lo numa tela é entregá-la, e "não faça isso" não é um controle. Pior:
15
+ -- o papel `accountant` do catálogo já carrega `vault.credential.decrypt`, de
16
+ -- modo que a porta estava aberta para todo contador do escritório.
17
+ --
18
+ -- A correção não é tirar o botão da tela. É dizer no BANCO que existem duas
19
+ -- classes de segredo, e que a segunda não tem caminho de saída:
20
+ --
21
+ -- revealable pode voltar ao humano que o guardou (chave de API, token).
22
+ -- write_only entra, é usado pelo processo, e NUNCA volta.
23
+ --
24
+ -- E é uma RESTRIÇÃO, não uma convenção, que amarra `certificate` à segunda: um
25
+ -- certificado gravado por qualquer caminho — rota nova, script, seed — nasce
26
+ -- irrecuperável, inclusive num caminho que ainda não foi escrito.
27
+
28
+ ALTER TABLE vault_credential ADD COLUMN IF NOT EXISTS exposure text NOT NULL DEFAULT 'revealable';
29
+
30
+ DO $$
31
+ BEGIN
32
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'vault_credential_exposure_values') THEN
33
+ ALTER TABLE vault_credential ADD CONSTRAINT vault_credential_exposure_values
34
+ CHECK (exposure IN ('revealable', 'write_only'));
35
+ END IF;
36
+ END $$;
37
+
38
+ -- Backfill ANTES da restrição de coerência: uma credencial de certificado já
39
+ -- gravada sob a regra antiga tornaria o CHECK inválido, e um `NOT VALID`
40
+ -- silencioso deixaria exatamente as linhas antigas — as que já correram risco —
41
+ -- fora da garantia.
42
+ UPDATE vault_credential SET exposure = 'write_only'
43
+ WHERE category = 'certificate' AND exposure <> 'write_only';
44
+
45
+ DO $$
46
+ BEGIN
47
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'vault_credential_certificate_is_write_only') THEN
48
+ ALTER TABLE vault_credential ADD CONSTRAINT vault_credential_certificate_is_write_only
49
+ CHECK (category <> 'certificate' OR exposure = 'write_only');
50
+ END IF;
51
+ END $$;
52
+
53
+ COMMENT ON COLUMN vault_credential.exposure IS
54
+ 'write_only = não existe caminho de leitura para humano, por nenhuma rota. Material de certificado é write_only por RESTRIÇÃO, não por disciplina da camada de rota.';
55
+ COMMENT ON CONSTRAINT vault_credential_certificate_is_write_only ON vault_credential IS
56
+ 'Remover esta restrição é a decisão consciente de permitir que a chave privada de um cliente volte para uma tela.';
57
+
58
+ -- ═══ 2 · A autorização de execução única ═════════════════════════════════
59
+ --
60
+ -- O motor da Fase 2 tem três desligamentos (flag de ambiente, elegibilidade,
61
+ -- cadência) e todos são ESTADO: ligados, ficam ligados. Para a primeira
62
+ -- consulta real contra um ambiente oficial, em nome de um contribuinte que não
63
+ -- pediu nada, estado permanente é a forma errada de autorização — o titular
64
+ -- autorizou UMA leitura, não um regime.
65
+ --
66
+ -- Esta tabela é um portão que se gasta. Quatro propriedades, todas no schema:
67
+ --
68
+ -- `max_runs = 1` CHECK literal. "Uma execução" não é configuração.
69
+ -- `operation = 'READ_ONLY'` idem. Mutação é INGRAVÁVEL nesta fase.
70
+ -- `expires_at` uma autorização esquecida morre sozinha.
71
+ -- `runs_consumed` nunca ultrapassa `max_runs`, e o CHECK é quem diz.
72
+ --
73
+ -- O período vem por EXTENSO — `period_start` e `period_end` além do par
74
+ -- ano/mês. O relato humano que originou esta frente continha exemplos de datas
75
+ -- inconsistentes entre si, e transformar "mês anterior" em regra implícita
76
+ -- produziria uma coleta cuja janela ninguém confirmou. Aqui a janela é dado
77
+ -- gravado, e a tela mostra as duas datas antes de qualquer execução.
78
+ CREATE TABLE IF NOT EXISTS fiscal_run_authorization (
79
+ id uuid PRIMARY KEY,
80
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
81
+ client_id uuid NOT NULL,
82
+
83
+ document_type text NOT NULL CHECK (document_type IN ('nfse', 'nfe', 'cte', 'nfce')),
84
+ environment text NOT NULL CHECK (environment IN ('synthetic', 'homologation', 'production')),
85
+ -- Slug da fonte, o mesmo vocabulário que governa cursor, disjuntor e
86
+ -- prontidão (`fiscal_sync_cursor.source`). Uma autorização emitida para uma
87
+ -- fonte não vale para outra.
88
+ source text NOT NULL,
89
+ credential_kind text NOT NULL DEFAULT 'certificate_a1'
90
+ CHECK (credential_kind IN ('certificate_a1', 'certificate_a3', 'municipal_portal')),
91
+
92
+ operation text NOT NULL DEFAULT 'READ_ONLY' CHECK (operation IN ('READ_ONLY', 'MUTATING')),
93
+
94
+ competence_year int NOT NULL CHECK (competence_year BETWEEN 2000 AND 2100),
95
+ competence_month int NOT NULL CHECK (competence_month BETWEEN 1 AND 12),
96
+ period_start date NOT NULL,
97
+ period_end date NOT NULL,
98
+
99
+ max_runs int NOT NULL DEFAULT 1,
100
+ runs_consumed int NOT NULL DEFAULT 0,
101
+
102
+ authorized_by uuid NOT NULL REFERENCES "user"(id),
103
+ authorized_at timestamptz NOT NULL DEFAULT now(),
104
+ -- Responsável contábil DECLARADO para esta execução. Texto, e não FK para
105
+ -- `user`: o profissional responsável pode não ter login no produto, e exigir
106
+ -- que tivesse forçaria a criação de uma identidade que ninguém pediu.
107
+ responsible_name text,
108
+ expires_at timestamptz NOT NULL,
109
+
110
+ consumed_at timestamptz,
111
+ consumed_by_run_id uuid,
112
+ revoked_at timestamptz,
113
+ revoked_by uuid REFERENCES "user"(id),
114
+ revoke_reason text,
115
+
116
+ created_at timestamptz NOT NULL DEFAULT now(),
117
+ updated_at timestamptz NOT NULL DEFAULT now(),
118
+
119
+ CONSTRAINT fiscal_run_authorization_tenant_id_uq UNIQUE (tenant_id, id),
120
+ FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
121
+
122
+ CONSTRAINT fiscal_run_authorization_one_shot CHECK (max_runs = 1),
123
+ CONSTRAINT fiscal_run_authorization_read_only CHECK (operation = 'READ_ONLY'),
124
+ CONSTRAINT fiscal_run_authorization_budget CHECK (runs_consumed >= 0 AND runs_consumed <= max_runs),
125
+ CONSTRAINT fiscal_run_authorization_consumption_coherent
126
+ CHECK ((consumed_at IS NULL) = (runs_consumed = 0)),
127
+ CONSTRAINT fiscal_run_authorization_window CHECK (period_end >= period_start),
128
+ CONSTRAINT fiscal_run_authorization_expiry CHECK (expires_at > authorized_at),
129
+ CONSTRAINT fiscal_run_authorization_revocation_coherent
130
+ CHECK ((revoked_at IS NULL) = (revoked_by IS NULL))
131
+ );
132
+
133
+ COMMENT ON CONSTRAINT fiscal_run_authorization_one_shot ON fiscal_run_authorization IS
134
+ 'Uma execução. Não é configuração: é restrição. Um segundo run real exige uma segunda autorização.';
135
+ COMMENT ON CONSTRAINT fiscal_run_authorization_read_only ON fiscal_run_authorization IS
136
+ 'Mutação em sistema fiscal externo é ingravável nesta fase. Remover esta restrição é a decisão consciente de permitir escrita.';
137
+
138
+ -- Uma autorização VIVA por (cliente, fonte, ambiente, competência). Sem isto,
139
+ -- emitir duas e consumir as duas devolve na prática o regime permanente que a
140
+ -- tabela existe para impedir.
141
+ CREATE UNIQUE INDEX IF NOT EXISTS fiscal_run_authorization_live_uq
142
+ ON fiscal_run_authorization (tenant_id, client_id, source, environment,
143
+ competence_year, competence_month)
144
+ WHERE consumed_at IS NULL AND revoked_at IS NULL;
145
+
146
+ CREATE INDEX IF NOT EXISTS fiscal_run_authorization_client_idx
147
+ ON fiscal_run_authorization (tenant_id, client_id, authorized_at DESC);
148
+
149
+ ALTER TABLE fiscal_run_authorization ENABLE ROW LEVEL SECURITY;
150
+ ALTER TABLE fiscal_run_authorization FORCE ROW LEVEL SECURITY;
151
+ CREATE POLICY fiscal_run_authorization_tenant_isolation ON fiscal_run_authorization
152
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
153
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
154
+
155
+ -- ═══ 3 · A cobrança da PLATAFORMA, separada da cobrança do escritório ═════
156
+ --
157
+ -- Há duas cobranças neste produto e confundi-las custa caro nas duas direções:
158
+ --
159
+ -- plataforma Baruk → escritório (assinatura do Office). `saas_subscription`.
160
+ -- escritório escritório → clientes dele (honorários). `receivable`.
161
+ --
162
+ -- O escritório fundador não paga a primeira. A forma ERRADA de implementar isso
163
+ -- é desligar o financeiro dele — que apagaria a segunda, que é o produto
164
+ -- inteiro. A forma errada seguinte é `if (tenant.code === 'sc')`, que faz o
165
+ -- segundo escritório fundador virar um deploy.
166
+ --
167
+ -- Esta tabela é a forma certa: um fato do tenant, com quem concedeu, quando, e
168
+ -- por quê. O motor de billing lê a linha; ele não conhece nenhum código de
169
+ -- escritório.
170
+ --
171
+ -- ═══ Quem escreve não é quem é cobrado ═══════════════════════════════════
172
+ --
173
+ -- Um controle escrito pelo controlado não é controle. Se o tenant pudesse
174
+ -- gravar a própria isenção, todo escritório seria fundador na primeira tarde.
175
+ -- As políticas abaixo são POR COMANDO: o tenant LÊ a própria linha; só o
176
+ -- operador da plataforma (a GUC `app.platform_operator`, que apenas as rotas de
177
+ -- backoffice setam) INSERE, ATUALIZA ou APAGA.
178
+ CREATE TABLE IF NOT EXISTS tenant_platform_billing (
179
+ tenant_id uuid PRIMARY KEY REFERENCES tenant(id),
180
+ billing_mode text NOT NULL DEFAULT 'standard' CHECK (billing_mode IN ('standard', 'exempt')),
181
+ exemption_reason text CHECK (exemption_reason IS NULL OR
182
+ exemption_reason IN ('founding_tenant', 'internal', 'partner')),
183
+ founding_tenant boolean NOT NULL DEFAULT false,
184
+ granted_by uuid REFERENCES "user"(id),
185
+ granted_at timestamptz,
186
+ -- Isenção com prazo é possível; a do fundador não tem, e `NULL` diz isso.
187
+ expires_on date,
188
+ notes text,
189
+ created_at timestamptz NOT NULL DEFAULT now(),
190
+ updated_at timestamptz NOT NULL DEFAULT now(),
191
+
192
+ -- Isentar custa motivo e data. `standard` é o estado gratuito — e o correto
193
+ -- para todo tenant sobre o qual ninguém decidiu nada.
194
+ CONSTRAINT tenant_platform_billing_exemption_needs_reason
195
+ CHECK (billing_mode = 'standard' OR (exemption_reason IS NOT NULL AND granted_at IS NOT NULL))
196
+ );
197
+
198
+ COMMENT ON TABLE tenant_platform_billing IS
199
+ 'Cobrança da PLATAFORMA (Baruk → escritório). Não governa a cobrança do escritório aos clientes dele, que é outro domínio e continua ativa.';
200
+ COMMENT ON CONSTRAINT tenant_platform_billing_exemption_needs_reason ON tenant_platform_billing IS
201
+ 'Isentar exige motivo e data. Ausência de linha significa cobrança padrão, nunca isenção por omissão.';
202
+
203
+ ALTER TABLE tenant_platform_billing ENABLE ROW LEVEL SECURITY;
204
+ ALTER TABLE tenant_platform_billing FORCE ROW LEVEL SECURITY;
205
+
206
+ -- Leitura: o próprio tenant, ou o operador.
207
+ CREATE POLICY tenant_platform_billing_read ON tenant_platform_billing
208
+ FOR SELECT
209
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid
210
+ OR current_setting('app.platform_operator', true) = 'true');
211
+
212
+ -- Escrita: SÓ o operador. Uma política por comando — `WITH CHECK` não governa
213
+ -- DELETE, e uma política única deixaria o apagamento da própria isenção (ou da
214
+ -- de outro) fora de qualquer regra.
215
+ CREATE POLICY tenant_platform_billing_insert ON tenant_platform_billing
216
+ FOR INSERT WITH CHECK (current_setting('app.platform_operator', true) = 'true');
217
+ CREATE POLICY tenant_platform_billing_update ON tenant_platform_billing
218
+ FOR UPDATE
219
+ USING (current_setting('app.platform_operator', true) = 'true')
220
+ WITH CHECK (current_setting('app.platform_operator', true) = 'true');
221
+ CREATE POLICY tenant_platform_billing_delete ON tenant_platform_billing
222
+ FOR DELETE USING (current_setting('app.platform_operator', true) = 'true');
223
+
224
+ -- ═══ 4 · O registry municipal deixa de responder só "não sabemos" ════════
225
+ --
226
+ -- `fiscal_coverage` (0058) já traz status, método, credencial exigida, fallback,
227
+ -- fonte e data. Faltavam duas respostas que a política API-first exige ANTES de
228
+ -- alguém cogitar automação de navegador:
229
+ --
230
+ -- `official_api_available` existe caminho estruturado oficial?
231
+ -- `supported_operations` o que ele faz — listar, baixar, consultar evento?
232
+ --
233
+ -- Sem a primeira, "não achei API" e "não procurei" são o mesmo registro, e o
234
+ -- segundo é o que costuma virar um Playwright logando num portal de prefeitura.
235
+ ALTER TABLE fiscal_coverage ADD COLUMN IF NOT EXISTS official_api_available text NOT NULL DEFAULT 'unknown';
236
+ ALTER TABLE fiscal_coverage ADD COLUMN IF NOT EXISTS supported_operations text[] NOT NULL DEFAULT '{}';
237
+
238
+ DO $$
239
+ BEGIN
240
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'fiscal_coverage_official_api_values') THEN
241
+ ALTER TABLE fiscal_coverage ADD CONSTRAINT fiscal_coverage_official_api_values
242
+ CHECK (official_api_available IN ('yes', 'no', 'unknown'));
243
+ END IF;
244
+ END $$;
245
+
246
+ COMMENT ON COLUMN fiscal_coverage.official_api_available IS
247
+ '"no" é uma medição; "unknown" é a ausência dela. Só a primeira autoriza sequer discutir fallback por navegador.';
248
+
249
+ -- ═══ Backfill: as linhas que já afirmavam cobertura ══════════════════════
250
+ --
251
+ -- A 0058 criou quatro linhas `SUPPORTED_OFFICIAL` — NF-e, CT-e e NFS-e nacional
252
+ -- —, todas com a norma citada em `source_reference`. Com a coluna nova nascendo
253
+ -- `unknown`, elas passariam a AFIRMAR cobertura sem ter respondido "existe
254
+ -- caminho oficial?", que é justamente a pergunta que a coluna existe para fazer.
255
+ --
256
+ -- Uma coluna nova sem backfill deixa de fora exatamente as linhas antigas — as
257
+ -- que já estavam em uso. O mesmo raciocínio do `exposure` acima.
258
+ UPDATE fiscal_coverage SET
259
+ official_api_available = 'yes',
260
+ supported_operations = CASE
261
+ WHEN automation_method = 'dfe_nsu_soap' THEN ARRAY['dist_nsu', 'cons_nsu', 'cons_chave']
262
+ WHEN automation_method = 'dfe_nsu_rest' THEN ARRAY['list_by_nsu', 'fetch_document', 'fetch_events']
263
+ ELSE supported_operations
264
+ END
265
+ WHERE coverage_status LIKE 'SUPPORTED%'
266
+ AND official_api_available = 'unknown'
267
+ AND automation_method IN ('dfe_nsu_soap', 'dfe_nsu_rest');
268
+
269
+ -- As linhas dos três municípios do piloto. `SUPPORTED_OFFICIAL` aqui significa
270
+ -- o que já significava na linha nacional do ADN: existe caminho oficial
271
+ -- documentado — e não "já funcionou". Quem responde "já funcionou" é
272
+ -- `digital_certificate.verified_at` somado a um `fiscal_sync_run` completo, e
273
+ -- ambos continuam vazios.
274
+ INSERT INTO fiscal_coverage (
275
+ id, document_type, jurisdiction_scope, jurisdiction_code, provider, coverage_status,
276
+ automation_method, credential_requirement, environments, fallback_type,
277
+ official_api_available, supported_operations,
278
+ last_verified_at, source_reference, notes
279
+ ) VALUES
280
+ (gen_random_uuid(), 'nfse', 'municipal', '5208707', 'nfse_adn', 'SUPPORTED_OFFICIAL',
281
+ 'dfe_nsu_rest', 'icp_brasil_mtls', ARRAY['homologation', 'production'], 'manual_upload',
282
+ 'yes', ARRAY['list_by_nsu', 'fetch_document', 'fetch_events'],
283
+ DATE '2026-09-08',
284
+ 'Prefeitura de Goiânia — comunicado oficial de ajuste da NFS-e à Reforma Tributária (vigência 01/01/2026); LC 214/2025 art. 62; Manual dos Contribuintes — APIs do ADN v1.0',
285
+ 'Goiânia MANTÉM emissor próprio (Sistema ISS Goiânia, provedor ISSNet) e o compartilhamento com o ADN é feito pela própria administração tributária. Logo o caminho de COLETA é o ADN nacional, por certificado — não o portal municipal. Nenhuma chamada autenticada foi feita a partir deste produto.'),
286
+
287
+ (gen_random_uuid(), 'nfse', 'municipal', '5201405', 'nfse_adn', 'SUPPORTED_OFFICIAL',
288
+ 'dfe_nsu_rest', 'icp_brasil_mtls', ARRAY['homologation', 'production'], 'manual_upload',
289
+ 'yes', ARRAY['list_by_nsu', 'fetch_document', 'fetch_events'],
290
+ DATE '2026-09-08',
291
+ 'Portal oficial da Prefeitura de Aparecida de Goiânia (sistema NFS-e em issnetonline.com.br/aparecida); LC 214/2025 art. 62; Manual dos Contribuintes — APIs do ADN v1.0',
292
+ 'Emissor municipal é ISSNet (mesmo provedor de Goiânia e Anápolis). Nenhuma API pública do ISSNet foi verificada; a via oficial de coleta é o ADN. Adesão específica do município ao compartilhamento NÃO foi confirmada em fonte municipal — apenas pela obrigação legal geral.'),
293
+
294
+ (gen_random_uuid(), 'nfse', 'municipal', '5201108', 'nfse_adn', 'SUPPORTED_OFFICIAL',
295
+ 'dfe_nsu_rest', 'icp_brasil_mtls', ARRAY['homologation', 'production'], 'manual_upload',
296
+ 'yes', ARRAY['list_by_nsu', 'fetch_document', 'fetch_events'],
297
+ DATE '2026-09-08',
298
+ 'Prefeitura de Anápolis — Decreto nº 52.525 (03/03/2026, efeitos retroativos a 01/01/2026); LC 214/2025 art. 62; Manual dos Contribuintes — APIs do ADN v1.0',
299
+ 'Anápolis mantém emissor municipal próprio (ISS.NET) com webservice local; o comunicado NÃO menciona o ADN. Simples Nacional migra ao emissor nacional a partir de 01/11/2026. A coleta pelo ADN depende do compartilhamento obrigatório, que este produto não verificou.'),
300
+
301
+ -- Estadual GO. A pergunta humana era "notas de entrada e saída"; a resposta
302
+ -- oficial separa as duas, e é essa separação que decide se um conector novo é
303
+ -- necessário — ou se o que falta não tem conector nenhum.
304
+ (gen_random_uuid(), 'nfe', 'state', 'GO', 'sefaz_dfe', 'SUPPORTED_OFFICIAL',
305
+ 'dfe_nsu_soap', 'icp_brasil_mtls', ARRAY['homologation', 'production'], 'issuer_export',
306
+ 'yes', ARRAY['dist_nsu', 'cons_nsu', 'cons_chave'],
307
+ DATE '2026-09-08',
308
+ 'Secretaria da Economia de Goiás — Documentos Fiscais (nfeweb.sefaz.go.gov.br, arquivo XML por certificado digital); NT 2014.002 v1.02c',
309
+ 'ENTRADAS: cobertas pela distribuição nacional NFeDistribuicaoDFe, autenticada por certificado ICP-Brasil — nenhuma credencial humana. SAÍDAS: o DF-e não distribui o que a própria empresa emitiu; a origem é o emissor do cliente. O login CPF/senha do portal da SEFAZ-GO NÃO é caminho de coleta estruturada e por isso não é modelado como credencial deste produto.')
310
+ ON CONFLICT DO NOTHING;
311
+
312
+ -- ═══ 5 · A capacidade ════════════════════════════════════════════════════
313
+ --
314
+ -- Chave NOVA, e não bump de `contract_version` — a versão do contrato é global
315
+ -- (0055) e subi-la para exigir schema novo obrigaria todo worker a reconhecer a
316
+ -- versão maior, inclusive os que nada têm a ver com cofre fiscal.
317
+ INSERT INTO platform_capability (key, label, contract_version, declared_by_migration) VALUES
318
+ ('office.fiscal-credential-vault.v1',
319
+ 'Cofre fiscal: certificado write-only, identidade conferida e autorização de execução única',
320
+ 1, '0060')
321
+ ON CONFLICT (key) DO NOTHING;
@@ -0,0 +1,193 @@
1
+ -- 0061 — de onde veio cada dado cadastral, e quem mandou nele.
2
+ --
3
+ -- ═══ O defeito que a proveniência existe para tornar indizível ═════════════
4
+ --
5
+ -- Sem ela, um cadastro pré-preenchido por fonte oficial e um cadastro digitado
6
+ -- à mão são a MESMA linha. E aí duas coisas ficam impossíveis:
7
+ --
8
+ -- 1. atualizar sem destruir. Uma segunda consulta traria o valor oficial, e
9
+ -- sobrescrever apagaria a correção que uma pessoa fez de propósito — o
10
+ -- telefone que o escritório sabe estar certo, o e-mail que mudou e a
11
+ -- Receita ainda não sabe.
12
+ -- 2. explicar. "Por que o município deste cliente é Goiânia?" tem respostas
13
+ -- diferentes conforme alguém tenha digitado ou a Receita tenha dito, e a
14
+ -- diferença decide quanto se confia no dado.
15
+ --
16
+ -- A tabela guarda o retrato OFICIAL, ao lado do cadastro — nunca por cima dele.
17
+ -- O cadastro continua sendo o que o escritório afirma; esta linha é o que a
18
+ -- fonte disse, quando disse, e por qual provedor.
19
+ --
20
+ -- ═══ Por que uma tabela, e não colunas em `client` ════════════════════════
21
+ --
22
+ -- Colunas `*_source` em `client` dobrariam a largura da tabela e ainda assim não
23
+ -- guardariam o valor oficial DIVERGENTE — só a etiqueta. É justamente o valor
24
+ -- divergente que a tela de conferência precisa mostrar lado a lado.
25
+
26
+ CREATE TABLE IF NOT EXISTS client_registry_snapshot (
27
+ id uuid PRIMARY KEY,
28
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
29
+ client_id uuid NOT NULL,
30
+
31
+ -- Quem respondeu, e se é fonte oficial. `official = false` NÃO é proibido —
32
+ -- é o que permite registrar um provedor de teste sem que ele se disfarce de
33
+ -- Receita Federal na trilha.
34
+ provider text NOT NULL,
35
+ provider_official boolean NOT NULL DEFAULT false,
36
+ fetched_at timestamptz NOT NULL DEFAULT now(),
37
+
38
+ -- O documento consultado, em dígitos. Guardado aqui porque o `client` pode ser
39
+ -- corrigido depois, e o retrato tem de dizer sobre QUAL número ele fala.
40
+ document_digits text NOT NULL CHECK (document_digits ~ '^[0-9]{14}$'),
41
+
42
+ -- O retrato normalizado. Todo campo é opcional: toda fonte tem lacuna, e uma
43
+ -- lacuna precisa ser dizível como ausência — não como string vazia.
44
+ legal_name text,
45
+ trade_name text,
46
+ registration_status text,
47
+ opened_on date,
48
+ legal_nature text,
49
+ company_size text,
50
+ primary_activity_code text,
51
+ primary_activity_text text,
52
+ secondary_activities jsonb NOT NULL DEFAULT '[]'::jsonb,
53
+ street text,
54
+ street_number text,
55
+ complement text,
56
+ district text,
57
+ postal_code text,
58
+ municipality text,
59
+ state_uf text,
60
+ phone text,
61
+ email text,
62
+ share_capital_cents bigint,
63
+
64
+ -- ═══ O silêncio da fonte NÃO é "não" ════════════════════════════════════
65
+ -- `NULL` aqui significa "a fonte não informou", e é diferente de `false`.
66
+ -- Colapsar os dois é como um optante do Simples vira Lucro Presumido por
67
+ -- omissão — e o regime decide quais obrigações o motor aplica.
68
+ simples_optant boolean,
69
+ mei_optant boolean,
70
+
71
+ created_at timestamptz NOT NULL DEFAULT now(),
72
+
73
+ CONSTRAINT client_registry_snapshot_tenant_id_uq UNIQUE (tenant_id, id),
74
+ FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id)
75
+ );
76
+
77
+ COMMENT ON COLUMN client_registry_snapshot.simples_optant IS
78
+ 'NULL = a fonte não informou. NÃO é false. O regime tributário depende disso, e silêncio não é negativa.';
79
+
80
+ -- Um retrato por (cliente, provedor, momento). O índice serve à pergunta real:
81
+ -- "qual foi o último retrato deste cliente?".
82
+ CREATE INDEX IF NOT EXISTS client_registry_snapshot_latest_idx
83
+ ON client_registry_snapshot (tenant_id, client_id, fetched_at DESC);
84
+
85
+ ALTER TABLE client_registry_snapshot ENABLE ROW LEVEL SECURITY;
86
+ ALTER TABLE client_registry_snapshot FORCE ROW LEVEL SECURITY;
87
+ CREATE POLICY client_registry_snapshot_tenant_isolation ON client_registry_snapshot
88
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
89
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
90
+
91
+ -- ═══ A etiqueta por ATRIBUTO ══════════════════════════════════════════════
92
+ --
93
+ -- O retrato acima diz o que a fonte falou. Esta tabela diz o que aconteceu com
94
+ -- cada campo DO CADASTRO: veio da fonte, ou uma pessoa o escreveu?
95
+ --
96
+ -- É ela que faz `HUMAN_OVERRIDE_PRESERVED` ser verificável: um campo marcado
97
+ -- `human` nunca é sobrescrito por atualização automática, e isso é uma consulta
98
+ -- — não uma convenção que alguém precisa lembrar.
99
+ CREATE TABLE IF NOT EXISTS client_field_provenance (
100
+ id uuid PRIMARY KEY,
101
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
102
+ client_id uuid NOT NULL,
103
+ field text NOT NULL,
104
+ origin text NOT NULL CHECK (origin IN ('official_lookup', 'human', 'import')),
105
+ provider text,
106
+ verified_at timestamptz,
107
+ updated_at timestamptz NOT NULL DEFAULT now(),
108
+ updated_by uuid REFERENCES "user"(id),
109
+
110
+ CONSTRAINT client_field_provenance_tenant_id_uq UNIQUE (tenant_id, id),
111
+ FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
112
+ -- Origem oficial sem provedor é afirmação sem autor.
113
+ CONSTRAINT client_field_provenance_official_needs_provider
114
+ CHECK (origin <> 'official_lookup' OR (provider IS NOT NULL AND verified_at IS NOT NULL))
115
+ );
116
+
117
+ CREATE UNIQUE INDEX IF NOT EXISTS client_field_provenance_uq
118
+ ON client_field_provenance (tenant_id, client_id, field);
119
+
120
+ ALTER TABLE client_field_provenance ENABLE ROW LEVEL SECURITY;
121
+ ALTER TABLE client_field_provenance FORCE ROW LEVEL SECURITY;
122
+ CREATE POLICY client_field_provenance_tenant_isolation ON client_field_provenance
123
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
124
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
125
+
126
+ -- ═══ O nome fantasia ══════════════════════════════════════════════════════
127
+ --
128
+ -- `client` guarda `display_name` e `legal_name`, e não tinha onde pôr o nome
129
+ -- fantasia — que é o que a fonte oficial devolve e o que a equipe usa para
130
+ -- falar do cliente ("HIPER FESTA", não "OLIVEIRA PRODUTOS PARA FESTAS LTDA").
131
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS trade_name text;
132
+
133
+ COMMENT ON COLUMN client.trade_name IS
134
+ 'Nome fantasia. Distinto de display_name (como o escritório chama) e de legal_name (razão social).';
135
+
136
+ INSERT INTO platform_capability (key, label, contract_version, declared_by_migration) VALUES
137
+ ('office.client-registry-provenance.v1',
138
+ 'Retrato de fonte oficial e proveniência por atributo do cadastro do cliente',
139
+ 1, '0061')
140
+ ON CONFLICT (key) DO NOTHING;
141
+
142
+ -- ═══ A consulta em si — cota, cache e trilha na MESMA linha ═══════════════
143
+ --
144
+ -- Esta tabela existe por três perguntas que não têm outra fonte:
145
+ --
146
+ -- 1. **quantas consultas este escritório já fez na janela?** Sem contagem
147
+ -- persistente, um contador em memória zera a cada redeploy e some quando
148
+ -- há duas instâncias — que é exatamente quando o limite importa.
149
+ -- 2. **já perguntamos este CNPJ há pouco?** Uma segunda consulta idêntica em
150
+ -- cinco minutos gasta cota de um contrato pago para reobter o que já se
151
+ -- sabe. O `payload` é o cache; o TTL vive no código.
152
+ -- 3. **quem perguntou por qual empresa?** Consulta de CNPJ é rastreável por
153
+ -- dever próprio: é a pergunta "esse escritório andou varrendo documentos?".
154
+ --
155
+ -- **Sem FK para `client`, e é de propósito.** A consulta acontece ANTES de o
156
+ -- cliente existir — o operador digita o CNPJ numa tela de cadastro vazia. Uma FK
157
+ -- aqui tornaria impossível registrar justamente a consulta mais comum.
158
+ CREATE TABLE IF NOT EXISTS client_registry_lookup (
159
+ id uuid PRIMARY KEY,
160
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
161
+ document_digits text NOT NULL CHECK (document_digits ~ '^[0-9]{14}$'),
162
+ provider text NOT NULL,
163
+ outcome text NOT NULL CHECK (outcome IN ('ok', 'failed')),
164
+ -- O motivo da recusa, quando houve. Vocabulário fechado no código
165
+ -- (`CompanyLookupFailure`); aqui fica aberto para não travar a migration num
166
+ -- vocabulário que ainda vai crescer com o primeiro provedor real.
167
+ failure_reason text,
168
+ -- O retrato devolvido, quando houve. É o cache: uma repetição dentro do TTL
169
+ -- é respondida daqui sem tocar a rede. NULL em toda linha `failed` — falha
170
+ -- não se cacheia, senão uma indisponibilidade de um minuto ficaria colada
171
+ -- no CNPJ pelo resto do TTL.
172
+ payload jsonb,
173
+ requested_by uuid REFERENCES "user"(id),
174
+ created_at timestamptz NOT NULL DEFAULT now(),
175
+
176
+ CONSTRAINT client_registry_lookup_tenant_id_uq UNIQUE (tenant_id, id),
177
+ CONSTRAINT client_registry_lookup_failure_has_no_payload
178
+ CHECK (outcome = 'ok' OR payload IS NULL)
179
+ );
180
+
181
+ -- A cota pergunta "quantas linhas deste tenant desde X"; o cache pergunta
182
+ -- "qual a última linha `ok` deste documento". Um índice serve às duas.
183
+ CREATE INDEX IF NOT EXISTS client_registry_lookup_quota_idx
184
+ ON client_registry_lookup (tenant_id, created_at DESC);
185
+ CREATE INDEX IF NOT EXISTS client_registry_lookup_cache_idx
186
+ ON client_registry_lookup (tenant_id, document_digits, created_at DESC)
187
+ WHERE outcome = 'ok';
188
+
189
+ ALTER TABLE client_registry_lookup ENABLE ROW LEVEL SECURITY;
190
+ ALTER TABLE client_registry_lookup FORCE ROW LEVEL SECURITY;
191
+ CREATE POLICY client_registry_lookup_tenant_isolation ON client_registry_lookup
192
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
193
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
@@ -0,0 +1,119 @@
1
+ -- 0062 — o primeiro contato, e a diferença entre "existe" e "nós fizemos".
2
+ --
3
+ -- ═══ Dois defeitos, e por que eles são o mesmo defeito ════════════════════
4
+ --
5
+ -- **1. O impasse.** A execução exigia `verified_at`; `verified_at` significa "o
6
+ -- ambiente oficial já aceitou"; e só uma execução produz esse aceite. A primeira
7
+ -- consulta real era inalcançável por construção — não por configuração, não por
8
+ -- falta de certificado. A auditoria da C2 encontrou o ciclo fechado.
9
+ --
10
+ -- **2. A cobertura mentindo por omissão.** `coverage_status = 'SUPPORTED_OFFICIAL'`
11
+ -- responde "a norma oferece um caminho oficial?". A tela mostrava isso ao lado do
12
+ -- botão de autorizar, e o operador lia "o Baruk já fala com esse serviço". Para
13
+ -- `sefaz_dfe` isso era falso: não existe adaptador, só a string do conector.
14
+ --
15
+ -- Os dois são a mesma confusão — **tratar o que o mundo oferece como o que este
16
+ -- produto construiu**. A correção é a mesma nos dois: separar os fatos em
17
+ -- colunas próprias e obrigar cada portão a citar a sua.
18
+
19
+ -- ═══ 1 · A verdade da capacidade, por camada ══════════════════════════════
20
+ --
21
+ -- `official_api_available` já respondia "existe API oficial?". Faltavam as duas
22
+ -- perguntas seguintes, e é a ausência delas que produzia a leitura errada.
23
+ ALTER TABLE fiscal_coverage
24
+ ADD COLUMN IF NOT EXISTS connector_implemented boolean NOT NULL DEFAULT false;
25
+ ALTER TABLE fiscal_coverage
26
+ ADD COLUMN IF NOT EXISTS protocol_verified boolean NOT NULL DEFAULT false;
27
+
28
+ COMMENT ON COLUMN fiscal_coverage.official_api_available IS
29
+ 'A NORMA oferece um caminho oficial? Fato do mundo, independente deste produto.';
30
+ COMMENT ON COLUMN fiscal_coverage.connector_implemented IS
31
+ 'ESTE produto tem adaptador para o caminho? Fato do repositório. `sefaz_dfe` era SUPPORTED_OFFICIAL sem uma linha de adaptador — foi o que esta coluna passou a tornar dizível.';
32
+ COMMENT ON COLUMN fiscal_coverage.protocol_verified IS
33
+ 'O envelope/contrato do serviço foi conferido contra o serviço REAL? Ler documentação não conta; para o ADN, os nomes dos campos do envelope não estão publicados em lugar acessível.';
34
+
35
+ -- Backfill explícito, e não default silencioso.
36
+ --
37
+ -- `DEFAULT false` deixaria toda linha existente afirmando "não implementado", o
38
+ -- que por acaso está certo para `sefaz_dfe` e errado para `nfse_adn`. Um acerto
39
+ -- por acaso é o que some no primeiro conector novo.
40
+ UPDATE fiscal_coverage SET connector_implemented = true
41
+ WHERE provider = 'nfse_adn';
42
+ UPDATE fiscal_coverage SET connector_implemented = false
43
+ WHERE provider = 'sefaz_dfe';
44
+ -- Nenhum conector tem o protocolo conferido contra o serviço real hoje. O do
45
+ -- ADN depende de um Swagger servido pelo próprio host que exige mTLS.
46
+ UPDATE fiscal_coverage SET protocol_verified = false;
47
+
48
+ -- ═══ 2 · A autorização passa a apontar para UM certificado ════════════════
49
+ --
50
+ -- Sem isto, trocar o certificado depois de autorizar mantinha a autorização de
51
+ -- pé — e a execução aconteceria com material que ninguém aprovou. O caso não é
52
+ -- teórico: substituir certificado é a operação normal quando um vence.
53
+ ALTER TABLE fiscal_run_authorization
54
+ ADD COLUMN IF NOT EXISTS credential_fingerprint text;
55
+
56
+ COMMENT ON COLUMN fiscal_run_authorization.credential_fingerprint IS
57
+ 'sha256 do DER do certificado vigente quando a autorização foi emitida. O executor recusa quando o certificado atual difere: autorizar é aprovar UM material, não uma intenção.';
58
+
59
+ -- ═══ 3 · O primeiro contato é um ATO, e ele tem registro próprio ══════════
60
+ --
61
+ -- Por que uma coluna e não um tipo de autorização separado: a autorização já é
62
+ -- one-shot, read-only, escopada e expirável. O primeiro contato não precisa de
63
+ -- outra tabela — precisa de uma DECLARAÇÃO de que quem autorizou sabia que a
64
+ -- credencial ainda não fora aceita por ninguém.
65
+ --
66
+ -- `false` como padrão importa: uma autorização comum continua exigindo
67
+ -- credencial verificada. Só quem marca este campo aceita o risco do bootstrap.
68
+ ALTER TABLE fiscal_run_authorization
69
+ ADD COLUMN IF NOT EXISTS first_contact boolean NOT NULL DEFAULT false;
70
+
71
+ COMMENT ON COLUMN fiscal_run_authorization.first_contact IS
72
+ 'Autorização de PRIMEIRO CONTATO: aceita credencial válida localmente e ainda não aceita por nenhum ambiente oficial. É o único caminho que resolve o impasse do verified_at, e nenhum agendador pode emiti-la.';
73
+
74
+ -- Quem executou, e por qual porta.
75
+ --
76
+ -- `manual` é o único valor que o primeiro contato admite, e o CHECK abaixo é
77
+ -- quem garante isso — não um `if` em TypeScript que alguém remove.
78
+ ALTER TABLE fiscal_run_authorization
79
+ ADD COLUMN IF NOT EXISTS trigger_kind text NOT NULL DEFAULT 'manual';
80
+
81
+ ALTER TABLE fiscal_run_authorization
82
+ DROP CONSTRAINT IF EXISTS fiscal_run_authorization_trigger_kind_check;
83
+ ALTER TABLE fiscal_run_authorization
84
+ ADD CONSTRAINT fiscal_run_authorization_trigger_kind_check
85
+ CHECK (trigger_kind IN ('manual', 'scheduled'));
86
+
87
+ -- ═══ O CHECK que impede o agendador de fazer o bootstrap ══════════════════
88
+ --
89
+ -- Está no banco, e não no orquestrador, porque a regra tem de sobreviver a um
90
+ -- refactor do orquestrador. Um cron que tentasse emitir autorização de primeiro
91
+ -- contato viola a linha abaixo e a transação morre.
92
+ ALTER TABLE fiscal_run_authorization
93
+ DROP CONSTRAINT IF EXISTS fiscal_run_authorization_first_contact_is_manual;
94
+ ALTER TABLE fiscal_run_authorization
95
+ ADD CONSTRAINT fiscal_run_authorization_first_contact_is_manual
96
+ CHECK (first_contact = false OR trigger_kind = 'manual');
97
+
98
+ COMMENT ON CONSTRAINT fiscal_run_authorization_first_contact_is_manual ON fiscal_run_authorization IS
99
+ 'Primeiro contato é ato de gente. Um agendador que o tentasse estaria decidindo, sozinho, gastar o certificado de um terceiro contra a Receita pela primeira vez.';
100
+
101
+ -- ═══ 4 · A habilitação fiscal do tenant, com granularidade ════════════════
102
+ --
103
+ -- `tenant_fiscal_automation` já existe (0058) e responde por MODO — qual
104
+ -- ambiente o escritório declarou operar. Ela continua sendo a chave-geral.
105
+ --
106
+ -- O que faltava era o outro lado do par: a matrícula POR CLIENTE já existia em
107
+ -- `client_fiscal_enrollment` (0058), também por `document_type`. Nada disso
108
+ -- precisa de tabela nova — precisa de superfície e de auditoria, que vêm no
109
+ -- código desta mesma frente.
110
+ --
111
+ -- Registrado aqui para quem ler a migration procurando as tabelas e não as
112
+ -- encontrar: elas existem desde a 0058, e esta frente as LIGA, não as cria.
113
+
114
+ -- ═══ 5 · A capacidade ═════════════════════════════════════════════════════
115
+ INSERT INTO platform_capability (key, label, contract_version, declared_by_migration) VALUES
116
+ ('office.fiscal-first-contact.v1',
117
+ 'Primeiro contato fiscal: autorização one-shot que aceita credencial válida só localmente',
118
+ 1, '0062')
119
+ ON CONFLICT (key) DO NOTHING;