@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,184 @@
1
+ -- 0046 — o modelo de dados que falta para ativar um cliente real.
2
+ --
3
+ -- A Fase 5 começou mapeando, contra o schema, exatamente quais dados um
4
+ -- escritório precisa para ativar um cliente. Quatro ausências apareceram, e
5
+ -- todas bloqueiam algo concreto do piloto:
6
+ --
7
+ -- 1. **Não há onde guardar município e UF.** Três obrigações do catálogo são
8
+ -- estaduais ou municipais e têm prazo que varia por localidade. Sem UF e
9
+ -- município no cliente, marcar essas obrigações como "depende da localidade"
10
+ -- é honesto mas inútil: não há o dado com que decidir.
11
+ --
12
+ -- 2. **Não há responsável pelo cliente.** `recurring_instance` e
13
+ -- `service_request` têm `responsible_user_id`; o cliente não tem. Então a
14
+ -- carteira não pode ser dividida entre as pessoas do escritório — só as
15
+ -- tarefas podem, uma a uma, depois de criadas.
16
+ --
17
+ -- 3. **A importação não deixa rastro reversível.** `commitImport` cria
18
+ -- clientes e devolve uma contagem. Não há como responder "quais linhas
19
+ -- entraram naquela importação" nem desfazer uma importação inteira.
20
+ --
21
+ -- 4. **A validação humana do catálogo não tem onde ser gravada.** O catálogo
22
+ -- fiscal foi semeado tecnicamente e não foi conferido contra os serviços que
23
+ -- a SC presta. Marcar "conferido" é por escritório, não global — o mesmo
24
+ -- template de sistema pode ser válido para um escritório e não se aplicar a
25
+ -- outro. Por isso é tabela própria, e não coluna em `recurring_item_type`:
26
+ -- aquela linha é COMPARTILHADA entre todos os tenants, e uma coluna nela
27
+ -- faria um escritório carimbar a validação do outro.
28
+ --
29
+ -- Nada aqui liga cobrança, obrigação ou envio. É só onde o dado passa a caber.
30
+
31
+ -- ── 1 · Localidade e responsável do cliente ────────────────────────────────
32
+ --
33
+ -- Os campos de endereço são deliberadamente poucos: os que o produto usa hoje.
34
+ -- `state_uf` tem CHECK de duas maiúsculas porque é ele que vai selecionar regra
35
+ -- estadual — um "Goias" digitado no lugar de "GO" faria a regra não casar em
36
+ -- silêncio, e silêncio é o modo de falha que esta fase existe para eliminar.
37
+
38
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS address_line text;
39
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS municipality text;
40
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS state_uf text;
41
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS postal_code text;
42
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS notes text;
43
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS responsible_user_id uuid REFERENCES "user"(id);
44
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS contract_started_on date;
45
+
46
+ DO $$
47
+ BEGIN
48
+ IF NOT EXISTS (
49
+ SELECT FROM pg_constraint WHERE conname = 'client_state_uf_format'
50
+ ) THEN
51
+ ALTER TABLE client ADD CONSTRAINT client_state_uf_format
52
+ CHECK (state_uf IS NULL OR state_uf ~ '^[A-Z]{2}$');
53
+ END IF;
54
+ END $$;
55
+
56
+ CREATE INDEX IF NOT EXISTS client_responsible_idx
57
+ ON client (tenant_id, responsible_user_id) WHERE deleted_at IS NULL;
58
+ CREATE INDEX IF NOT EXISTS client_locality_idx
59
+ ON client (tenant_id, state_uf, municipality) WHERE deleted_at IS NULL;
60
+
61
+ COMMENT ON COLUMN client.state_uf IS
62
+ 'UF em duas maiúsculas. Seleciona regra estadual de vencimento; formato livre faria a regra não casar em silêncio.';
63
+ COMMENT ON COLUMN client.responsible_user_id IS
64
+ 'Responsável pela carteira deste cliente. Toda troca passa por audit_log — ver assignClientResponsible.';
65
+
66
+ -- ── 2 · Lote de importação ─────────────────────────────────────────────────
67
+ --
68
+ -- Existe para duas perguntas que hoje não têm resposta: "o que entrou naquela
69
+ -- importação?" e "como desfaço?". O desfazer é lógico (soft-delete dos clientes
70
+ -- do lote que ninguém tocou desde então), nunca físico: apagar linha real é
71
+ -- proibido, e um cliente que já ganhou honorário ou obrigação não é mais "só uma
72
+ -- linha importada".
73
+ --
74
+ -- `source_digest` é o sha256 do CSV. É ele que amarra plano e commit: o commit
75
+ -- recusa aplicar um conteúdo diferente do que foi previsto, em vez de reparsear
76
+ -- e produzir um resultado que ninguém viu.
77
+
78
+ CREATE TABLE IF NOT EXISTS client_import_batch (
79
+ id uuid PRIMARY KEY,
80
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
81
+ source_digest text NOT NULL,
82
+ source_name text,
83
+ row_total int NOT NULL DEFAULT 0,
84
+ created_count int NOT NULL DEFAULT 0,
85
+ skipped_count int NOT NULL DEFAULT 0,
86
+ error_count int NOT NULL DEFAULT 0,
87
+ status text NOT NULL DEFAULT 'applied'
88
+ CHECK (status IN ('applied', 'rolled_back')),
89
+ created_by uuid REFERENCES "user"(id),
90
+ created_at timestamptz NOT NULL DEFAULT now(),
91
+ rolled_back_at timestamptz,
92
+ rolled_back_by uuid REFERENCES "user"(id),
93
+ CONSTRAINT client_import_batch_tenant_id_uq UNIQUE (tenant_id, id),
94
+ CHECK ((status <> 'rolled_back') OR rolled_back_at IS NOT NULL)
95
+ );
96
+ CREATE INDEX IF NOT EXISTS client_import_batch_tenant_idx
97
+ ON client_import_batch (tenant_id, created_at DESC);
98
+
99
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS import_batch_id uuid;
100
+
101
+ DO $$
102
+ BEGIN
103
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'client_import_batch_fk') THEN
104
+ ALTER TABLE client ADD CONSTRAINT client_import_batch_fk
105
+ FOREIGN KEY (tenant_id, import_batch_id)
106
+ REFERENCES client_import_batch (tenant_id, id);
107
+ END IF;
108
+ END $$;
109
+
110
+ CREATE INDEX IF NOT EXISTS client_import_batch_idx
111
+ ON client (tenant_id, import_batch_id) WHERE import_batch_id IS NOT NULL;
112
+
113
+ ALTER TABLE client_import_batch ENABLE ROW LEVEL SECURITY;
114
+ ALTER TABLE client_import_batch FORCE ROW LEVEL SECURITY;
115
+ CREATE POLICY client_import_batch_tenant_isolation ON client_import_batch
116
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
117
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
118
+
119
+ -- ── 3 · Validação humana do catálogo, por escritório ───────────────────────
120
+ --
121
+ -- Um item do catálogo, para um escritório, está em um de quatro estados. O
122
+ -- padrão é `pending_validation` e ele é o ponto inteiro: enquanto ninguém
123
+ -- conferiu, o produto deve DIZER que ninguém conferiu, em vez de deixar o seed
124
+ -- passar por verdade operacional.
125
+ --
126
+ -- `depends_on_locality` marca os itens cujo prazo muda por UF ou município. Não
127
+ -- é um prazo inventado — é a ausência de prazo, declarada.
128
+
129
+ CREATE TABLE IF NOT EXISTS recurring_item_type_validation (
130
+ id uuid PRIMARY KEY,
131
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
132
+ item_type_id uuid NOT NULL REFERENCES recurring_item_type(id),
133
+ status text NOT NULL DEFAULT 'pending_validation'
134
+ CHECK (status IN ('validated', 'pending_validation', 'not_applicable', 'disabled')),
135
+ depends_on_locality boolean NOT NULL DEFAULT false,
136
+ note text,
137
+ validated_by uuid REFERENCES "user"(id),
138
+ validated_at timestamptz,
139
+ created_at timestamptz NOT NULL DEFAULT now(),
140
+ updated_at timestamptz NOT NULL DEFAULT now(),
141
+ CONSTRAINT recurring_item_type_validation_tenant_id_uq UNIQUE (tenant_id, id),
142
+ CHECK ((status <> 'validated') OR validated_at IS NOT NULL)
143
+ );
144
+ CREATE UNIQUE INDEX IF NOT EXISTS recurring_item_type_validation_uq
145
+ ON recurring_item_type_validation (tenant_id, item_type_id);
146
+
147
+ ALTER TABLE recurring_item_type_validation ENABLE ROW LEVEL SECURITY;
148
+ ALTER TABLE recurring_item_type_validation FORCE ROW LEVEL SECURITY;
149
+ CREATE POLICY recurring_item_type_validation_tenant_isolation ON recurring_item_type_validation
150
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
151
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
152
+
153
+ COMMENT ON TABLE recurring_item_type_validation IS
154
+ 'Conferência humana do catálogo, POR ESCRITÓRIO. Tabela própria porque recurring_item_type com tenant_id NULL é linha compartilhada: coluna nela faria um escritório carimbar a validação do outro.';
155
+
156
+ -- ── 4 · O serviço contratado ganha responsável e vínculo com obrigação ─────
157
+ --
158
+ -- `fee_agreement` já era a entidade de serviço contratado: tem descrição, valor,
159
+ -- periodicidade, vencimento, início, fim e status, e um cliente pode ter
160
+ -- vários. Não se cria entidade nova para o que já existe. Faltavam duas coisas.
161
+ --
162
+ -- O vínculo é tabela de ligação porque a relação é N-para-N de verdade: um
163
+ -- serviço de folha cobre eSocial, FGTS e a própria folha; e a mesma obrigação
164
+ -- pode estar coberta por mais de um contrato ao longo do tempo.
165
+
166
+ ALTER TABLE fee_agreement ADD COLUMN IF NOT EXISTS responsible_user_id uuid REFERENCES "user"(id);
167
+
168
+ CREATE TABLE IF NOT EXISTS fee_agreement_obligation (
169
+ id uuid PRIMARY KEY,
170
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
171
+ fee_agreement_id uuid NOT NULL,
172
+ item_type_id uuid NOT NULL REFERENCES recurring_item_type(id),
173
+ created_at timestamptz NOT NULL DEFAULT now(),
174
+ CONSTRAINT fee_agreement_obligation_tenant_id_uq UNIQUE (tenant_id, id),
175
+ FOREIGN KEY (tenant_id, fee_agreement_id) REFERENCES fee_agreement (tenant_id, id)
176
+ );
177
+ CREATE UNIQUE INDEX IF NOT EXISTS fee_agreement_obligation_uq
178
+ ON fee_agreement_obligation (tenant_id, fee_agreement_id, item_type_id);
179
+
180
+ ALTER TABLE fee_agreement_obligation ENABLE ROW LEVEL SECURITY;
181
+ ALTER TABLE fee_agreement_obligation FORCE ROW LEVEL SECURITY;
182
+ CREATE POLICY fee_agreement_obligation_tenant_isolation ON fee_agreement_obligation
183
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
184
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
@@ -0,0 +1,89 @@
1
+ -- 0047 — liberação do destinatário para comunicação externa.
2
+ --
3
+ -- ── O que foi medido em produção ────────────────────────────────────────────
4
+ --
5
+ -- Em 2026-09-05, às 12:00, o cron de cobrança enviou 5 e-mails no tenant `sc`.
6
+ -- Hoje isso é inofensivo: o único cliente com e-mail cadastrado é o do próprio
7
+ -- titular, e os recebíveis são sintéticos.
8
+ --
9
+ -- O problema aparece no dia seguinte à importação da carteira real. A régua
10
+ -- percorre todo cliente com e-mail e recebível vencido, e **nada no caminho
11
+ -- pergunta se alguém conferiu aquele endereço**. Trezentos clientes importados
12
+ -- de manhã recebem cobrança automática à tarde, sobre dados que ninguém
13
+ -- validou. Foi exatamente assim que 81 e-mails saíram sobre a carteira de QA.
14
+ --
15
+ -- ── Por que não é consentimento ─────────────────────────────────────────────
16
+ --
17
+ -- O motor já tem consentimento, e ele está certo do jeito que está: a política
18
+ -- do produto trata `unknown` como permitido no e-mail porque cobrança
19
+ -- transacional se apoia na relação contratual. Mudar isso travaria a cobrança
20
+ -- de toda carteira legada que nunca teve o campo preenchido — o próprio código
21
+ -- do consentimento avisa disso.
22
+ --
23
+ -- São perguntas diferentes:
24
+ --
25
+ -- consentimento → "esta pessoa aceita ser contatada?" (vontade do DESTINATÁRIO)
26
+ -- liberação → "alguém daqui conferiu este endereço?" (conferência do REMETENTE)
27
+ --
28
+ -- Elas se separam exatamente no caso que importa: o cliente recém-importado tem
29
+ -- relação contratual e nenhuma conferência.
30
+ --
31
+ -- ── Por que a ausência bloqueia ─────────────────────────────────────────────
32
+ --
33
+ -- O padrão é NÃO liberado, e não existe configuração que inverta isso. Um
34
+ -- default "libera se ninguém disse nada" transformaria a omissão em
35
+ -- autorização — e omissão é o estado natural de todo cliente que acabou de
36
+ -- entrar. O cliente não some da operação: ele aparece com pulo nomeado
37
+ -- (`recipient_not_confirmed`) na trilha e contado no painel.
38
+
39
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS communication_cleared_at timestamptz;
40
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS communication_cleared_by uuid REFERENCES "user"(id);
41
+
42
+ DO $$
43
+ BEGIN
44
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'client_clearance_coherent') THEN
45
+ -- Data e autor andam juntos: uma liberação sem autor não responde "quem
46
+ -- conferiu?", que é a única pergunta que ela existe para responder.
47
+ ALTER TABLE client ADD CONSTRAINT client_clearance_coherent
48
+ CHECK ((communication_cleared_at IS NULL) = (communication_cleared_by IS NULL));
49
+ END IF;
50
+ END $$;
51
+
52
+ CREATE INDEX IF NOT EXISTS client_clearance_idx
53
+ ON client (tenant_id, communication_cleared_at) WHERE deleted_at IS NULL;
54
+
55
+ COMMENT ON COLUMN client.communication_cleared_at IS
56
+ 'Quando alguém do escritório conferiu o contato e liberou este cliente para comunicação externa. NULL = não liberado, e a régua pula com motivo nomeado.';
57
+
58
+ -- ── Marco de início do piloto real ──────────────────────────────────────────
59
+ --
60
+ -- Os registros hoje no tenant `sc` são de desenvolvimento, QA, homologação e
61
+ -- demonstração — inclusive os do App Review da Meta. Nenhum é carteira real.
62
+ --
63
+ -- Sem um marco explícito, daqui a três meses ninguém distingue "cliente de
64
+ -- teste de agosto" de "cliente real de setembro", e todo indicador do painel
65
+ -- passa a misturar os dois. A tabela existe para que a fronteira seja um FATO
66
+ -- gravado, com autor e data, e não uma lembrança.
67
+
68
+ CREATE TABLE IF NOT EXISTS tenant_pilot_milestone (
69
+ id uuid PRIMARY KEY,
70
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
71
+ milestone text NOT NULL CHECK (milestone IN ('real_pilot_start')),
72
+ occurred_at timestamptz NOT NULL DEFAULT now(),
73
+ declared_by uuid REFERENCES "user"(id),
74
+ note text,
75
+ CONSTRAINT tenant_pilot_milestone_tenant_id_uq UNIQUE (tenant_id, id)
76
+ );
77
+
78
+ -- Um marco por tenant: "quando começou de verdade" não admite duas respostas.
79
+ CREATE UNIQUE INDEX IF NOT EXISTS tenant_pilot_milestone_uq
80
+ ON tenant_pilot_milestone (tenant_id, milestone);
81
+
82
+ ALTER TABLE tenant_pilot_milestone ENABLE ROW LEVEL SECURITY;
83
+ ALTER TABLE tenant_pilot_milestone FORCE ROW LEVEL SECURITY;
84
+ CREATE POLICY tenant_pilot_milestone_tenant_isolation ON tenant_pilot_milestone
85
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
86
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
87
+
88
+ COMMENT ON TABLE tenant_pilot_milestone IS
89
+ 'Fronteira gravada entre dado pré-produtivo (QA, demo, Meta App Review) e carteira real. Sem ela, os indicadores do painel misturam os dois e ninguém consegue separar depois.';
@@ -0,0 +1,16 @@
1
+ -- 0048 — a observação do catálogo passa a chegar a quem confere.
2
+ --
3
+ -- `FiscalCatalogEntry.note` existe na vertical desde a Fase 3, com o comentário
4
+ -- "Aparece na UI para o operador saber o que ajustar". Ela nunca apareceu:
5
+ -- não havia coluna, o seed não a escrevia, e a tela não tinha o que mostrar.
6
+ --
7
+ -- Nove das dezessete entradas têm nota, e são exatamente as que o escritório
8
+ -- precisa ler para decidir — as de esfera estadual e municipal, cujo prazo
9
+ -- muda por localidade, e as que dependem do segmento atendido. A conferência
10
+ -- humana do catálogo é o bloqueio desta fase, e ela estava sendo pedida sem a
11
+ -- informação que a torna possível.
12
+
13
+ ALTER TABLE recurring_item_type ADD COLUMN IF NOT EXISTS note text;
14
+
15
+ COMMENT ON COLUMN recurring_item_type.note IS
16
+ 'Observação para quem confere: o que este item exige de decisão local (UF, município, segmento). Não é regra — é o que o operador precisa saber para decidir.';
@@ -0,0 +1,279 @@
1
+ -- 0049 — a fundação nacional do motor fiscal.
2
+ --
3
+ -- ═══ A decisão de modelagem que organiza tudo ═══════════════════════════════
4
+ --
5
+ -- Hoje `recurring_item_type` responde duas perguntas diferentes na mesma linha:
6
+ --
7
+ -- "o que é esta obrigação?" → DAS, ISS, eSocial. Nacional e estável.
8
+ -- "para quem, quando e como vence?" → varia por UF, por município e no tempo.
9
+ --
10
+ -- Enquanto as duas moram juntas, o índice único em `(key)` permite UMA linha
11
+ -- por chave, e daí saem as três limitações que a auditoria mediu: o ISS de
12
+ -- Goiânia e o de São Paulo não coexistem, duas versões da mesma regra não
13
+ -- coexistem, e a aplicabilidade só sabe olhar regime.
14
+ --
15
+ -- Esta migration separa as duas perguntas:
16
+ --
17
+ -- `recurring_item_type` → a IDENTIDADE. Continua como está. Nada quebra.
18
+ -- `fiscal_rule` → a REGRA: jurisdição + vigência + versão +
19
+ -- condições + vencimento.
20
+ --
21
+ -- Um tipo de item passa a ter N regras: uma federal, uma por UF, uma por
22
+ -- município, e mais de uma no tempo. É o que abrangência nacional exige, e é
23
+ -- aditivo — nenhuma linha existente é reescrita.
24
+ --
25
+ -- ═══ O que esta migration NÃO faz ══════════════════════════════════════════
26
+ --
27
+ -- Não cataloga regra nenhuma do Brasil. Ela cria a capacidade; o conteúdo
28
+ -- entra depois, com governança. Os 17 seeds atuais são migrados na 0050 SEM
29
+ -- ganhar precisão que não têm.
30
+
31
+ -- ── 1 · Vocabulário do perfil fiscal ───────────────────────────────────────
32
+ --
33
+ -- Registro de atributos, e não colunas em `client`.
34
+ --
35
+ -- A alternativa seria `has_employees`, `icms_taxpayer`, `iss_taxpayer`,
36
+ -- `ipi_taxpayer`… uma coluna por pergunta fiscal. Isso não escala: cada UF e
37
+ -- cada segmento acrescenta perguntas, e a tabela de cliente viraria uma
38
+ -- estrutura rígida impossível de evoluir — exatamente o que a premissa pede
39
+ -- para evitar.
40
+ --
41
+ -- Com um REGISTRO, acrescentar um atributo é INSERT, não migration. E a FK
42
+ -- impede erro de digitação virar atributo novo em silêncio.
43
+
44
+ CREATE TABLE IF NOT EXISTS fiscal_attribute_definition (
45
+ key text PRIMARY KEY,
46
+ label text NOT NULL,
47
+ description text,
48
+ value_type text NOT NULL CHECK (value_type IN ('boolean', 'text', 'enum')),
49
+ -- Para `enum`: os valores aceitos. Para os demais, `null`.
50
+ allowed_values jsonb,
51
+ created_at timestamptz NOT NULL DEFAULT now(),
52
+ CHECK ((value_type = 'enum') = (allowed_values IS NOT NULL))
53
+ );
54
+
55
+ COMMENT ON TABLE fiscal_attribute_definition IS
56
+ 'Vocabulário GLOBAL do perfil fiscal. Acrescentar atributo é INSERT, não migration — é o que permite o modelo evoluir sem alterar a tabela de cliente.';
57
+
58
+ INSERT INTO fiscal_attribute_definition (key, label, description, value_type, allowed_values) VALUES
59
+ ('has_employees', 'Possui empregados',
60
+ 'Decide a aplicabilidade das obrigações trabalhistas. A AUSÊNCIA deste dado não é "não": é desconhecido, e o motor devolve INSUFFICIENT_DATA.',
61
+ 'boolean', NULL),
62
+ ('icms_taxpayer', 'Contribuinte de ICMS', NULL, 'boolean', NULL),
63
+ ('ipi_taxpayer', 'Contribuinte de IPI', NULL, 'boolean', NULL),
64
+ ('iss_taxpayer', 'Contribuinte de ISS', NULL, 'boolean', NULL),
65
+ ('activity_segment', 'Segmento de atividade', NULL,
66
+ 'enum', '["comercio","industria","servicos","misto"]'::jsonb),
67
+ ('cnae_primary', 'CNAE principal', 'Código, sem interpretação pelo motor nesta fase.', 'text', NULL),
68
+ ('state_registration', 'Inscrição estadual', NULL, 'text', NULL),
69
+ ('municipal_registration', 'Inscrição municipal', NULL, 'text', NULL)
70
+ ON CONFLICT (key) DO NOTHING;
71
+
72
+ -- ── 2 · Perfil fiscal do cliente ───────────────────────────────────────────
73
+ --
74
+ -- Ausência de linha = atributo DESCONHECIDO, e é distinto de `false`. É a
75
+ -- distinção que sustenta o `INSUFFICIENT_DATA` do motor: um cliente sobre o
76
+ -- qual ninguém disse se tem empregados não pode receber eSocial nem ser
77
+ -- declarado isento dele.
78
+
79
+ CREATE TABLE IF NOT EXISTS client_fiscal_attribute (
80
+ id uuid PRIMARY KEY,
81
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
82
+ client_id uuid NOT NULL,
83
+ attribute_key text NOT NULL REFERENCES fiscal_attribute_definition(key),
84
+ value_bool boolean,
85
+ value_text text,
86
+ source text,
87
+ updated_by uuid REFERENCES "user"(id),
88
+ created_at timestamptz NOT NULL DEFAULT now(),
89
+ updated_at timestamptz NOT NULL DEFAULT now(),
90
+ CONSTRAINT client_fiscal_attribute_tenant_id_uq UNIQUE (tenant_id, id),
91
+ FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
92
+ -- Exatamente um valor. Nenhum seria linha sem informação; dois seriam duas
93
+ -- respostas para a mesma pergunta.
94
+ CHECK ((value_bool IS NOT NULL)::int + (value_text IS NOT NULL)::int = 1)
95
+ );
96
+
97
+ CREATE UNIQUE INDEX IF NOT EXISTS client_fiscal_attribute_uq
98
+ ON client_fiscal_attribute (tenant_id, client_id, attribute_key);
99
+
100
+ ALTER TABLE client_fiscal_attribute ENABLE ROW LEVEL SECURITY;
101
+ ALTER TABLE client_fiscal_attribute FORCE ROW LEVEL SECURITY;
102
+ CREATE POLICY client_fiscal_attribute_tenant_isolation ON client_fiscal_attribute
103
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
104
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
105
+
106
+ -- Código IBGE do município: o identificador canônico.
107
+ --
108
+ -- `client.municipality` é texto livre e serve para a tela. Casar regra
109
+ -- municipal por texto livre falharia no primeiro "Goiania" sem acento. O
110
+ -- código é opcional: sem ele, regra municipal devolve INSUFFICIENT_DATA em vez
111
+ -- de casar por aproximação.
112
+ ALTER TABLE client ADD COLUMN IF NOT EXISTS municipality_ibge_code text;
113
+
114
+ DO $$
115
+ BEGIN
116
+ IF NOT EXISTS (SELECT FROM pg_constraint WHERE conname = 'client_ibge_format') THEN
117
+ ALTER TABLE client ADD CONSTRAINT client_ibge_format
118
+ CHECK (municipality_ibge_code IS NULL OR municipality_ibge_code ~ '^[0-9]{7}$');
119
+ END IF;
120
+ END $$;
121
+
122
+ -- ── 3 · A regra fiscal versionada ──────────────────────────────────────────
123
+
124
+ CREATE TABLE IF NOT EXISTS fiscal_rule (
125
+ id uuid PRIMARY KEY,
126
+ -- NULL = regra GLOBAL do produto. NOT NULL = regra do próprio escritório.
127
+ -- Mesmo padrão de `recurring_item_type` e `role`: ler o global é direito de
128
+ -- todos; escrevê-lo, de ninguém que opere como tenant.
129
+ tenant_id uuid REFERENCES tenant(id),
130
+ item_type_id uuid NOT NULL REFERENCES recurring_item_type(id),
131
+
132
+ -- ── jurisdição ──────────────────────────────────────────────────────────
133
+ jurisdiction_scope text NOT NULL CHECK (jurisdiction_scope IN ('federal', 'state', 'municipal')),
134
+ jurisdiction_uf text CHECK (jurisdiction_uf IS NULL OR jurisdiction_uf ~ '^[A-Z]{2}$'),
135
+ jurisdiction_city_ibge text CHECK (jurisdiction_city_ibge IS NULL OR jurisdiction_city_ibge ~ '^[0-9]{7}$'),
136
+ -- A jurisdição precisa ser COMPLETA para o seu nível. Uma regra "estadual"
137
+ -- sem UF não é uma regra: é um marcador que casaria com o país inteiro.
138
+ CHECK (
139
+ (jurisdiction_scope = 'federal' AND jurisdiction_uf IS NULL AND jurisdiction_city_ibge IS NULL) OR
140
+ (jurisdiction_scope = 'state' AND jurisdiction_uf IS NOT NULL AND jurisdiction_city_ibge IS NULL) OR
141
+ (jurisdiction_scope = 'municipal' AND jurisdiction_uf IS NOT NULL AND jurisdiction_city_ibge IS NOT NULL)
142
+ ),
143
+
144
+ -- ── vigência e versão ───────────────────────────────────────────────────
145
+ version int NOT NULL DEFAULT 1 CHECK (version > 0),
146
+ valid_from date NOT NULL,
147
+ valid_until date,
148
+ CHECK (valid_until IS NULL OR valid_until >= valid_from),
149
+
150
+ status text NOT NULL DEFAULT 'pending_validation'
151
+ CHECK (status IN ('not_configured', 'pending_validation', 'validated', 'expired', 'disabled')),
152
+
153
+ -- ── conteúdo ────────────────────────────────────────────────────────────
154
+ -- AST declarativa. Interpretada por código tipado, NUNCA avaliada como
155
+ -- expressão: nada aqui vira `eval`, SQL ou função.
156
+ conditions jsonb NOT NULL DEFAULT '{"op":"always"}'::jsonb,
157
+ due_rule jsonb,
158
+
159
+ -- ── procedência ─────────────────────────────────────────────────────────
160
+ source_reference text,
161
+ validated_by uuid REFERENCES "user"(id),
162
+ validated_at timestamptz,
163
+ note text,
164
+
165
+ created_at timestamptz NOT NULL DEFAULT now(),
166
+ updated_at timestamptz NOT NULL DEFAULT now(),
167
+ deleted_at timestamptz,
168
+
169
+ CONSTRAINT fiscal_rule_tenant_id_uq UNIQUE (tenant_id, id),
170
+ -- Uma regra `validated` sem quem validou é uma afirmação sem autor.
171
+ CHECK ((status <> 'validated') OR (validated_at IS NOT NULL AND validated_by IS NOT NULL)),
172
+ -- `not_configured` é o estado honesto de quem não tem vencimento definido.
173
+ -- Uma regra validada SEM vencimento produziria obrigação sem data.
174
+ CHECK ((status <> 'validated') OR due_rule IS NOT NULL)
175
+ );
176
+
177
+ -- Versões da mesma regra não se sobrepõem: uma só vigente por jurisdição.
178
+ -- Mesmo padrão que `accounting_regime` já provou para o regime do cliente.
179
+ CREATE UNIQUE INDEX IF NOT EXISTS fiscal_rule_current_uq
180
+ ON fiscal_rule (
181
+ coalesce(tenant_id::text, '-'), item_type_id, jurisdiction_scope,
182
+ coalesce(jurisdiction_uf, '-'), coalesce(jurisdiction_city_ibge, '-')
183
+ )
184
+ WHERE valid_until IS NULL AND deleted_at IS NULL;
185
+
186
+ CREATE UNIQUE INDEX IF NOT EXISTS fiscal_rule_version_uq
187
+ ON fiscal_rule (
188
+ coalesce(tenant_id::text, '-'), item_type_id, jurisdiction_scope,
189
+ coalesce(jurisdiction_uf, '-'), coalesce(jurisdiction_city_ibge, '-'), version
190
+ )
191
+ WHERE deleted_at IS NULL;
192
+
193
+ -- Pré-filtragem: a engine busca por jurisdição + vigência antes de avaliar
194
+ -- condição nenhuma. Sem este índice, avaliar a carteira exigiria varrer o
195
+ -- catálogo inteiro por cliente.
196
+ CREATE INDEX IF NOT EXISTS fiscal_rule_lookup_idx
197
+ ON fiscal_rule (jurisdiction_scope, jurisdiction_uf, jurisdiction_city_ibge, valid_from)
198
+ WHERE deleted_at IS NULL;
199
+ CREATE INDEX IF NOT EXISTS fiscal_rule_item_idx
200
+ ON fiscal_rule (item_type_id, valid_from) WHERE deleted_at IS NULL;
201
+
202
+ ALTER TABLE fiscal_rule ENABLE ROW LEVEL SECURITY;
203
+ ALTER TABLE fiscal_rule FORCE ROW LEVEL SECURITY;
204
+
205
+ -- Leitura: a regra global e as do próprio escritório.
206
+ -- Escrita: SOMENTE as do próprio escritório.
207
+ --
208
+ -- O `WITH CHECK` sem o ramo `IS NULL` é a lição da 0045: com ele, qualquer
209
+ -- tenant forjaria regra fiscal GLOBAL — que vale para todos os escritórios do
210
+ -- país. É a escalada mais cara que este schema comporta.
211
+ CREATE POLICY fiscal_rule_visibility ON fiscal_rule
212
+ USING (tenant_id IS NULL OR tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
213
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
214
+
215
+ DO $$
216
+ DECLARE owner_role text;
217
+ BEGIN
218
+ SELECT tableowner INTO owner_role FROM pg_tables
219
+ WHERE schemaname = 'public' AND tablename = 'fiscal_rule';
220
+ IF owner_role IS NULL THEN
221
+ RAISE EXCEPTION 'fiscal_rule sem dono identificável — abortando';
222
+ END IF;
223
+ -- FORCE RLS vale para o dono; o provisionamento do catálogo global roda sem
224
+ -- tenant no contexto e precisa de política nominal. Padrão da 0042/0045.
225
+ EXECUTE format(
226
+ 'CREATE POLICY fiscal_rule_system_provisioning ON fiscal_rule FOR ALL TO %I USING (true) WITH CHECK (true)',
227
+ owner_role);
228
+ END $$;
229
+
230
+ COMMENT ON POLICY fiscal_rule_visibility ON fiscal_rule IS
231
+ 'Leitura: regra global + as do tenant. Escrita: SOMENTE do tenant. O ramo IS NULL fora do WITH CHECK impede forjar regra fiscal nacional (lição do P0-A, Fase 4).';
232
+
233
+ -- ── 4 · Política operacional do escritório ─────────────────────────────────
234
+ --
235
+ -- Separa REGRA LEGAL de PROCEDIMENTO DO ESCRITÓRIO.
236
+ --
237
+ -- O prazo legal do DAS é do país. O prazo em que o escritório quer os
238
+ -- documentos do cliente na mão é dele. Enquanto os dois moram no mesmo campo,
239
+ -- ajustar o procedimento interno reescreve a regra legal — em silêncio, e para
240
+ -- todo mundo que enxerga aquela linha.
241
+
242
+ CREATE TABLE IF NOT EXISTS tenant_rule_policy (
243
+ id uuid PRIMARY KEY,
244
+ tenant_id uuid NOT NULL REFERENCES tenant(id),
245
+ item_type_id uuid NOT NULL REFERENCES recurring_item_type(id),
246
+ -- Dias ANTES do vencimento legal em que o escritório quer a coisa pronta.
247
+ -- Não altera o vencimento legal: acrescenta um prazo interno ao lado dele.
248
+ internal_lead_days int CHECK (internal_lead_days IS NULL OR internal_lead_days BETWEEN 0 AND 90),
249
+ enabled boolean NOT NULL DEFAULT true,
250
+ note text,
251
+ updated_by uuid REFERENCES "user"(id),
252
+ created_at timestamptz NOT NULL DEFAULT now(),
253
+ updated_at timestamptz NOT NULL DEFAULT now(),
254
+ CONSTRAINT tenant_rule_policy_tenant_id_uq UNIQUE (tenant_id, id)
255
+ );
256
+
257
+ CREATE UNIQUE INDEX IF NOT EXISTS tenant_rule_policy_uq
258
+ ON tenant_rule_policy (tenant_id, item_type_id);
259
+
260
+ ALTER TABLE tenant_rule_policy ENABLE ROW LEVEL SECURITY;
261
+ ALTER TABLE tenant_rule_policy FORCE ROW LEVEL SECURITY;
262
+ CREATE POLICY tenant_rule_policy_tenant_isolation ON tenant_rule_policy
263
+ USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
264
+ WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
265
+
266
+ COMMENT ON TABLE tenant_rule_policy IS
267
+ 'Procedimento do escritório, ao LADO da regra legal e nunca por cima dela. Prazo interno não é prazo legal.';
268
+
269
+ -- ── 5 · Preservação histórica ──────────────────────────────────────────────
270
+ --
271
+ -- A instância já congela `label` e `due_date`. Falta saber QUAL versão da
272
+ -- regra produziu aquela data — sem isso, uma V2 publicada amanhã faz a
273
+ -- obrigação de ontem parecer ter nascido de uma regra que não existia.
274
+
275
+ ALTER TABLE recurring_instance ADD COLUMN IF NOT EXISTS fiscal_rule_id uuid REFERENCES fiscal_rule(id);
276
+ ALTER TABLE recurring_instance ADD COLUMN IF NOT EXISTS fiscal_rule_version int;
277
+
278
+ COMMENT ON COLUMN recurring_instance.fiscal_rule_id IS
279
+ 'Versão EXATA da regra que gerou esta obrigação. Publicar uma V2 não altera o que já foi gerado sob a V1.';
@@ -0,0 +1,29 @@
1
+ -- 0050 — o vocabulário do perfil fiscal é lido pelo runtime, nunca escrito.
2
+ --
3
+ -- Esta migration existe separada da 0049 por uma razão de processo, e vale
4
+ -- registrar: eu havia acrescentado este bloco ao fim da 0049 depois de ela já
5
+ -- ter sido aplicada. O runner recusou — migrations são imutáveis, e a checagem
6
+ -- de hash existe exatamente para impedir que o que rodou num ambiente seja
7
+ -- diferente do que roda no próximo.
8
+ --
9
+ -- ── A barreira ─────────────────────────────────────────────────────────────
10
+ --
11
+ -- `fiscal_attribute_definition` é catálogo GLOBAL, sem `tenant_id`. Não há RLS
12
+ -- que o proteja, porque não há linha de ninguém: a barreira só pode ser o
13
+ -- privilégio.
14
+ --
15
+ -- O runtime lê o vocabulário a cada avaliação de aplicabilidade e nunca o
16
+ -- escreve. Um tenant capaz de inserir atributo aqui poderia criar um atributo
17
+ -- que nenhuma regra usa (inócuo) ou — pior — apagar um que as regras de todos
18
+ -- os escritórios usam, derrubando a avaliação do país inteiro por FK.
19
+ --
20
+ -- Repetido em `migrate.ts` no mesmo bloco de `role` e `audit_log`: o GRANT da
21
+ -- allowlist é amplo por construção e devolveria a escrita no deploy seguinte.
22
+ -- Foi o defeito que a Fase 3 encontrou ao separar GRANT de hardening.
23
+
24
+ DO $$
25
+ BEGIN
26
+ IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'baruk_app') THEN
27
+ EXECUTE 'REVOKE INSERT, UPDATE, DELETE ON fiscal_attribute_definition FROM baruk_app';
28
+ END IF;
29
+ END $$;