ekwo-os 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/README.md +873 -0
  2. package/dist/args.d.ts +57 -0
  3. package/dist/args.d.ts.map +1 -0
  4. package/dist/args.js +134 -0
  5. package/dist/args.js.map +1 -0
  6. package/dist/assets/expected-objects.json +9432 -0
  7. package/dist/assets/migrations/20260911120000_core_companies.sql +260 -0
  8. package/dist/assets/migrations/20260911120100_accounts_journals.sql +211 -0
  9. package/dist/assets/migrations/20260911120200_contacts.sql +90 -0
  10. package/dist/assets/migrations/20260911120300_taxes.sql +146 -0
  11. package/dist/assets/migrations/20260911120400_entries.sql +338 -0
  12. package/dist/assets/migrations/20260911120500_documents.sql +279 -0
  13. package/dist/assets/migrations/20260911120600_payments_reconciliation.sql +251 -0
  14. package/dist/assets/migrations/20260911120700_bank.sql +178 -0
  15. package/dist/assets/migrations/20260911120800_analytics_attachments.sql +128 -0
  16. package/dist/assets/migrations/20260911120900_post_document.sql +279 -0
  17. package/dist/assets/migrations/20260911121000_reporting.sql +235 -0
  18. package/dist/assets/migrations/20260911121100_country_templates.sql +226 -0
  19. package/dist/assets/migrations/20260911121200_fec.sql +71 -0
  20. package/dist/assets/migrations/20260911130000_instance.sql +77 -0
  21. package/dist/assets/migrations/20260911130100_instance_members.sql +224 -0
  22. package/dist/assets/migrations/20260911140000_instance_admins.sql +112 -0
  23. package/dist/assets/migrations/20260911160000_tax_posting_templates_unique.sql +17 -0
  24. package/dist/assets/migrations/20260911170000_document_amount_paid.sql +82 -0
  25. package/dist/assets/migrations/20260911173000_post_payment.sql +122 -0
  26. package/dist/assets/migrations/20260911173100_sequence_counters_under_rls.sql +84 -0
  27. package/dist/assets/migrations/20260911183000_country_journal_defaults.sql +143 -0
  28. package/dist/assets/migrations/20260911193853_line_account_defaults.sql +274 -0
  29. package/dist/assets/migrations/20260911195054_products.sql +221 -0
  30. package/dist/assets/migrations/20260911210131_anon_surface.sql +85 -0
  31. package/dist/assets/migrations/20260912074712_country_packs.sql +318 -0
  32. package/dist/assets/migrations/20260912080311_report_code_and_region.sql +198 -0
  33. package/dist/assets/migrations/20260912081014_pack_certification_maintained.sql +31 -0
  34. package/dist/assets/migrations/20260912081015_pack_certification_backfill.sql +16 -0
  35. package/dist/assets/migrations/20260912090407_tax_report_boxes.sql +329 -0
  36. package/dist/assets/migrations/20260912091917_tax_on_base_value.sql +25 -0
  37. package/dist/assets/migrations/20260912091918_tax_engine_columns.sql +776 -0
  38. package/dist/assets/migrations/20260912094412_opening_and_closing.sql +759 -0
  39. package/dist/assets/migrations/20260912095825_charts_of_accounts.sql +326 -0
  40. package/dist/assets/migrations/20260912100412_financial_statements.sql +632 -0
  41. package/dist/assets/migrations/20260912104719_one_formula_evaluator.sql +209 -0
  42. package/dist/assets/migrations/20260912105720_entry_kind_appropriation.sql +26 -0
  43. package/dist/assets/migrations/20260912105721_appropriation_entry_kind.sql +444 -0
  44. package/dist/assets/migrations/20260912111751_document_rules.sql +274 -0
  45. package/dist/assets/migrations/20260912112132_cash_basis_vat_and_fx.sql +1189 -0
  46. package/dist/assets/migrations/20260913074512_modules.sql +493 -0
  47. package/dist/assets/migrations/20260913075903_asset_disposal_roles.sql +47 -0
  48. package/dist/assets/migrations/20260913083216_capabilities.sql +637 -0
  49. package/dist/assets/migrations/20260913083901_company_invitations.sql +262 -0
  50. package/dist/assets/migrations/20260913084402_user_preferences.sql +376 -0
  51. package/dist/assets/migrations/20260913084847_company_profile.sql +261 -0
  52. package/dist/assets/migrations/20260913085436_numbering_reads_the_pack.sql +235 -0
  53. package/dist/assets/migrations/20260913085932_api_keys.sql +303 -0
  54. package/dist/assets/migrations/20260913090216_fiscal_year_bounds.sql +159 -0
  55. package/dist/assets/migrations/20260913092527_entries_import.sql +219 -0
  56. package/dist/assets/migrations/20260913101536_null_safe_guards.sql +188 -0
  57. package/dist/assets/migrations/20260913102115_installer_is_named.sql +462 -0
  58. package/dist/assets/migrations/20260913102758_no_currency_default.sql +138 -0
  59. package/dist/assets/migrations/20260913103355_cash_basis_needs_a_box.sql +453 -0
  60. package/dist/assets/migrations/20260913104014_aged_balance_named_group.sql +79 -0
  61. package/dist/assets/migrations/20260913104232_foreign_key_indexes.sql +144 -0
  62. package/dist/assets/migrations/20260913105120_declared_no_reader.sql +41 -0
  63. package/dist/assets/migrations/20260913111407_pack_languages.sql +223 -0
  64. package/dist/assets/migrations/20260913112233_schema_comments_for_a_reader.sql +27 -0
  65. package/dist/assets/migrations/20260913114535_fec_opening_balances.sql +307 -0
  66. package/dist/assets/migrations/20260914103412_audit_log.sql +509 -0
  67. package/dist/assets/migrations/20260914111907_pack_upgrade.sql +428 -0
  68. package/dist/assets/migrations/20260914120500_rounding_reads_the_currency.sql +206 -0
  69. package/dist/assets/migrations/20260914121200_amounts_round_at_the_currency.sql +2403 -0
  70. package/dist/assets/migrations/20260914134325_schema_version_0_2_0.sql +36 -0
  71. package/dist/assets/migrations/20260914143915_accounts_in_use.sql +428 -0
  72. package/dist/assets/migrations/20260914144731_account_code_frozen.sql +99 -0
  73. package/dist/assets/migrations/20260914151207_schema_grants_its_own_rights.sql +284 -0
  74. package/dist/assets/migrations/20260914152840_pack_upgrade_records_its_own_line.sql +237 -0
  75. package/dist/assets/migrations/20260914163943_declaration_periodicity.sql +349 -0
  76. package/dist/assets/migrations/20260915094000_foreign_services_received.sql +37 -0
  77. package/dist/assets/migrations/20260915094500_mentions_read_a_foreign_service.sql +72 -0
  78. package/dist/assets/migrations/20260915153000_document_shares.sql +568 -0
  79. package/dist/assets/migrations/20260915160000_ec_sales_list.sql +181 -0
  80. package/dist/assets/migrations/20260915161842_pack_sources.sql +56 -0
  81. package/dist/assets/migrations/20260915170500_schema_version_0_3_0.sql +45 -0
  82. package/dist/assets/migrations/20260915174500_a_vat_category_is_a_code.sql +177 -0
  83. package/dist/assets/migrations/20260915180000_document_rule_references.sql +85 -0
  84. package/dist/assets/migrations/20260915181000_territories.sql +342 -0
  85. package/dist/assets/migrations/20260915181500_ec_sales_list_reads_the_territories.sql +222 -0
  86. package/dist/assets/migrations/20260915182000_intracom_triangular.sql +53 -0
  87. package/dist/assets/migrations/20260915182500_a_triangular_supply_says_reverse_charge.sql +99 -0
  88. package/dist/assets/migrations/20260915191200_a_document_knows_its_language.sql +633 -0
  89. package/dist/assets/migrations/20260915195000_a_price_that_holds_its_tax.sql +649 -0
  90. package/dist/assets/migrations/20260915200000_a_posting_names_its_boxes.sql +1004 -0
  91. package/dist/assets/migrations/20260916094500_a_company_files_more_than_one_declaration.sql +795 -0
  92. package/dist/assets/migrations/20260916103000_a_ledger_line_names_its_posting.sql +902 -0
  93. package/dist/assets/migrations/20260916123000_a_vocabulary_for_a_tax_that_is_not_a_vat.sql +144 -0
  94. package/dist/assets/migrations/20260916124000_a_box_can_be_a_rate_of_a_box.sql +525 -0
  95. package/dist/assets/migrations/20260916125000_a_tax_follows_the_territory.sql +1318 -0
  96. package/dist/assets/migrations/20260916126000_a_tax_point_and_its_exception.sql +1211 -0
  97. package/dist/assets/migrations/20260917090000_a_counterparty_that_learns.sql +561 -0
  98. package/dist/assets/migrations/20260917120000_what_the_money_pays.sql +545 -0
  99. package/dist/assets/migrations/20260917150000_a_filing_is_a_row.sql +488 -0
  100. package/dist/assets/migrations/20260917170000_when_it_is_due.sql +194 -0
  101. package/dist/assets/migrations/20260917180000_a_box_is_a_number_and_a_kind.sql +213 -0
  102. package/dist/assets/migrations/20260917190000_what_a_declaration_owes.sql +486 -0
  103. package/dist/assets/migrations/20260917200000_what_moved_after_it_went.sql +227 -0
  104. package/dist/assets/migrations/20260918090000_a_form_names_its_file.sql +27 -0
  105. package/dist/assets/migrations/20260918110000_a_deposit_and_what_came_back.sql +286 -0
  106. package/dist/assets/migrations/20260918113741_a_fourth_preset_is_named.sql +9 -0
  107. package/dist/assets/migrations/20260918113807_a_client_reads_and_hands_over.sql +96 -0
  108. package/dist/assets/migrations/20260918114322_two_definer_functions_check_their_caller.sql +75 -0
  109. package/dist/assets/migrations/20260918130000_every_company_somebody_keeps.sql +177 -0
  110. package/dist/assets/migrations/20260918140000_a_session_nobody_prepared.sql +40 -0
  111. package/dist/assets/migrations/20260918141107_a_line_keeps_the_tax_it_was_posted_with.sql +256 -0
  112. package/dist/assets/migrations/20260918141342_a_company_has_an_electronic_address.sql +66 -0
  113. package/dist/assets/migrations/20260918141605_an_invoice_reads_whole_from_the_views.sql +313 -0
  114. package/dist/assets/migrations/20260918141627_a_policy_asks_once.sql +132 -0
  115. package/dist/assets/migrations/20260918143352_a_suggestion_reads_the_words_once.sql +204 -0
  116. package/dist/assets/migrations/20260918143417_a_reference_of_the_caller_and_a_rehearsal.sql +115 -0
  117. package/dist/assets/migrations/20260918150712_a_company_leaves_with_its_books.sql +1119 -0
  118. package/dist/assets/migrations/20260918150931_a_statement_is_imported_once.sql +654 -0
  119. package/dist/assets/migrations/20260918161204_a_posted_document_does_not_move.sql +437 -0
  120. package/dist/assets/migrations/20260918161538_a_posted_entry_does_not_move.sql +252 -0
  121. package/dist/assets/migrations/20260918171946_an_entry_is_posted_by_post_entry.sql +289 -0
  122. package/dist/assets/migrations/20260918174312_schema_version_0_4_0.sql +53 -0
  123. package/dist/assets/modules/assets/module.json +13 -0
  124. package/dist/assets/modules/assets/supabase/migrations/20260913081447_assets.sql +1190 -0
  125. package/dist/assets/modules/assets/supabase/migrations/20260913104234_foreign_key_indexes.sql +47 -0
  126. package/dist/assets/modules/assets/supabase/migrations/20260913104500_assets_capabilities.sql +145 -0
  127. package/dist/assets/modules/assets/supabase/migrations/20260914122100_assets_round_at_the_currency.sql +564 -0
  128. package/dist/assets/modules/assets/supabase/migrations/20260914145012_assets_accounts_in_use.sql +37 -0
  129. package/dist/assets/modules/assets/supabase/migrations/20260914151530_assets_grants_its_own_rights.sql +63 -0
  130. package/dist/assets/modules/assets/supabase/migrations/20260918113912_assets_client_reads.sql +20 -0
  131. package/dist/assets/modules/assets/supabase/migrations/20260918150801_assets_leave_with_the_company.sql +41 -0
  132. package/dist/assets/modules/budgets/module.json +12 -0
  133. package/dist/assets/modules/budgets/supabase/migrations/20260913083012_budgets.sql +210 -0
  134. package/dist/assets/modules/budgets/supabase/migrations/20260913104233_foreign_key_indexes.sql +37 -0
  135. package/dist/assets/modules/budgets/supabase/migrations/20260913104501_budgets_capabilities.sql +72 -0
  136. package/dist/assets/modules/budgets/supabase/migrations/20260914122400_budgets_round_at_the_currency.sql +68 -0
  137. package/dist/assets/modules/budgets/supabase/migrations/20260914145048_budgets_accounts_in_use.sql +30 -0
  138. package/dist/assets/modules/budgets/supabase/migrations/20260914151812_budgets_grants_its_own_rights.sql +31 -0
  139. package/dist/assets/modules/budgets/supabase/migrations/20260918113954_budgets_client_reads.sql +20 -0
  140. package/dist/assets/modules/budgets/supabase/migrations/20260918150823_budgets_leave_with_the_company.sql +37 -0
  141. package/dist/assets/modules/schema/module.1.json +69 -0
  142. package/dist/assets/seed/00_currencies.sql +15 -0
  143. package/dist/assets/seed/00_territories.sql +280 -0
  144. package/dist/assets/seed/05_framework_generic.sql +110 -0
  145. package/dist/assets/seed/10_pack_be.sql +1284 -0
  146. package/dist/assets/seed/11_pack_fr.sql +1112 -0
  147. package/dist/assets/seed/12_pack_lu.sql +2484 -0
  148. package/dist/assets/seed/13_pack_ee.sql +733 -0
  149. package/dist/assets/seed/14_pack_gb.sql +796 -0
  150. package/dist/assets/seed/15_pack_us.sql +751 -0
  151. package/dist/assets/seed/90_demo_company.sql +368 -0
  152. package/dist/assets/seed/modules/assets/10_pack_be.sql +58 -0
  153. package/dist/assets/seed/modules/assets/11_pack_fr.sql +57 -0
  154. package/dist/assets/seed/modules/assets/14_pack_gb.sql +58 -0
  155. package/dist/assets/seed/modules/assets/15_pack_us.sql +60 -0
  156. package/dist/auth.d.ts +59 -0
  157. package/dist/auth.d.ts.map +1 -0
  158. package/dist/auth.js +134 -0
  159. package/dist/auth.js.map +1 -0
  160. package/dist/bin.d.ts +6 -0
  161. package/dist/bin.d.ts.map +1 -0
  162. package/dist/bin.js +8 -0
  163. package/dist/bin.js.map +1 -0
  164. package/dist/books.d.ts +60 -0
  165. package/dist/books.d.ts.map +1 -0
  166. package/dist/books.js +168 -0
  167. package/dist/books.js.map +1 -0
  168. package/dist/bootstrap.d.ts +236 -0
  169. package/dist/bootstrap.d.ts.map +1 -0
  170. package/dist/bootstrap.js +459 -0
  171. package/dist/bootstrap.js.map +1 -0
  172. package/dist/bundle.d.ts +27 -0
  173. package/dist/bundle.d.ts.map +1 -0
  174. package/dist/bundle.js +47 -0
  175. package/dist/bundle.js.map +1 -0
  176. package/dist/checklist.d.ts +35 -0
  177. package/dist/checklist.d.ts.map +1 -0
  178. package/dist/checklist.js +64 -0
  179. package/dist/checklist.js.map +1 -0
  180. package/dist/cli.d.ts +14 -0
  181. package/dist/cli.d.ts.map +1 -0
  182. package/dist/cli.js +318 -0
  183. package/dist/cli.js.map +1 -0
  184. package/dist/commands/company.d.ts +59 -0
  185. package/dist/commands/company.d.ts.map +1 -0
  186. package/dist/commands/company.js +287 -0
  187. package/dist/commands/company.js.map +1 -0
  188. package/dist/commands/contact.d.ts +9 -0
  189. package/dist/commands/contact.d.ts.map +1 -0
  190. package/dist/commands/contact.js +82 -0
  191. package/dist/commands/contact.js.map +1 -0
  192. package/dist/commands/demo.d.ts +19 -0
  193. package/dist/commands/demo.d.ts.map +1 -0
  194. package/dist/commands/demo.js +72 -0
  195. package/dist/commands/demo.js.map +1 -0
  196. package/dist/commands/doctor.d.ts +12 -0
  197. package/dist/commands/doctor.d.ts.map +1 -0
  198. package/dist/commands/doctor.js +68 -0
  199. package/dist/commands/doctor.js.map +1 -0
  200. package/dist/commands/document.d.ts +17 -0
  201. package/dist/commands/document.d.ts.map +1 -0
  202. package/dist/commands/document.js +217 -0
  203. package/dist/commands/document.js.map +1 -0
  204. package/dist/commands/init.d.ts +31 -0
  205. package/dist/commands/init.d.ts.map +1 -0
  206. package/dist/commands/init.js +535 -0
  207. package/dist/commands/init.js.map +1 -0
  208. package/dist/commands/login.d.ts +24 -0
  209. package/dist/commands/login.d.ts.map +1 -0
  210. package/dist/commands/login.js +128 -0
  211. package/dist/commands/login.js.map +1 -0
  212. package/dist/commands/migrate.d.ts +30 -0
  213. package/dist/commands/migrate.d.ts.map +1 -0
  214. package/dist/commands/migrate.js +115 -0
  215. package/dist/commands/migrate.js.map +1 -0
  216. package/dist/commands/module.d.ts +32 -0
  217. package/dist/commands/module.d.ts.map +1 -0
  218. package/dist/commands/module.js +285 -0
  219. package/dist/commands/module.js.map +1 -0
  220. package/dist/commands/pack.d.ts +22 -0
  221. package/dist/commands/pack.d.ts.map +1 -0
  222. package/dist/commands/pack.js +481 -0
  223. package/dist/commands/pack.js.map +1 -0
  224. package/dist/commands/payment.d.ts +15 -0
  225. package/dist/commands/payment.d.ts.map +1 -0
  226. package/dist/commands/payment.js +97 -0
  227. package/dist/commands/payment.js.map +1 -0
  228. package/dist/commands/register.d.ts +20 -0
  229. package/dist/commands/register.d.ts.map +1 -0
  230. package/dist/commands/register.js +134 -0
  231. package/dist/commands/register.js.map +1 -0
  232. package/dist/commands/status.d.ts +8 -0
  233. package/dist/commands/status.d.ts.map +1 -0
  234. package/dist/commands/status.js +134 -0
  235. package/dist/commands/status.js.map +1 -0
  236. package/dist/commands/whoami.d.ts +21 -0
  237. package/dist/commands/whoami.d.ts.map +1 -0
  238. package/dist/commands/whoami.js +133 -0
  239. package/dist/commands/whoami.js.map +1 -0
  240. package/dist/company.d.ts +16 -0
  241. package/dist/company.d.ts.map +1 -0
  242. package/dist/company.js +26 -0
  243. package/dist/company.js.map +1 -0
  244. package/dist/config.d.ts +24 -0
  245. package/dist/config.d.ts.map +1 -0
  246. package/dist/config.js +50 -0
  247. package/dist/config.js.map +1 -0
  248. package/dist/connection.d.ts +79 -0
  249. package/dist/connection.d.ts.map +1 -0
  250. package/dist/connection.js +116 -0
  251. package/dist/connection.js.map +1 -0
  252. package/dist/context.d.ts +47 -0
  253. package/dist/context.d.ts.map +1 -0
  254. package/dist/context.js +93 -0
  255. package/dist/context.js.map +1 -0
  256. package/dist/doctor.d.ts +45 -0
  257. package/dist/doctor.d.ts.map +1 -0
  258. package/dist/doctor.js +448 -0
  259. package/dist/doctor.js.map +1 -0
  260. package/dist/grants.d.ts +88 -0
  261. package/dist/grants.d.ts.map +1 -0
  262. package/dist/grants.js +174 -0
  263. package/dist/grants.js.map +1 -0
  264. package/dist/identity.d.ts +54 -0
  265. package/dist/identity.d.ts.map +1 -0
  266. package/dist/identity.js +132 -0
  267. package/dist/identity.js.map +1 -0
  268. package/dist/index.d.ts +44 -0
  269. package/dist/index.d.ts.map +1 -0
  270. package/dist/index.js +43 -0
  271. package/dist/index.js.map +1 -0
  272. package/dist/inventory.d.ts +155 -0
  273. package/dist/inventory.d.ts.map +1 -0
  274. package/dist/inventory.js +303 -0
  275. package/dist/inventory.js.map +1 -0
  276. package/dist/migrations.d.ts +76 -0
  277. package/dist/migrations.d.ts.map +1 -0
  278. package/dist/migrations.js +226 -0
  279. package/dist/migrations.js.map +1 -0
  280. package/dist/module/read.d.ts +91 -0
  281. package/dist/module/read.d.ts.map +1 -0
  282. package/dist/module/read.js +172 -0
  283. package/dist/module/read.js.map +1 -0
  284. package/dist/output.d.ts +110 -0
  285. package/dist/output.d.ts.map +1 -0
  286. package/dist/output.js +173 -0
  287. package/dist/output.js.map +1 -0
  288. package/dist/pack/certification.d.ts +27 -0
  289. package/dist/pack/certification.d.ts.map +1 -0
  290. package/dist/pack/certification.js +38 -0
  291. package/dist/pack/certification.js.map +1 -0
  292. package/dist/pack/compile.d.ts +75 -0
  293. package/dist/pack/compile.d.ts.map +1 -0
  294. package/dist/pack/compile.js +801 -0
  295. package/dist/pack/compile.js.map +1 -0
  296. package/dist/pack/filing.d.ts +48 -0
  297. package/dist/pack/filing.d.ts.map +1 -0
  298. package/dist/pack/filing.js +56 -0
  299. package/dist/pack/filing.js.map +1 -0
  300. package/dist/pack/read.d.ts +766 -0
  301. package/dist/pack/read.d.ts.map +1 -0
  302. package/dist/pack/read.js +2336 -0
  303. package/dist/pack/read.js.map +1 -0
  304. package/dist/pack/schema.d.ts +26 -0
  305. package/dist/pack/schema.d.ts.map +1 -0
  306. package/dist/pack/schema.js +181 -0
  307. package/dist/pack/schema.js.map +1 -0
  308. package/dist/pack/territories.d.ts +98 -0
  309. package/dist/pack/territories.d.ts.map +1 -0
  310. package/dist/pack/territories.js +0 -0
  311. package/dist/pack/territories.js.map +1 -0
  312. package/dist/pack/upgrade.d.ts +86 -0
  313. package/dist/pack/upgrade.d.ts.map +1 -0
  314. package/dist/pack/upgrade.js +76 -0
  315. package/dist/pack/upgrade.js.map +1 -0
  316. package/dist/pack/vat-codes.d.ts +273 -0
  317. package/dist/pack/vat-codes.d.ts.map +1 -0
  318. package/dist/pack/vat-codes.js +513 -0
  319. package/dist/pack/vat-codes.js.map +1 -0
  320. package/dist/profiles.d.ts +67 -0
  321. package/dist/profiles.d.ts.map +1 -0
  322. package/dist/profiles.js +187 -0
  323. package/dist/profiles.js.map +1 -0
  324. package/dist/prompt.d.ts +40 -0
  325. package/dist/prompt.d.ts.map +1 -0
  326. package/dist/prompt.js +120 -0
  327. package/dist/prompt.js.map +1 -0
  328. package/dist/registry.d.ts +84 -0
  329. package/dist/registry.d.ts.map +1 -0
  330. package/dist/registry.js +104 -0
  331. package/dist/registry.js.map +1 -0
  332. package/dist/rest.d.ts +81 -0
  333. package/dist/rest.d.ts.map +1 -0
  334. package/dist/rest.js +245 -0
  335. package/dist/rest.js.map +1 -0
  336. package/dist/schema.d.ts +15 -0
  337. package/dist/schema.d.ts.map +1 -0
  338. package/dist/schema.js +15 -0
  339. package/dist/schema.js.map +1 -0
  340. package/dist/seeds.d.ts +27 -0
  341. package/dist/seeds.d.ts.map +1 -0
  342. package/dist/seeds.js +47 -0
  343. package/dist/seeds.js.map +1 -0
  344. package/dist/session.d.ts +39 -0
  345. package/dist/session.d.ts.map +1 -0
  346. package/dist/session.js +92 -0
  347. package/dist/session.js.map +1 -0
  348. package/dist/sql.d.ts +48 -0
  349. package/dist/sql.d.ts.map +1 -0
  350. package/dist/sql.js +112 -0
  351. package/dist/sql.js.map +1 -0
  352. package/dist/status.d.ts +94 -0
  353. package/dist/status.d.ts.map +1 -0
  354. package/dist/status.js +120 -0
  355. package/dist/status.js.map +1 -0
  356. package/dist/ui.d.ts +55 -0
  357. package/dist/ui.d.ts.map +1 -0
  358. package/dist/ui.js +114 -0
  359. package/dist/ui.js.map +1 -0
  360. package/package.json +29 -0
  361. package/schema/output.1.json +613 -0
@@ -0,0 +1,235 @@
1
+ -- Ekwo OS — the reports the schema exists for.
2
+ --
3
+ -- Every one of them filters posted entries in the WHERE clause, never in a
4
+ -- LEFT JOIN condition: a draft line that survives an outer join is how a
5
+ -- trial balance silently stops tying out.
6
+
7
+ -- ---------------------------------------------------------------------------
8
+ -- trial_balance
9
+ -- ---------------------------------------------------------------------------
10
+
11
+ create or replace function trial_balance(
12
+ p_company_id uuid,
13
+ p_from date,
14
+ p_to date
15
+ )
16
+ returns table (
17
+ account_id uuid,
18
+ account_code text,
19
+ account_name text,
20
+ account_type account_type,
21
+ internal_group text,
22
+ opening_balance numeric,
23
+ debit numeric,
24
+ credit numeric,
25
+ closing_balance numeric
26
+ )
27
+ language sql
28
+ stable
29
+ as $$
30
+ select a.id,
31
+ a.code,
32
+ a.name,
33
+ a.account_type,
34
+ a.internal_group,
35
+ coalesce(sum(l.balance) filter (where e.entry_date < p_from), 0)::numeric as opening_balance,
36
+ coalesce(sum(l.debit) filter (where e.entry_date between p_from and p_to), 0)::numeric as debit,
37
+ coalesce(sum(l.credit) filter (where e.entry_date between p_from and p_to), 0)::numeric as credit,
38
+ coalesce(sum(l.balance) filter (where e.entry_date <= p_to), 0)::numeric as closing_balance
39
+ from accounts a
40
+ left join entry_lines l on l.account_id = a.id
41
+ left join entries e on e.id = l.entry_id and e.state = 'posted'
42
+ where a.company_id = p_company_id
43
+ -- Kill the outer-join leak: a line whose entry is not posted is dropped.
44
+ and (l.id is null or e.id is not null)
45
+ and (e.id is null or e.entry_date <= p_to)
46
+ group by a.id, a.code, a.name, a.account_type, a.internal_group
47
+ order by a.code;
48
+ $$;
49
+
50
+ comment on function trial_balance(uuid, date, date) is
51
+ 'Opening balance, movements of the period and closing balance per account, posted entries only.';
52
+
53
+ -- ---------------------------------------------------------------------------
54
+ -- general_ledger
55
+ -- ---------------------------------------------------------------------------
56
+
57
+ create or replace function general_ledger(
58
+ p_company_id uuid,
59
+ p_from date,
60
+ p_to date,
61
+ p_account_ids uuid[] default null
62
+ )
63
+ returns table (
64
+ account_id uuid,
65
+ account_code text,
66
+ account_name text,
67
+ entry_line_id uuid,
68
+ entry_id uuid,
69
+ entry_number text,
70
+ entry_date date,
71
+ journal_code text,
72
+ reference text,
73
+ line_name text,
74
+ contact_name text,
75
+ debit numeric,
76
+ credit numeric,
77
+ matching_number text,
78
+ running_balance numeric
79
+ )
80
+ language sql
81
+ stable
82
+ as $$
83
+ with opening as (
84
+ select l.account_id, sum(l.balance) as balance
85
+ from entry_lines l
86
+ join entries e on e.id = l.entry_id
87
+ where l.company_id = p_company_id
88
+ and e.state = 'posted'
89
+ and e.entry_date < p_from
90
+ group by l.account_id
91
+ ),
92
+ movements as (
93
+ select l.id, l.account_id, l.entry_id, e.number, e.entry_date, j.code as journal_code,
94
+ e.reference, l.name, c.name as contact_name, l.debit, l.credit, l.balance,
95
+ l.matching_number, l.sequence
96
+ from entry_lines l
97
+ join entries e on e.id = l.entry_id
98
+ join journals j on j.id = e.journal_id
99
+ left join contacts c on c.id = l.contact_id
100
+ where l.company_id = p_company_id
101
+ and e.state = 'posted'
102
+ and e.entry_date between p_from and p_to
103
+ )
104
+ select a.id, a.code, a.name,
105
+ m.id, m.entry_id, m.number, m.entry_date, m.journal_code, m.reference,
106
+ m.name, m.contact_name, m.debit, m.credit, m.matching_number,
107
+ (coalesce(o.balance, 0)
108
+ + sum(m.balance) over (partition by a.id
109
+ order by m.entry_date, m.number, m.sequence, m.id
110
+ rows between unbounded preceding and current row))::numeric
111
+ from movements m
112
+ join accounts a on a.id = m.account_id
113
+ left join opening o on o.account_id = a.id
114
+ where p_account_ids is null or a.id = any (p_account_ids)
115
+ order by a.code, m.entry_date, m.number, m.sequence, m.id;
116
+ $$;
117
+
118
+ comment on function general_ledger(uuid, date, date, uuid[]) is
119
+ 'Posted lines of a period per account, with the balance carried forward from before the period.';
120
+
121
+ -- ---------------------------------------------------------------------------
122
+ -- aged_balance
123
+ --
124
+ -- Read from the ledger and from what is still unmatched, not from documents.
125
+ -- An aged balance built on invoices can never tie back to the balance sheet.
126
+ -- ---------------------------------------------------------------------------
127
+
128
+ create or replace function aged_balance(
129
+ p_company_id uuid,
130
+ p_at date default current_date,
131
+ p_group text default 'receivable'
132
+ )
133
+ returns table (
134
+ contact_id uuid,
135
+ contact_name text,
136
+ account_id uuid,
137
+ account_code text,
138
+ not_due numeric,
139
+ days_1_30 numeric,
140
+ days_31_60 numeric,
141
+ days_61_90 numeric,
142
+ days_over_90 numeric,
143
+ total numeric
144
+ )
145
+ language sql
146
+ stable
147
+ as $$
148
+ with open_lines as (
149
+ select l.contact_id,
150
+ l.account_id,
151
+ case when p_group = 'payable' then -l.balance else l.balance end
152
+ * (case when abs(l.balance) = 0 then 0
153
+ else (abs(l.balance) - l.matched_amount) / abs(l.balance) end) as residual,
154
+ coalesce(l.date_maturity, e.entry_date) as due_date
155
+ from entry_lines l
156
+ join entries e on e.id = l.entry_id
157
+ join accounts a on a.id = l.account_id
158
+ where l.company_id = p_company_id
159
+ and e.state = 'posted'
160
+ and e.entry_date <= p_at
161
+ and a.reconcilable
162
+ and a.account_type = case when p_group = 'payable'
163
+ then 'liability_payable'::account_type
164
+ else 'asset_receivable'::account_type end
165
+ and abs(l.balance) - l.matched_amount > 0.005
166
+ )
167
+ select o.contact_id,
168
+ c.name,
169
+ o.account_id,
170
+ a.code,
171
+ round(sum(o.residual) filter (where o.due_date >= p_at), 2),
172
+ round(sum(o.residual) filter (where p_at - o.due_date between 1 and 30), 2),
173
+ round(sum(o.residual) filter (where p_at - o.due_date between 31 and 60), 2),
174
+ round(sum(o.residual) filter (where p_at - o.due_date between 61 and 90), 2),
175
+ round(sum(o.residual) filter (where p_at - o.due_date > 90), 2),
176
+ round(sum(o.residual), 2)
177
+ from open_lines o
178
+ left join contacts c on c.id = o.contact_id
179
+ join accounts a on a.id = o.account_id
180
+ group by o.contact_id, c.name, o.account_id, a.code
181
+ order by c.name nulls last;
182
+ $$;
183
+
184
+ comment on function aged_balance(uuid, date, text) is
185
+ 'Open receivables (or payables) by age, from unmatched ledger lines. p_group is ''receivable'' or ''payable''.';
186
+
187
+ -- ---------------------------------------------------------------------------
188
+ -- vat_return
189
+ --
190
+ -- Aggregates whatever the tax postings wrote on the lines. No country rule
191
+ -- lives here: boxes come from the data.
192
+ --
193
+ -- This function was published with the two balance boxes of the Belgian frame
194
+ -- VI computed inline, behind a test on the company's fiscal country. That was
195
+ -- the one country rule left in the core, and it was removed from this file on
196
+ -- 12 September 2026 rather than only overridden later: no installation
197
+ -- anywhere had run it, and a country literal in a published migration is a
198
+ -- country literal in the repository. The totals now come from the declaration
199
+ -- form of the country pack, in `20260912090407_tax_report_boxes`, which
200
+ -- replaces this function.
201
+ -- ---------------------------------------------------------------------------
202
+
203
+ create or replace function vat_return(
204
+ p_company_id uuid,
205
+ p_from date,
206
+ p_to date
207
+ )
208
+ returns table (
209
+ box text,
210
+ kind text,
211
+ amount numeric,
212
+ computed boolean
213
+ )
214
+ language sql
215
+ stable
216
+ as $$
217
+ with boxes as (
218
+ select l.declaration_box as box,
219
+ case when l.tax_line then 'tax' else 'base' end as kind,
220
+ round(sum(l.box_amount), 2) as amount
221
+ from entry_lines l
222
+ join entries e on e.id = l.entry_id
223
+ where l.company_id = p_company_id
224
+ and e.state = 'posted'
225
+ and e.entry_date between p_from and p_to
226
+ and l.declaration_box is not null
227
+ group by 1, 2
228
+ having round(sum(l.box_amount), 2) <> 0
229
+ )
230
+ select b.box, b.kind, b.amount, false from boxes b
231
+ order by 1, 2;
232
+ $$;
233
+
234
+ comment on function vat_return(uuid, date, date) is
235
+ 'VAT return boxes for a period, summed from the declaration boxes written on the ledger lines.';
@@ -0,0 +1,226 @@
1
+ -- Ekwo OS — country templates.
2
+ --
3
+ -- The chart of accounts, the journals and the taxes of a country are
4
+ -- reference data, not code. `install_country_template()` copies them into a
5
+ -- company. Seeds fill the templates; nothing here is country specific.
6
+
7
+ create table account_templates (
8
+ id uuid primary key default gen_random_uuid(),
9
+ country char(2) not null,
10
+ code text not null,
11
+ name text not null,
12
+ account_type account_type not null,
13
+ reconcilable boolean not null default false,
14
+ parent_code text,
15
+ sequence integer not null default 10,
16
+ unique (country, code),
17
+ constraint account_templates_country_format check (country ~ '^[A-Z]{2}$'),
18
+ constraint account_templates_third_party_reconcilable check (
19
+ account_type not in ('asset_receivable', 'liability_payable') or reconcilable
20
+ )
21
+ );
22
+
23
+ comment on table account_templates is 'Reference charts of accounts, one set per country.';
24
+
25
+ create table journal_templates (
26
+ id uuid primary key default gen_random_uuid(),
27
+ country char(2) not null,
28
+ code text not null,
29
+ name text not null,
30
+ journal_type journal_type not null,
31
+ sequence integer not null default 10,
32
+ unique (country, code)
33
+ );
34
+
35
+ create table tax_templates (
36
+ id uuid primary key default gen_random_uuid(),
37
+ country char(2) not null,
38
+ code text not null,
39
+ name text not null,
40
+ description text,
41
+ amount_type tax_amount_type not null default 'percent',
42
+ amount numeric(12, 4) not null default 0,
43
+ applies_to tax_scope not null default 'both',
44
+ treatment tax_treatment not null default 'domestic',
45
+ valid_from date not null default date '1970-01-01',
46
+ valid_to date,
47
+ legal_reference text,
48
+ vat_category char(2),
49
+ exemption_code text,
50
+ sequence integer not null default 10,
51
+ unique (country, code)
52
+ );
53
+
54
+ comment on table tax_templates is 'Reference taxes per country, with their period of validity.';
55
+
56
+ create table tax_posting_templates (
57
+ id uuid primary key default gen_random_uuid(),
58
+ tax_template_id uuid not null references tax_templates(id) on delete cascade,
59
+ document_kind tax_document_kind not null default 'invoice',
60
+ posting_type tax_posting_type not null,
61
+ factor_percent numeric(7, 3) not null default 100,
62
+ account_code text,
63
+ declaration_box text,
64
+ box_factor_percent numeric(7, 3) not null default 100,
65
+ sequence integer not null default 10,
66
+ constraint tax_posting_templates_base_has_no_account check (
67
+ posting_type <> 'base' or account_code is null
68
+ ),
69
+ constraint tax_posting_templates_tax_has_account check (
70
+ posting_type <> 'tax' or account_code is not null
71
+ )
72
+ );
73
+
74
+ create unique index tax_posting_templates_one_base_idx
75
+ on tax_posting_templates (tax_template_id, document_kind) where posting_type = 'base';
76
+
77
+ create table country_defaults (
78
+ country char(2) primary key,
79
+ name text not null,
80
+ currency_code char(3) not null default 'EUR',
81
+ receivable_code text not null,
82
+ payable_code text not null,
83
+ suspense_code text,
84
+ rounding_code text,
85
+ retained_earnings_code text,
86
+ sales_account_code text,
87
+ purchase_account_code text,
88
+ bank_account_code text,
89
+ sales_journal_code text not null default 'SAL',
90
+ purchase_journal_code text not null default 'PUR',
91
+ misc_journal_code text not null default 'MISC'
92
+ );
93
+
94
+ comment on table country_defaults is 'Which template account plays which role, per country.';
95
+
96
+ -- ---------------------------------------------------------------------------
97
+ -- Helpers
98
+ -- ---------------------------------------------------------------------------
99
+
100
+ create or replace function account_id_by_code(p_company_id uuid, p_code text)
101
+ returns uuid
102
+ language sql
103
+ stable
104
+ as $$
105
+ select id from accounts where company_id = p_company_id and code = p_code;
106
+ $$;
107
+
108
+ comment on function account_id_by_code(uuid, text) is 'Account of a company by its code, or NULL.';
109
+
110
+ -- ---------------------------------------------------------------------------
111
+ -- install_country_template
112
+ -- ---------------------------------------------------------------------------
113
+
114
+ create or replace function install_country_template(
115
+ p_company_id uuid,
116
+ p_country char(2)
117
+ )
118
+ returns void
119
+ language plpgsql
120
+ as $$
121
+ declare
122
+ v_defaults country_defaults%rowtype;
123
+ r record;
124
+ v_tax_id uuid;
125
+ begin
126
+ if not exists (select 1 from companies where id = p_company_id) then
127
+ raise exception 'unknown_company: %', p_company_id;
128
+ end if;
129
+ if not exists (select 1 from account_templates where country = p_country) then
130
+ raise exception 'unknown_country_template: no chart of accounts seeded for %', p_country;
131
+ end if;
132
+
133
+ -- 1. Accounts, without the hierarchy.
134
+ insert into accounts (company_id, code, name, account_type, reconcilable)
135
+ select p_company_id, t.code, t.name, t.account_type, t.reconcilable
136
+ from account_templates t
137
+ where t.country = p_country
138
+ on conflict (company_id, code) do nothing;
139
+
140
+ -- 2. Hierarchy, now that every code exists.
141
+ update accounts a
142
+ set parent_id = p.id
143
+ from account_templates t
144
+ join accounts p on p.company_id = p_company_id and p.code = t.parent_code
145
+ where a.company_id = p_company_id
146
+ and a.code = t.code
147
+ and t.country = p_country
148
+ and t.parent_code is not null
149
+ and a.parent_id is null;
150
+
151
+ -- 3. Journals.
152
+ insert into journals (company_id, code, name, journal_type)
153
+ select p_company_id, t.code, t.name, t.journal_type
154
+ from journal_templates t
155
+ where t.country = p_country
156
+ on conflict (company_id, code) do nothing;
157
+
158
+ -- 4. Taxes and their postings.
159
+ for r in
160
+ select * from tax_templates where country = p_country order by sequence, code
161
+ loop
162
+ v_tax_id := null;
163
+ insert into taxes (company_id, code, name, description, amount_type, amount,
164
+ applies_to, treatment, country, valid_from, valid_to,
165
+ legal_reference, vat_category, exemption_code, sequence)
166
+ values (p_company_id, r.code, r.name, r.description, r.amount_type, r.amount,
167
+ r.applies_to, r.treatment, p_country, r.valid_from, r.valid_to,
168
+ r.legal_reference, r.vat_category, r.exemption_code, r.sequence)
169
+ on conflict (company_id, code) do nothing
170
+ returning id into v_tax_id;
171
+
172
+ if v_tax_id is null then
173
+ continue;
174
+ end if;
175
+
176
+ insert into tax_postings (tax_id, company_id, document_kind, posting_type,
177
+ factor_percent, account_id, declaration_box,
178
+ box_factor_percent, sequence)
179
+ select v_tax_id, p_company_id, tp.document_kind, tp.posting_type,
180
+ tp.factor_percent, account_id_by_code(p_company_id, tp.account_code),
181
+ tp.declaration_box, tp.box_factor_percent, tp.sequence
182
+ from tax_posting_templates tp
183
+ where tp.tax_template_id = r.id
184
+ order by tp.sequence;
185
+ end loop;
186
+
187
+ -- 5. Roles.
188
+ select * into v_defaults from country_defaults where country = p_country;
189
+ if found then
190
+ update companies c
191
+ set receivable_account_id = coalesce(c.receivable_account_id, account_id_by_code(p_company_id, v_defaults.receivable_code)),
192
+ payable_account_id = coalesce(c.payable_account_id, account_id_by_code(p_company_id, v_defaults.payable_code)),
193
+ suspense_account_id = coalesce(c.suspense_account_id, account_id_by_code(p_company_id, v_defaults.suspense_code)),
194
+ rounding_account_id = coalesce(c.rounding_account_id, account_id_by_code(p_company_id, v_defaults.rounding_code)),
195
+ retained_earnings_account_id = coalesce(c.retained_earnings_account_id, account_id_by_code(p_company_id, v_defaults.retained_earnings_code)),
196
+ sales_journal_id = coalesce(c.sales_journal_id, (select id from journals where company_id = p_company_id and code = v_defaults.sales_journal_code)),
197
+ purchase_journal_id = coalesce(c.purchase_journal_id, (select id from journals where company_id = p_company_id and code = v_defaults.purchase_journal_code)),
198
+ miscellaneous_journal_id = coalesce(c.miscellaneous_journal_id, (select id from journals where company_id = p_company_id and code = v_defaults.misc_journal_code))
199
+ where c.id = p_company_id;
200
+ end if;
201
+ end;
202
+ $$;
203
+
204
+ comment on function install_country_template(uuid, char) is
205
+ 'Copies a country chart of accounts, journals and taxes into a company and wires the default roles.';
206
+
207
+ -- ---------------------------------------------------------------------------
208
+ -- Row level security
209
+ -- ---------------------------------------------------------------------------
210
+
211
+ alter table account_templates enable row level security;
212
+ alter table journal_templates enable row level security;
213
+ alter table tax_templates enable row level security;
214
+ alter table tax_posting_templates enable row level security;
215
+ alter table country_defaults enable row level security;
216
+
217
+ create policy account_templates_select on account_templates
218
+ for select using (auth.uid() is not null);
219
+ create policy journal_templates_select on journal_templates
220
+ for select using (auth.uid() is not null);
221
+ create policy tax_templates_select on tax_templates
222
+ for select using (auth.uid() is not null);
223
+ create policy tax_posting_templates_select on tax_posting_templates
224
+ for select using (auth.uid() is not null);
225
+ create policy country_defaults_select on country_defaults
226
+ for select using (auth.uid() is not null);
@@ -0,0 +1,71 @@
1
+ -- Ekwo OS — the French FEC, as a query.
2
+ --
3
+ -- Eighteen columns fixed by the arrete du 29 juillet 2013 (art. A. 47 A-1 du
4
+ -- LPF). The schema was shaped so this needs no application logic: the letter
5
+ -- comes from `reconciliations`, the sub-ledger code from
6
+ -- `contacts.auxiliary_code`, the validation date from `entries.posted_at`.
7
+
8
+ create or replace function fec_lines(
9
+ p_company_id uuid,
10
+ p_from date,
11
+ p_to date
12
+ )
13
+ returns table (
14
+ journal_code text,
15
+ journal_lib text,
16
+ ecriture_num text,
17
+ ecriture_date date,
18
+ compte_num text,
19
+ compte_lib text,
20
+ comp_aux_num text,
21
+ comp_aux_lib text,
22
+ piece_ref text,
23
+ piece_date date,
24
+ ecriture_lib text,
25
+ debit numeric,
26
+ credit numeric,
27
+ ecriture_let text,
28
+ date_let date,
29
+ valid_date date,
30
+ montant_devise numeric,
31
+ idevise text
32
+ )
33
+ language sql
34
+ stable
35
+ as $$
36
+ select j.code,
37
+ j.name,
38
+ e.number,
39
+ e.entry_date,
40
+ a.code,
41
+ a.name,
42
+ c.auxiliary_code,
43
+ case when c.auxiliary_code is not null then c.name end,
44
+ coalesce(d.number, d.supplier_reference, e.reference, e.number),
45
+ coalesce(d.document_date, e.entry_date),
46
+ coalesce(nullif(l.name, ''), e.description, a.name),
47
+ l.debit,
48
+ l.credit,
49
+ l.matching_number,
50
+ (select max(r.matched_at) from reconciliations r
51
+ where r.debit_line_id = l.id or r.credit_line_id = l.id),
52
+ coalesce(e.posted_at::date, e.entry_date),
53
+ case when l.currency_code is not null and l.currency_code <> co.currency_code
54
+ then l.amount_currency end,
55
+ case when l.currency_code is not null and l.currency_code <> co.currency_code
56
+ then l.currency_code end
57
+ from entry_lines l
58
+ join entries e on e.id = l.entry_id
59
+ join journals j on j.id = e.journal_id
60
+ join accounts a on a.id = l.account_id
61
+ join companies co on co.id = l.company_id
62
+ left join contacts c on c.id = l.contact_id
63
+ left join documents d on d.id = e.document_id
64
+ where l.company_id = p_company_id
65
+ and e.state = 'posted'
66
+ and e.entry_date between p_from and p_to
67
+ order by e.entry_date, e.number, l.sequence, l.id;
68
+ $$;
69
+
70
+ comment on function fec_lines(uuid, date, date) is
71
+ 'The eighteen columns of the French FEC for a period, in chronological order.';
@@ -0,0 +1,77 @@
1
+ -- Ekwo OS — the instance itself.
2
+ --
3
+ -- One installation belongs to one customer, so the installation is a fact
4
+ -- worth recording: who it belongs to, which country's rules it was set up
5
+ -- for, which edition it runs, and which schema version it was installed at.
6
+ -- Exactly one row, forever. There is no `tenant_id` anywhere in this schema
7
+ -- and this table is the reason: the instance IS the tenant.
8
+ --
9
+ -- Registration with Ekwo is an opt-in. `contact_email` and `registered_at`
10
+ -- are empty on a fresh install, nothing writes them without the operator
11
+ -- asking, and nothing in the software checks them. Community works
12
+ -- unregistered, forever.
13
+
14
+ -- The instance-level role. A new enum value cannot be used in the same
15
+ -- transaction that adds it, so the table that constrains it lives in the
16
+ -- next migration.
17
+ alter type member_role add value if not exists 'instance_admin';
18
+
19
+ create type instance_edition as enum ('community', 'cloud');
20
+
21
+ -- The schema version this release ships. Bumped by a migration at each
22
+ -- release; `ekwo migrate` writes it back onto the instance row.
23
+ create or replace function ekwo_schema_version()
24
+ returns text
25
+ language sql
26
+ immutable
27
+ as $$
28
+ select '0.1.0'::text;
29
+ $$;
30
+
31
+ comment on function ekwo_schema_version() is
32
+ 'Schema version of the installed release. Bumped by a migration, never by hand.';
33
+
34
+ create table instance (
35
+ -- Singleton. The primary key and the check together make a second row
36
+ -- impossible, rather than merely unusual.
37
+ id smallint primary key default 1,
38
+ instance_id uuid not null unique default gen_random_uuid(),
39
+ organization_name text not null,
40
+ country char(2) not null,
41
+ edition instance_edition not null default 'community',
42
+ schema_version text not null default ekwo_schema_version(),
43
+ installed_at timestamptz not null default now(),
44
+ -- Opt-in registration with Ekwo. Empty by default, never a condition of
45
+ -- use, never checked by anything in this repository.
46
+ contact_email text,
47
+ registered_at timestamptz,
48
+ updated_at timestamptz not null default now(),
49
+ constraint instance_singleton check (id = 1),
50
+ constraint instance_country_format check (country ~ '^[A-Z]{2}$'),
51
+ constraint instance_registration_needs_an_address check (
52
+ registered_at is null or contact_email is not null
53
+ )
54
+ );
55
+
56
+ comment on table instance is
57
+ 'The installation itself. Exactly one row. Registration with Ekwo is optional and empty by default.';
58
+ comment on column instance.instance_id is
59
+ 'Stable identifier of this installation, generated locally. Never a licence key.';
60
+ comment on column instance.edition is
61
+ 'community when you run it yourself, cloud when Ekwo operates it. Gates nothing in this repository.';
62
+ comment on column instance.schema_version is
63
+ 'Version of the schema at install, updated by migrations.';
64
+ comment on column instance.contact_email is
65
+ 'Opt-in only: an address to reach the operator. Empty unless they asked to register.';
66
+ comment on column instance.registered_at is
67
+ 'Opt-in only: when the operator registered with Ekwo. Empty means not registered, which is a supported state.';
68
+
69
+ create trigger instance_set_updated_at
70
+ before update on instance
71
+ for each row execute function set_updated_at();
72
+
73
+ alter table instance enable row level security;
74
+
75
+ -- Anyone signed into this installation may see which installation it is.
76
+ create policy instance_select on instance
77
+ for select using (auth.uid() is not null);