@fayz-ai/db 0.13.0 → 0.14.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 (187) hide show
  1. package/canonical-schema.json +106 -23
  2. package/dist/index.cjs +4 -4
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -4
  7. package/dist/index.js.map +1 -1
  8. package/dist/schema/spine.d.ts +42 -37
  9. package/dist/schema/spine.d.ts.map +1 -1
  10. package/migrations/000_baseline.sql +29667 -0
  11. package/migrations/001_the_tenant_has_apps.sql +314 -0
  12. package/migrations/002_the_spine_drops_the_vendor_and_the_dead.sql +129 -0
  13. package/migrations/003_the_role_rpcs_finish_and_the_mirrors_go.sql +135 -0
  14. package/migrations/004_the_projections_get_a_successor.sql +312 -0
  15. package/migrations/005_the_archetypes_anchor_to_the_unit.sql +90 -0
  16. package/migrations/006_the_helpers_read_the_source.sql +153 -0
  17. package/migrations/007_the_compat_machinery_leaves_with_the_tables.sql +77 -0
  18. package/migrations/008_the_switchers_see_across_accounts.sql +150 -0
  19. package/migrations/009_the_compat_aliases_nobody_adopted.sql +57 -0
  20. package/migrations/010_the_new_tenant_is_born_with_its_trade.sql +201 -0
  21. package/migrations/011_leadcontrol_joins_the_family.sql +116 -0
  22. package/migrations/012_chefcontrol_wears_its_own_mark.sql +28 -0
  23. package/migrations/013_the_workspace_switch_reaches_the_other_half.sql +156 -0
  24. package/migrations/014_the_chooser_can_read_what_it_offers.sql +91 -0
  25. package/migrations/015_the_unit_bindings_belong_to_one_workspace.sql +86 -0
  26. package/migrations/016_the_rule_stops_asking_every_row.sql +543 -0
  27. package/migrations/017_the_pin_is_checked_against_the_right_workspace.sql +139 -0
  28. package/migrations/018_the_bootstrap_says_what_you_reach.sql +114 -0
  29. package/migrations/019_distributing_one_row_stops_costing_the_table.sql +245 -0
  30. package/migrations/020_the_agenda_asks_where_someone_works.sql +81 -0
  31. package/migrations/022_the_line_says_which_document_it_belongs_to.sql +109 -0
  32. package/package.json +1 -1
  33. package/migrations/0000_legacy_quarantine.sql +0 -86
  34. package/migrations/0000b_straggler_sweep.sql +0 -37
  35. package/migrations/000_core_v1_convert.sql +0 -343
  36. package/migrations/001_core.sql +0 -372
  37. package/migrations/002_rls_user_tenant_ids.sql +0 -64
  38. package/migrations/003_invitations.sql +0 -17
  39. package/migrations/004_archetypes.sql +0 -343
  40. package/migrations/005_locations_archetype.sql +0 -18
  41. package/migrations/006_archetype_rls.sql +0 -74
  42. package/migrations/007_archetype_grants.sql +0 -4
  43. package/migrations/008_grants.sql +0 -5
  44. package/migrations/009_anon_hardening.sql +0 -19
  45. package/migrations/010_migration_ledger.sql +0 -46
  46. package/migrations/011_anon_write_revoke.sql +0 -12
  47. package/migrations/012_rename_migration_ledger.sql +0 -61
  48. package/migrations/013_sequences_rls.sql +0 -22
  49. package/migrations/014_plan_entitlements.sql +0 -28
  50. package/migrations/015_agent_guard.sql +0 -108
  51. package/migrations/016_agent_guard_actor.sql +0 -102
  52. package/migrations/017_core_addresses.sql +0 -115
  53. package/migrations/018_global_search.sql +0 -482
  54. package/migrations/019_tenant_members_person_id.sql +0 -20
  55. package/migrations/020_fayz_projects.sql +0 -63
  56. package/migrations/021_tenant_roles.sql +0 -74
  57. package/migrations/022_invite_acceptance.sql +0 -91
  58. package/migrations/023_team_visibility.sql +0 -75
  59. package/migrations/024_analytics_engine.sql +0 -317
  60. package/migrations/025_created_by.sql +0 -75
  61. package/migrations/026_audit_trail.sql +0 -73
  62. package/migrations/027_domain_events.sql +0 -266
  63. package/migrations/028_tenant_scoped_token.sql +0 -127
  64. package/migrations/029_connections.sql +0 -186
  65. package/migrations/030_effect_idempotency.sql +0 -159
  66. package/migrations/031_sync_run_message.sql +0 -39
  67. package/migrations/032_connection_secrets.sql +0 -227
  68. package/migrations/033_sync_schedule.sql +0 -651
  69. package/migrations/034_custom_fields.sql +0 -55
  70. package/migrations/035_field_registry.sql +0 -148
  71. package/migrations/036_analytics_run_batch.sql +0 -84
  72. package/migrations/037_sync_tick_one_at_a_time.sql +0 -256
  73. package/migrations/038_onboarding_responses.sql +0 -103
  74. package/migrations/039_unit_tree.sql +0 -270
  75. package/migrations/040_resource_grants.sql +0 -474
  76. package/migrations/041_scoped_columns.sql +0 -192
  77. package/migrations/042_unit_scope_policies.sql +0 -145
  78. package/migrations/043_view_invoker.sql +0 -90
  79. package/migrations/044_unit_member_facts.sql +0 -47
  80. package/migrations/045_unit_entry.sql +0 -236
  81. package/migrations/046_membership_visible_to_members.sql +0 -85
  82. package/migrations/047_tasks.sql +0 -266
  83. package/migrations/048_every_login_is_a_person.sql +0 -190
  84. package/migrations/049_bookable_people.sql +0 -126
  85. package/migrations/050_authz_core.sql +0 -230
  86. package/migrations/051_authz_helpers.sql +0 -330
  87. package/migrations/052_authz_fanout.sql +0 -253
  88. package/migrations/053_authz_catalog_templates.sql +0 -402
  89. package/migrations/060_tenancy_seam.sql +0 -132
  90. package/migrations/061_create_tenant.sql +0 -125
  91. package/migrations/062_invitations.sql +0 -329
  92. package/migrations/063_legacy_tenancy_retired.sql +0 -568
  93. package/migrations/064_agent_guard_authz.sql +0 -118
  94. package/migrations/064b_supersede_unit_scope.sql +0 -205
  95. package/migrations/065_scaffold_sweep.sql +0 -139
  96. package/migrations/066_shadow_report.sql +0 -122
  97. package/migrations/070_permission_catalog.sql +0 -205
  98. package/migrations/071_v1_permission_map.sql +0 -266
  99. package/migrations/072_role_rpcs.sql +0 -126
  100. package/migrations/073_legacy_rbac_retire.sql +0 -471
  101. package/migrations/075_company_legal_entities.sql +0 -169
  102. package/migrations/076_tenant_settings.sql +0 -251
  103. package/migrations/080_people_roles.sql +0 -269
  104. package/migrations/081_people_identity.sql +0 -271
  105. package/migrations/082_people_membership_link.sql +0 -142
  106. package/migrations/083_people_data_migration.sql +0 -75
  107. package/migrations/084_people_registrations_tokens.sql +0 -282
  108. package/migrations/085_catalog_products.sql +0 -333
  109. package/migrations/086_catalog_pricing.sql +0 -194
  110. package/migrations/087_catalog_packages.sql +0 -134
  111. package/migrations/090_orders_venda.sql +0 -166
  112. package/migrations/091_orders_scaffold.sql +0 -92
  113. package/migrations/095_config_field_rules.sql +0 -261
  114. package/migrations/096_audit_append_only.sql +0 -256
  115. package/migrations/097_sequences_authorized.sql +0 -111
  116. package/migrations/098_holidays.sql +0 -80
  117. package/migrations/099_access_grants.sql +0 -293
  118. package/migrations/100_migration_schema.sql +0 -217
  119. package/migrations/101_migration_allowlist.sql +0 -202
  120. package/migrations/102_migration_rpcs.sql +0 -933
  121. package/migrations/103_migration_reconcile_ponr.sql +0 -132
  122. package/migrations/105_policies_to_authenticated.sql +0 -71
  123. package/migrations/106_function_search_path.sql +0 -55
  124. package/migrations/107_core_table_prefix.sql +0 -361
  125. package/migrations/108_authz_write_guards.sql +0 -149
  126. package/migrations/109_catalog_migration_promoted_columns.sql +0 -126
  127. package/migrations/110_people_kind_vocabulary.sql +0 -120
  128. package/migrations/111_migration_excluded_is_a_decision.sql +0 -259
  129. package/migrations/111_replacing_a_view_keeps_its_dependents.sql +0 -132
  130. package/migrations/112_money_precision_standard.sql +0 -132
  131. package/migrations/113_addresses_units_companies.sql +0 -114
  132. package/migrations/114_migrations_ledger_immutable.sql +0 -65
  133. package/migrations/115_registration_honours_field_rules.sql +0 -172
  134. package/migrations/116_field_rules_check_needs_a_tenant.sql +0 -72
  135. package/migrations/117_authz_reconciliation_schedule.sql +0 -82
  136. package/migrations/118_migration_catalog_writers.sql +0 -450
  137. package/migrations/119_migration_config_writers.sql +0 -193
  138. package/migrations/120_migration_facet_writer.sql +0 -139
  139. package/migrations/121_migration_financial_writers.sql +0 -294
  140. package/migrations/122_migration_inventory_writers.sql +0 -245
  141. package/migrations/123_migration_order_item_writer.sql +0 -144
  142. package/migrations/124_migration_ledger_writers.sql +0 -170
  143. package/migrations/125_migration_authz_people_writers.sql +0 -205
  144. package/migrations/126_owner_scoping_is_configuration.sql +0 -247
  145. package/migrations/127_scaffold_audit_hook.sql +0 -98
  146. package/migrations/128_shadow_tables_enforced.sql +0 -93
  147. package/migrations/129_order_kind_terminal_states.sql +0 -57
  148. package/migrations/130_every_login_is_a_person.sql +0 -196
  149. package/migrations/131_migration_invoice_split.sql +0 -127
  150. package/migrations/132_audit_prune_scheduled.sql +0 -28
  151. package/migrations/133_unit_is_a_session_property.sql +0 -155
  152. package/migrations/134_field_rules_on_read.sql +0 -341
  153. package/migrations/135_distribution_polarity.sql +0 -158
  154. package/migrations/136_unit_id_means_locality.sql +0 -358
  155. package/migrations/137_vendor_named_spine_objects.sql +0 -126
  156. package/migrations/138_grants_inherit_down_the_tree.sql +0 -178
  157. package/migrations/139_distributable_is_a_scaffold_option.sql +0 -109
  158. package/migrations/140_masking_is_a_scaffold_option.sql +0 -85
  159. package/migrations/141_renamed_objects_keep_a_compat_name.sql +0 -192
  160. package/migrations/142_a_person_has_addresses.sql +0 -212
  161. package/migrations/143_a_professional_has_a_rate.sql +0 -75
  162. package/migrations/144_a_product_can_be_sold_in_sizes.sql +0 -57
  163. package/migrations/145_the_app_says_which_tenant_it_is_in.sql +0 -123
  164. package/migrations/146_products_stock_has_one_writer.sql +0 -67
  165. package/migrations/147_every_archetype_has_a_kind_registry.sql +0 -388
  166. package/migrations/148_the_legacy_archetype_stops_being_writable.sql +0 -154
  167. package/migrations/149_the_event_log_gets_a_consumer.sql +0 -331
  168. package/migrations/150_the_app_is_configured_in_the_database.sql +0 -285
  169. package/migrations/151_stock_balance_is_an_archetype.sql +0 -144
  170. package/migrations/152_a_file_is_an_archetype.sql +0 -222
  171. package/migrations/153_a_plugin_calls_a_service_through_one_door.sql +0 -199
  172. package/migrations/154_the_plan_is_a_ceiling.sql +0 -258
  173. package/migrations/155_a_tenant_can_leave.sql +0 -271
  174. package/migrations/156_the_service_door_has_a_server_side.sql +0 -335
  175. package/migrations/157_nobody_creates_objects_in_public.sql +0 -74
  176. package/migrations/158_the_registry_owns_the_status_vocabulary.sql +0 -153
  177. package/migrations/159_the_plan_catalogue_gets_its_first_rows.sql +0 -132
  178. package/migrations/160_the_vertical_decides_what_starts_on.sql +0 -246
  179. package/migrations/161_a_tenant_leaves_with_its_data.sql +0 -363
  180. package/migrations/162_every_name_has_one_creator_for_real.sql +0 -126
  181. package/migrations/163_a_species_nobody_declared_goes_to_quarantine.sql +0 -184
  182. package/migrations/164_the_sequence_table_joins_the_register.sql +0 -26
  183. package/migrations/165_a_view_is_not_a_way_in.sql +0 -90
  184. package/migrations/166_the_platform_billing_leftovers_go.sql +0 -72
  185. package/migrations/167_a_view_gets_back_what_its_table_grants.sql +0 -112
  186. package/migrations/168_the_grant_census_stops_crying_wolf.sql +0 -33
  187. package/migrations/169_the_census_asks_postgres_instead_of_guessing.sql +0 -45
@@ -1,202 +0,0 @@
1
- -- ============================================================================
2
- -- 101_migration_allowlist.sql — the frozen core-A extraction allowlist
3
- -- (core-beauty-chef.md §3.1) and the tables the extractor must never send.
4
- --
5
- -- Data every destination needs, so it is a migration, not a seed. Rows are
6
- -- frozen: changing one is a new migration file, not an UPDATE (the trigger of
7
- -- 090 refuses writes unless the session unlocks, as this file does).
8
- --
9
- -- Column maps: "target_col" copies, "target_col@source_table" resolves a V1
10
- -- reference through the ledger (unresolved ⇒ quarantine 'fk'), "jsonb:a.b"
11
- -- lands in the destination row's metadata (vertical data, ADR 0009), "-" is
12
- -- dropped on purpose (documented minimisation, PRD 03 R7). Maps for tables
13
- -- without a writer are coarse: the notable columns and where they go; the
14
- -- domain slice that ships the destination completes them with its writer.
15
- -- ============================================================================
16
-
17
- SELECT set_config('migration.allowlist_unlock', 'on', false);
18
-
19
- CREATE OR REPLACE FUNCTION migration._allow(
20
- p_source text, p_target text, p_domain text, p_writer text, p_writer_args jsonb,
21
- p_financial text[], p_columns jsonb, p_notes text
22
- ) RETURNS void LANGUAGE sql SECURITY DEFINER SET search_path = '' AS $$
23
- INSERT INTO migration.allowlist (source_table, target_table, layer, domain, columns, writer, writer_args, financial_columns, frozen, notes)
24
- VALUES (p_source, p_target, 'core-A', p_domain, coalesce(p_columns, '{}'::jsonb), p_writer, coalesce(p_writer_args, '{}'::jsonb), coalesce(p_financial, '{}'), true, p_notes)
25
- ON CONFLICT (source_table) DO UPDATE
26
- SET target_table = EXCLUDED.target_table, layer = EXCLUDED.layer, domain = EXCLUDED.domain, columns = EXCLUDED.columns,
27
- writer = EXCLUDED.writer, writer_args = EXCLUDED.writer_args, financial_columns = EXCLUDED.financial_columns,
28
- frozen = true, notes = EXCLUDED.notes;
29
- $$;
30
- REVOKE ALL ON FUNCTION migration._allow(text, text, text, text, jsonb, text[], jsonb, text) FROM public, anon, authenticated;
31
-
32
- -- ── licence / tenant / unit ─────────────────────────────────────────────
33
- SELECT migration._allow('licenses', 'public.tenants', 'tenancy', NULL, '{}',
34
- '{}', '{"uuid":"id","name":"name","slug":"slug","plan":"jsonb:migration.v1_plan","active":"jsonb:migration.v1_active","max_users":"jsonb:migration.v1_max_users","software_profile_id":"jsonb:migration.v1_software_profile_id","time_clock_enabled":"-"}',
35
- 'ADR 0002: a licence is a tenant (kind business; network when general_settings.company_type = franquia). The tenant is provisioned by a human before batch_open; this row documents the map, the destination does not create tenants.');
36
- SELECT migration._allow('licenses_admin', 'public.tenants', 'tenancy', NULL, '{}', '{}', '{"license_id":"jsonb:migration.license_id"}',
37
- 'Platform-admin view of licences: tenant settings/plan metadata; no writer.');
38
- SELECT migration._allow('license_users', 'app.memberships', 'tenancy', NULL, '{}', '{}',
39
- '{"uuid":"id","license_id":"tenant_id","user_id":"user_id","role":"role_id","email":"-","active":"active"}',
40
- 'A membership needs an auth.users row the destination cannot mint for a real login: the human invites (transactional invite RPC, #134); role mapped via the permission catalog (#136).');
41
- SELECT migration._allow('profiles', 'public.people', 'tenancy', NULL, '{}', '{}', '{"id":"-","full_name":"name","email":"email","avatar_url":"avatar_url"}',
42
- 'Login profile: folded into the Person of the member (memberships.person_id, PRD 03 R3); no writer.');
43
- SELECT migration._allow('modules', 'public.tenants', 'tenancy', NULL, '{}', '{}', '{"code":"jsonb:modules"}', 'PRD 02 R3: modules become tenant configuration (enabled plugins), not a table.');
44
- SELECT migration._allow('software_profiles', 'public.tenants', 'tenancy', NULL, '{}', '{}', '{"name":"jsonb:software_profile"}', 'PRD 02 R3: software profile → tenant configuration.');
45
- SELECT migration._allow('software_profile_modules', 'public.tenants', 'tenancy', NULL, '{}', '{}', '{}', 'PRD 02 R3: profile × module → tenant configuration.');
46
- SELECT migration._allow('tenant_domains', 'public.tenants', 'tenancy', NULL, '{}', '{}', '{"domain":"jsonb:branding.domain","logo_url":"jsonb:branding.logo_url"}', 'PRD 02 R5: branding/domain into tenant settings; login must survive a branding failure.');
47
- SELECT migration._allow('companies', 'app.units', 'tenancy', 'unit', '{"default_kind":"branch"}', '{}',
48
- '{"uuid":"id","tenant_id":"-","legal_name":"name","trade_name":"jsonb:trade_name","abbreviation":"jsonb:abbreviation","is_headquarters":"kind","active":"active","cnpj":"jsonb:legal.cnpj","location_group_id":"parent_unit_id@location_groups","address":"jsonb:address.street","address_number":"jsonb:address.number","address_complement":"jsonb:address.complement","neighborhood":"jsonb:address.neighborhood","city":"jsonb:address.city","state":"jsonb:address.state","postal_code":"jsonb:address.postal_code","phone_1":"jsonb:contact.phone_1","phone_2":"jsonb:contact.phone_2","mobile_1":"jsonb:contact.mobile_1","email_1":"jsonb:contact.email_1","whatsapp_number":"jsonb:contact.whatsapp","timezone":"jsonb:timezone","logo_url":"jsonb:branding.logo_url","brand_colors":"jsonb:branding.colors","certificate_cn":"-","certificate_plugnotas_id":"-","dfe_sync_cursor":"-","dfe_last_sync_at":"-"}',
49
- 'ADR 0002 / PRD 02 R1: a company is a unit (is_headquarters → hq, else branch). CNPJ/legal data go to the legal entity (Empresa, #138) — kept in metadata.legal until that writer exists. A second hq in a tenant is a state quarantine, never a silent demotion.');
50
- SELECT migration._allow('service_locations', 'app.units', 'tenancy', NULL, '{}', '{}', '{"uuid":"id","company_id":"unit_id@companies","name":"jsonb:name"}',
51
- 'PRD 02 R1: a service location is a place INSIDE a unit, not a unit — extension of the owning plugin in Phase 2; recorded pending until then.');
52
- SELECT migration._allow('location_groups', 'app.units', 'tenancy', 'unit', '{"default_kind":"branch","grouping":true}', '{}',
53
- '{"uuid":"id","tenant_id":"-","name":"name","description":"jsonb:description","active":"active"}',
54
- 'PRD 02 R1: a location group is a parent unit (franchisee/region); companies point at it through parent_unit_id.');
55
-
56
- -- ── permissions ─────────────────────────────────────────────────────────
57
- SELECT migration._allow('system_permissions', 'app.permissions', 'authz', NULL, '{}', '{}', '{"code":"key"}', '#136: only the 83 enforced codes map to {plugin}.{action} keys; the catalog is seeded by migrations, not migrated row by row.');
58
- SELECT migration._allow('permission_rules', 'app.roles', 'authz', NULL, '{}', '{}', '{"uuid":"id","name":"name"}', '#136: a rule is a tenant role.');
59
- SELECT migration._allow('permission_rule_details', 'app.role_permissions', 'authz', NULL, '{}', '{}', '{"rule_id":"role_id@permission_rules","permission_code":"permission"}', '#136: rule × permission → role_permissions.');
60
- SELECT migration._allow('employee_permission_rules', 'app.memberships', 'authz', NULL, '{}', '{}', '{"employee_id":"person_id@employees","rule_id":"role_id@permission_rules"}', 'Role of the employee member; through the Person of the employee (PRD 03 R3).');
61
- SELECT migration._allow('professional_permission_rules', 'app.memberships', 'authz', NULL, '{}', '{}', '{"professional_id":"person_id@professionals","rule_id":"role_id@permission_rules"}', 'Role of the professional member; through the Person of the professional.');
62
-
63
- -- ── base configuration ──────────────────────────────────────────────────
64
- SELECT migration._allow('general_settings', 'public.tenants', 'config', NULL,
65
- '{"by_key":true,"never":["permissions_enforcement_enabled"],"later_phase":["attendance_step_order","pos_stock_deduction_enabled","client_menu_config"]}', '{}',
66
- '{"setting_key":"jsonb:settings.<key>","setting_value":"jsonb:settings.<key>","category":"-","display_name":"-","options":"-"}',
67
- 'PRD 02 R4 (default g): migrated BY KEY, never as a table. Core keys → tenants.settings; vertical keys → the owning plugin; permissions_enforcement_enabled never (RLS is the law); beauty/chef keys wait for phases 3/4.');
68
- SELECT migration._allow('required_field_rules', 'config.field_rules', 'config', NULL, '{}', '{}', '{"context":"context","entity":"entity","field_key":"field_key","visibility":"state"}', 'PRD 07 / #144: 3-state FieldRules per context; the config slice owns the destination table name.');
69
- SELECT migration._allow('field_visibility_rules', 'config.field_rules', 'config', NULL, '{}', '{}', '{}', 'PRD 07 / #144: folded into FieldRules.');
70
- SELECT migration._allow('holidays', 'config.holidays', 'config', NULL, '{}', '{}', '{"uuid":"id","date":"date","name":"name","recurring":"recurring","unit_id":"unit_id@companies","units":"jsonb:units"}', 'PRD 07: tenant/unit holidays.');
71
- SELECT migration._allow('central_holidays', 'config.holidays', 'config', NULL, '{}', '{}', '{"date":"date","name":"name"}', 'National calendar; platform-level rows.');
72
- -- The three source names below are V1 spelling and stay as V1 wrote them; V2 calls
73
- -- the destination `access_grants` (the QR is one delivery channel, not the concept).
74
- SELECT migration._allow('qr_access_configs', 'config.access_grant', 'config', NULL, '{}', '{}', '{"enabled":"enabled","hours_valid":"hours_valid","scan_window_minutes":"scan_window_minutes"}', 'PRD 07 / #144: the V1 config is opaque; it becomes one grant per (unit, role) with channel ''qr''.');
75
- SELECT migration._allow('qr_access_grants', 'config.access_grant', 'config', NULL, '{}', '{}', '{}', 'PRD 07 / #144: V1 issued codes become access_grants on the ''qr'' channel with a freshly minted secret.');
76
- SELECT migration._allow('qr_access_sessions', 'config.access_grant', 'config', NULL, '{}', '{}', '{}', 'PRD 07 / #144: live sessions are not migrated (they expire); documented for completeness.');
77
-
78
- -- ── people ──────────────────────────────────────────────────────────────
79
- SELECT migration._allow('clients', 'public.people', 'people', 'person', '{"role":"customer"}', '{}',
80
- '{"uuid":"id","tenant_id":"-","name":"name","social_name":"jsonb:social_name","cpf":"document_number","rg":"jsonb:documents.rg","email":"email","phone":"phone","mobile":"jsonb:contact.mobile","birth_date":"date_of_birth","gender":"jsonb:profile.gender","marital_status":"jsonb:profile.marital_status","profession":"jsonb:profile.profession","education":"jsonb:profile.education","nationality":"jsonb:profile.nationality","avatar_url":"avatar_url","address":"address","address_number":"jsonb:address.number","address_complement":"jsonb:address.complement","neighborhood":"jsonb:address.neighborhood","city":"city","state":"state","country":"country","postal_code":"postal_code","notes":"notes","origin":"jsonb:customer.origin","lead_source":"jsonb:customer.lead_source","lead_source_ref":"jsonb:customer.lead_source_ref","referral":"jsonb:customer.referral","origin_referrer_client_id":"jsonb:customer.referrer_client_ref","responsible_client_id":"jsonb:customer.responsible_client_ref","customer_since":"jsonb:customer.since","first_contact_at":"jsonb:customer.first_contact_at","last_contact_at":"jsonb:customer.last_contact_at","last_visit":"jsonb:customer.last_visit","total_visits":"jsonb:customer.total_visits","stage":"jsonb:customer.stage","stage_changed_at":"jsonb:customer.stage_changed_at","identification_color":"jsonb:customer.color","skin_color":"jsonb:beauty.skin_color","hair_color":"jsonb:beauty.hair_color","hair_type":"jsonb:beauty.hair_type","warnings":"jsonb:beauty.warnings","search_text":"-","stage_changed_by":"-"}',
81
- 'ADR 0003 / PRD 03: a client is a Person with the customer role. Dedup by exact CPF (merge), no CPF ⇒ new Person unless someone already shares email+phone (identity quarantine). Clinical columns → metadata.beauty (ADR 0009).');
82
- SELECT migration._allow('professionals', 'public.people', 'people', 'person', '{"role":"professional"}', '{}',
83
- '{"uuid":"id","tenant_id":"-","name":"name","social_name":"jsonb:social_name","cpf":"document_number","rg":"jsonb:documents.rg","email":"email","phone":"phone","birth_date":"date_of_birth","gender":"jsonb:profile.gender","avatar_url":"avatar_url","avatar_color":"jsonb:profile.avatar_color","active":"is_active","specialty":"jsonb:professional.specialty","job_title":"jsonb:professional.job_title","cbo_code":"jsonb:professional.cbo_code","cbo_description":"jsonb:professional.cbo_description","commission_rate":"jsonb:professional.commission_rate","is_salesperson":"jsonb:professional.is_salesperson","service_ids":"jsonb:professional.v1_service_refs","units":"jsonb:professional.v1_unit_refs","agenda_notes":"jsonb:professional.agenda_notes","user_id":"jsonb:migration.v1_user_id","street":"address","number":"jsonb:address.number","complement":"jsonb:address.complement","neighborhood":"jsonb:address.neighborhood","city":"city","state":"state","cep":"postal_code","base_salary":"-","bank_account":"-","bank_agency":"-","bank_code":"-","pix_key":"-","ctps_number":"-","pis_pasep":"-","esocial_registration":"-","health_plan_value":"-","dental_plan_value":"-","food_voucher_value":"-","meal_voucher_value":"-","transport_voucher_value":"-","dismissal_reason":"-","mother_name":"-","father_name":"-","voter_id":"-","cnh_number":"-","passport_number":"-","reservist_number":"-","search_text":"-"}',
84
- 'ADR 0003: a professional is a role of a Person (same human as an employee/client merges by CPF). HR-sensitive data (salary, bank, CTPS, PIS, eSocial, family) does NOT migrate in Phase 0 (PRD 03 R4/R7 — Phase 2 hr).');
85
- SELECT migration._allow('employees', 'public.people', 'people', 'person', '{"role":"employee"}', '{}',
86
- '{"uuid":"id","tenant_id":"-","name":"name","social_name":"jsonb:social_name","cpf":"document_number","rg":"jsonb:documents.rg","email":"email","phone":"phone","mobile":"jsonb:contact.mobile","birth_date":"date_of_birth","gender":"jsonb:profile.gender","avatar_url":"avatar_url","active":"is_active","job_title":"jsonb:employee.job_title","department":"jsonb:employee.department","units":"jsonb:employee.v1_unit_refs","professional_access":"jsonb:employee.v1_professional_access","user_id":"jsonb:migration.v1_user_id","address":"address","city":"city","state":"state","country":"country","postal_code":"postal_code","observations":"notes","base_salary":"-","bank_account":"-","bank_agency":"-","bank_code":"-","pix_key":"-","ctps_number":"-","pis_pasep":"-","esocial_registration":"-","health_plan_value":"-","dental_plan_value":"-","food_voucher_value":"-","meal_voucher_value":"-","transport_voucher_value":"-","dismissal_reason":"-","mother_name":"-","father_name":"-","voter_id":"-","cnh_number":"-","passport_number":"-","reservist_number":"-"}',
87
- 'ADR 0003: employee role of a Person; email/phone/mobile are arrays in V1 (the extractor sends the first). HR-sensitive data does NOT migrate in Phase 0.');
88
- SELECT migration._allow('contacts', 'public.people', 'people', 'person', '{"role":"contact","role_by":"contact_type"}', '{}',
89
- '{"uuid":"id","tenant_id":"-","name":"name","cpf_cnpj":"document_number","document":"jsonb:documents.other","email":"email","email_2":"jsonb:contact.email_2","phone":"phone","phone_2":"jsonb:contact.phone_2","mobile":"jsonb:contact.mobile","mobile_2":"jsonb:contact.mobile_2","contact_type":"jsonb:contact.type","service_provider_type":"jsonb:contact.service_provider_type","group_name":"jsonb:contact.group","gender":"jsonb:profile.gender","active":"is_active","address":"address","address_number":"jsonb:address.number","address_complement":"jsonb:address.complement","neighborhood":"jsonb:address.neighborhood","city":"city","state":"state","postal_code":"postal_code","observations":"notes","unit_id":"jsonb:contact.v1_unit_ref","units":"jsonb:contact.v1_unit_refs","municipal_state_registration":"jsonb:legal.state_registration","default_chart_account_id":"jsonb:financial.v1_default_chart_account_ref","cost_center_id":"jsonb:financial.v1_cost_center_ref","allowed_chart_accounts":"jsonb:financial.v1_allowed_chart_accounts","limit_chart_accounts":"jsonb:financial.limit_chart_accounts","add_items_automatically":"jsonb:financial.add_items_automatically","bank_account":"-","bank_agency":"-","bank_code":"-","pix_key":"-","search_text":"-"}',
90
- 'ADR 0003: contact role (contact_type supplier ⇒ supplier role). CNPJ contacts are legal-entity counterparties (Pessoa como Conta, ADR 0005).');
91
- SELECT migration._allow('suppliers', 'public.people', 'people', 'person', '{"role":"supplier"}', '{}',
92
- '{"uuid":"id","name":"name","document":"document_number","email":"email","phone":"phone"}',
93
- 'Listed in §3.1; in the V1 schema of 2026-08 suppliers are contacts with contact_type = supplier — the extractor sends whichever exists, the destination writes the supplier role either way.');
94
- SELECT migration._allow('client_registrations', 'public.people', 'people', NULL, '{}', '{}', '{"uuid":"id","name":"name","cpf":"document_number","email":"email","phone":"phone"}', 'PRD 03 R6: pre-registration → Person creation queue with dedup; contract only in Phase 0.');
95
- SELECT migration._allow('client_access_tokens', 'public.people', 'people', NULL, '{}', '{}', '{"client_id":"person_id@clients","token":"-"}', 'PRD 03 R6: opaque portal tokens; the token value never migrates (re-issued in V2).');
96
- SELECT migration._allow('professions', 'public.people', 'people', NULL, '{}', '{}', '{"name":"jsonb:professional.profession"}', 'Reference list folded into the professional role JSONB.');
97
- SELECT migration._allow('origins', 'public.people', 'people', NULL, '{}', '{}', '{"name":"jsonb:customer.origin"}', 'Reference list of the customer role.');
98
- SELECT migration._allow('partnerships', 'public.people', 'people', NULL, '{}', '{}', '{"name":"jsonb:customer.partnership"}', 'Reference list of the customer role (price variations reference it).');
99
-
100
- -- ── catalog ─────────────────────────────────────────────────────────────
101
- SELECT migration._allow('product_categories', 'public.categories', 'catalog', 'category', '{"kind":"product"}', '{}',
102
- '{"uuid":"id","tenant_id":"-","name":"name","description":"jsonb:description","active":"is_active","menu_order":"sort_order","image_url":"icon","show_in_menu":"jsonb:chef.show_in_menu","delivery_available":"jsonb:chef.delivery_available","pdv_available":"jsonb:chef.pdv_available","prep_time":"jsonb:chef.prep_time"}',
103
- 'PRD 04 R2: shared categories(kind). Chef-only flags → metadata.chef.');
104
- SELECT migration._allow('service_categories', 'public.categories', 'catalog', 'category', '{"kind":"service"}', '{}',
105
- '{"uuid":"id","tenant_id":"-","name":"name","description":"jsonb:description","color":"color","active":"is_active","numeric_id":"-"}', 'PRD 04 R2.');
106
- SELECT migration._allow('products', 'public.products', 'catalog', 'product', '{"kind":"good"}', '{}',
107
- '{"uuid":"id","tenant_id":"-","name":"name","description":"description","internal_code":"sku","barcode":"jsonb:catalog.barcode","brand":"jsonb:catalog.brand","category_id":"category_id@product_categories","sale_price":"price","cost_price":"cost","avg_purchase_price":"jsonb:inventory.avg_purchase_price","active":"is_active","is_for_sale":"jsonb:catalog.is_for_sale","is_resale":"jsonb:catalog.is_resale","is_asset":"jsonb:catalog.is_asset","is_ingredient":"jsonb:chef.is_ingredient","is_intermediate":"jsonb:chef.is_intermediate","is_produced":"jsonb:chef.is_produced","product_type":"jsonb:catalog.v1_product_type","purpose":"jsonb:catalog.v1_purpose","image_url":"image_url","measurement_unit_id":"jsonb:inventory.v1_measurement_unit_ref","content_per_unit":"jsonb:inventory.content_per_unit","content_unit_id":"jsonb:inventory.v1_content_unit_ref","conversion_factor":"jsonb:inventory.conversion_factor","commission_percent":"jsonb:catalog.commission_percent","professional_resale_price":"jsonb:catalog.professional_resale_price","menu_available":"jsonb:chef.menu_available","menu_order":"jsonb:chef.menu_order","delivery_available":"jsonb:chef.delivery_available","delivery_price":"jsonb:chef.delivery_price","pdv_available":"jsonb:chef.pdv_available","current_quantity":"-","minimum_quantity":"-","maximum_quantity":"-","default_stock_location_id":"-","default_stock_unit_id":"-","supplier_id":"jsonb:inventory.v1_supplier_ref","allowed_supplier_ids":"jsonb:inventory.v1_allowed_supplier_refs","search_text":"-","numeric_id":"-"}',
108
- 'PRD 04 R1/R5: a product is a catalog item kind=good; quantities are NOT catalog (stock_positions, PRD 06) and are dropped here.');
109
- SELECT migration._allow('services', 'public.products', 'catalog', 'product', '{"kind":"service"}', '{}',
110
- '{"uuid":"id","tenant_id":"-","name":"name","description":"description","internal_code":"sku","category_id":"category_id@service_categories","price":"price","active":"is_active","duration_minutes":"jsonb:catalog.duration_minutes","color":"jsonb:catalog.color","service_kind":"jsonb:beauty.service_kind","revision_count":"jsonb:beauty.revision_count","revision_price":"jsonb:beauty.revision_price","revision_deadline_days":"jsonb:beauty.revision_deadline_days","validity_days":"jsonb:catalog.validity_days","contract_text":"jsonb:beauty.contract_text","post_service_text":"jsonb:beauty.post_service_text","reminder_text":"jsonb:beauty.reminder_text","scheduling_alert_text":"jsonb:beauty.scheduling_alert_text","always_ask_used_products":"jsonb:beauty.always_ask_used_products","suggest_quote_on_execution":"jsonb:beauty.suggest_quote_on_execution","category":"-","search_text":"-"}',
111
- 'PRD 04 R1: a service is a catalog item kind=service (public.services is drift, folded by #139). service_kind is beauty semantics on a core column → metadata.beauty until #139 promotes it (R6).');
112
- SELECT migration._allow('product_barcodes', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products","barcode":"jsonb:catalog.barcodes[]"}', 'Facet of the product (Matriz D7).');
113
- SELECT migration._allow('product_sale_info', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products"}', 'Facet of the product.');
114
- SELECT migration._allow('product_sale_channels', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products"}', 'Facet of the product.');
115
- SELECT migration._allow('product_fiscal_info', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products"}', 'Facet of the product (fiscal; NF is core-B).');
116
- SELECT migration._allow('product_asset_info', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products"}', 'Facet of the product.');
117
- SELECT migration._allow('product_ingredient_info', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products"}', 'Facet of the product (chef).');
118
- SELECT migration._allow('product_intermediate_info', 'public.products', 'catalog', NULL, '{}', '{}', '{"product_id":"id@products"}', 'Facet of the product (chef).');
119
- SELECT migration._allow('measurement_units', 'public.plg_inventory_measurement_units', 'catalog', NULL, '{}', '{}', '{"uuid":"id","name":"name","abbreviation":"abbreviation","active":"is_active"}', 'PRD 06 R2: units of measure live in the inventory core.');
120
- SELECT migration._allow('unit_conversions', 'public.plg_inventory_unit_conversions', 'catalog', NULL, '{}', '{}', '{"from_unit_id":"from_unit_id@measurement_units","to_unit_id":"to_unit_id@measurement_units","conversion_factor":"factor"}', 'PRD 06 R2.');
121
- SELECT migration._allow('price_tables', 'catalog.price_tables', 'catalog', NULL, '{}', '{}', '{"uuid":"id","description":"name","type":"kind","valid_from":"valid_from","valid_until":"valid_until","unit_ids":"jsonb:scope.v1_unit_refs","category_ids":"jsonb:scope.v1_category_refs","professional_ids":"jsonb:scope.v1_professional_refs","partnership_ids":"jsonb:scope.v1_partnership_refs","active":"is_active"}', 'PRD 04 R3 / #139 owns the destination.');
122
- SELECT migration._allow('price_table_items', 'catalog.price_table_items', 'catalog', NULL, '{}', '{}', '{"uuid":"id","price_table_id":"price_table_id@price_tables","service_id":"product_id@services","table_price":"price"}', 'PRD 04 R3.');
123
- SELECT migration._allow('price_variations', 'catalog.price_variations', 'catalog', NULL, '{}', '{}', '{"uuid":"id","variation_type":"kind","value_type":"value_type","value":"value","first_appointment_only":"jsonb:rules.first_appointment_only","active":"is_active"}', 'PRD 04 R3.');
124
- SELECT migration._allow('service_packages', 'catalog.packages', 'catalog', NULL, '{}', '{}', '{"uuid":"id","name":"name","description":"description","total_price":"price","status":"status","validity_days":"jsonb:validity.days","validity_months":"jsonb:validity.months","validity_enabled":"jsonb:validity.enabled","replaces_uuid":"jsonb:v1_replaces","replaced_by_uuid":"jsonb:v1_replaced_by","active":"is_active"}', 'PRD 04 R4: packages facet — contract only, Phase 3 uses.');
125
- SELECT migration._allow('service_package_items', 'catalog.package_items', 'catalog', NULL, '{}', '{}', '{"uuid":"id","package_id":"package_id@service_packages","service_id":"product_id@services","product_id":"product_id@products","item_type":"item_type","quantity":"quantity","unit_price":"unit_price","package_price":"price"}', 'PRD 04 R4.');
126
- SELECT migration._allow('package_settings', 'catalog.packages', 'catalog', NULL, '{}', '{}', '{}', 'PRD 04 R4: tenant-level package settings → configuration.');
127
- SELECT migration._allow('package_unit_shares', 'catalog.packages', 'catalog', NULL, '{}', '{}', '{}', 'PRD 04 R4: package revenue share by unit → facet.');
128
- SELECT migration._allow('discount_reasons', 'config.orders', 'catalog', NULL, '{}', '{}', '{"uuid":"id","name":"name"}', 'PRD 04 R7: configuration of the owning plugin (orders/financial), not catalog.');
129
- SELECT migration._allow('discount_users', 'config.orders', 'catalog', NULL, '{}', '{}', '{}', 'PRD 04 R7.');
130
- SELECT migration._allow('cancellation_reasons', 'config.orders', 'catalog', NULL, '{}', '{}', '{"uuid":"id","name":"name"}', 'PRD 04 R7.');
131
- SELECT migration._allow('cancellation_users', 'config.orders', 'catalog', NULL, '{}', '{}', '{}', 'PRD 04 R7.');
132
-
133
- -- ── financial base ──────────────────────────────────────────────────────
134
- SELECT migration._allow('invoices', 'public.orders', 'financial', 'order',
135
- '{"kind":"sale","status_map":{"draft":"draft","canceled":"cancelled","cancelled":"cancelled","*":"completed"},"split_invoice":true}',
136
- ARRAY['subtotal', 'discount', 'tax', 'total'],
137
- '{"uuid":"id","tenant_id":"-","type":"jsonb:financial.v1_type","status":"status","invoice_date":"completed_at","total_amount":"total","paid_amount":"jsonb:financial.v1_paid_amount","total_installments":"jsonb:financial.v1_total_installments","client_id":"party_id@clients","unit_id":"unit_id@companies","cash_session_id":"jsonb:financial.v1_cash_session_ref","account_central_id":"jsonb:financial.v1_account_central_ref","opportunity_id":"jsonb:crm.v1_opportunity_ref","fiscal_number":"reference_number","observations":"notes","cancel_reason":"jsonb:cancellation.reason","cancel_reason_id":"jsonb:cancellation.v1_reason_ref","canceled_at":"jsonb:cancellation.at","canceled_by":"-"}',
138
- 'ADR 0004 / PRD 05 R1+R13: an invoice of type service/receivable is a Venda (orders) + a receivable invoice (plg_financial_invoices, second ledger row, split); payable/purchase is an invoice only. Financial columns are never overwritten once written (value quarantine). V1 status is kept in metadata.migration.source_status.');
139
- SELECT migration._allow('invoice_items', 'public.order_items', 'financial', NULL, '{}', ARRAY['unit_price', 'discount', 'total'],
140
- '{"uuid":"id","invoice_id":"order_id@invoices","item_type":"jsonb:item_type","service_id":"product_id@services","product_id":"product_id@products","service_package_id":"jsonb:v1_package_ref","description":"name","quantity":"quantity","unit_price":"unit_price","discount":"discount","additional":"jsonb:financial.additional","total_amount":"total","is_executed":"jsonb:execution.is_executed","execution_date":"jsonb:execution.date","execution_start_time":"jsonb:execution.start_time","execution_end_time":"jsonb:execution.end_time","executed_by_professional_id":"jsonb:execution.v1_professional_ref","execution_photos":"-","appointment_id":"jsonb:agenda.v1_appointment_ref","gift_card_id":"jsonb:v1_gift_card_ref","canceled_at":"jsonb:cancellation.at","cancel_reason":"jsonb:cancellation.reason","account_id":"jsonb:financial.v1_account_ref","cost_center_id":"jsonb:financial.v1_cost_center_ref"}',
141
- 'PRD 05 R3 / #140: order_items with scaffold columns; execution state → column when the vertical uses it (ADR 0009); execution status must follow the EF lesson #1 (antecipated-sale item status > procedure status), never "has a procedure id".');
142
- SELECT migration._allow('invoice_items_discounted', 'public.order_items', 'financial', NULL, '{}', '{}', '{}', 'Facet of the item.');
143
- SELECT migration._allow('invoice_item_adjustments', 'public.order_items', 'financial', NULL, '{}', '{}', '{}', 'Facet of the item.');
144
- SELECT migration._allow('invoice_item_participants', 'public.order_items', 'financial', NULL, '{}', '{}', '{}', 'Facet of the item (commission participants).');
145
- SELECT migration._allow('invoice_cancellation_logs', 'public.audit_logs', 'financial', NULL, '{}', '{}', '{}', 'Append-only history → audit.');
146
- SELECT migration._allow('invoice_item_cancellation_logs', 'public.audit_logs', 'financial', NULL, '{}', '{}', '{}', 'Append-only history → audit.');
147
- SELECT migration._allow('account_central', 'public.plg_financial_accounts', 'financial', NULL, '{}', '{}', '{"uuid":"id","name":"name","account_type":"kind"}', 'PRD 05 R6: an account of the two-leg ledger (#142).');
148
- SELECT migration._allow('bank_accounts', 'public.plg_financial_accounts', 'financial', NULL, '{}', ARRAY['initial_balance'],
149
- '{"uuid":"id","name":"name","account_type":"kind","bank_code":"jsonb:bank.code","bank_name":"jsonb:bank.name","agency_number":"jsonb:bank.agency","account_number":"jsonb:bank.account","holder":"jsonb:bank.holder","document":"jsonb:bank.document","initial_balance":"initial_balance","current_balance":"-","credit_limit":"jsonb:card.credit_limit","closing_day":"jsonb:card.closing_day","due_day":"jsonb:card.due_day","card_brand_id":"jsonb:card.v1_brand_ref","default_fee_rate":"jsonb:card.default_fee_rate","days_to_credit":"jsonb:card.days_to_credit","unit_id":"unit_id@companies","active":"is_active","integration_password":"-","cnab_agreement_code":"-","cnab_company_code":"-","cnab_next_sequence":"-"}',
150
- 'PRD 05 R6/R13: bank_accounts by account_type → accounts (bank, cofre, cartão crédito/débito). Balances are views; current_balance is dropped and reconciled instead. Integration secrets never migrate.');
151
- SELECT migration._allow('card_brands', 'public.plg_financial_card_brands', 'financial', NULL, '{}', '{}', '{"uuid":"id","name":"name"}', 'PRD 05 R11.');
152
- SELECT migration._allow('cc_receiving_fee_configs', 'public.plg_financial_card_fee_configs', 'financial', NULL, '{}', '{}', '{}', 'PRD 05 R11: brand × installment range × fee per receiving account (#142).');
153
- SELECT migration._allow('payment_methods', 'public.plg_financial_payment_methods', 'financial', NULL, '{}', '{}', '{"uuid":"id","name":"name","payment_method_type_id":"type_id@payment_method_types","max_installments":"jsonb:installments.max","min_installments":"jsonb:installments.min","discount":"jsonb:pricing.discount","interest":"jsonb:pricing.interest","active":"is_active"}', 'PRD 05.');
154
- SELECT migration._allow('payment_method_types', 'public.plg_financial_payment_method_types', 'financial', NULL, '{}', '{}', '{"uuid":"id","name":"name"}', 'PRD 05.');
155
- SELECT migration._allow('chart_of_accounts', 'public.plg_financial_chart_of_accounts', 'financial', NULL, '{}', '{}', '{"uuid":"id","code":"code","name":"name","account_type":"kind","parent_id":"parent_id@chart_of_accounts","active":"is_active"}', 'PRD 05.');
156
- SELECT migration._allow('cost_centers', 'public.plg_financial_cost_centers', 'financial', NULL, '{}', '{}', '{"uuid":"id","code":"code","name":"name","description":"description","active":"is_active"}', 'PRD 05.');
157
- SELECT migration._allow('financial_movements', 'public.plg_financial_movements', 'financial', NULL, '{}', ARRAY['amount', 'paid_amount'],
158
- '{"uuid":"id","invoice_id":"financial_invoice_id@invoices","type":"movement_kind","movement_type":"jsonb:v1_movement_type","amount":"amount","paid_amount":"paid_amount","status":"status","due_date":"due_date","payment_date":"paid_at","installment_number":"installment_number","debit_account_id":"debit_account_id@account_central","credit_account_id":"credit_account_id@account_central","bank_account_id":"jsonb:v1_bank_account_ref","payment_method_id":"payment_method_id@payment_methods","payment_method_type_id":"payment_method_type_id@payment_method_types","card_brand":"jsonb:card.brand","card_installments":"jsonb:card.installments","cash_session_id":"cash_session_id@cash_register_sessions","parent_movement_id":"parent_movement_id@financial_movements","external_id":"external_id","external_source":"external_source","is_confirmed":"jsonb:confirmed","confirmed_at":"confirmed_at","barcode":"jsonb:barcode","notes":"notes","order_guest_id":"-"}',
159
- 'PRD 05 R7/R13: append-only two-leg movements (debit + credit account). Never overwritten. Paid invoices without movements receive an identifiable synthetic payment (Crédito Legado, R14) — the extractor emits it, the destination records it as a normal row.');
160
- SELECT migration._allow('payment_allocations', 'public.plg_financial_allocations', 'financial', NULL, '{}', ARRAY['allocated_amount'],
161
- '{"uuid":"id","payment_movement_id":"payment_movement_id@financial_movements","bill_movement_id":"installment_id@financial_movements","allocated_amount":"allocated_amount","origin":"origin"}', 'PRD 05 R8.');
162
- SELECT migration._allow('payment_deletion_logs', 'public.audit_logs', 'financial', NULL, '{}', '{}', '{}', 'Append-only history → audit.');
163
- SELECT migration._allow('payment_unlink_logs', 'public.audit_logs', 'financial', NULL, '{}', '{}', '{}', 'Append-only history → audit.');
164
- SELECT migration._allow('cash_register_sessions', 'public.plg_financial_cash_register_sessions', 'financial', NULL, '{}', ARRAY['opening_balance', 'closing_balance', 'counted_cash', 'counted_card'],
165
- '{"uuid":"id","unit_id":"unit_id@companies","bank_account_id":"account_id@bank_accounts","opened_at":"opened_at","opened_by_user_id":"jsonb:v1_opened_by","closed_at":"closed_at","closed_by_user_id":"jsonb:v1_closed_by","opening_balance":"opening_balance","closing_balance":"closing_balance","expected_cash":"expected_cash","expected_card":"expected_card","counted_cash":"counted_cash","counted_card":"counted_card","difference_cash":"difference_cash","difference_card":"difference_card","status":"status","review_status":"jsonb:review.status","notes":"notes"}',
166
- 'PRD 05 R10: caixinha per user and unit.');
167
- SELECT migration._allow('cash_session_reviewers', 'public.plg_financial_cash_register_sessions', 'financial', NULL, '{}', '{}', '{}', 'PRD 05 R10: optional reviewers → facet.');
168
- SELECT migration._allow('client_credits', 'derived', 'financial', NULL, '{"verify_only":true}', ARRAY['amount'], '{"client_id":"party_id@clients","amount":"amount"}', 'PRD 05 R9/R13: customer credit is the balance of the Person account (view) — not written, VERIFIED by the reconciliation.');
169
- SELECT migration._allow('client_credit_wallets', 'derived', 'financial', NULL, '{"verify_only":true}', ARRAY['balance'], '{}', 'PRD 05 R13: derived; verified, not written.');
170
- SELECT migration._allow('client_credit_ledger', 'derived', 'financial', NULL, '{"verify_only":true}', ARRAY['amount'], '{}', 'PRD 05 R13: derived; verified, not written.');
171
- SELECT migration._allow('bill_attachments', 'storage', 'financial', NULL, '{}', '{}', '{}', 'D13 minimum: invoice attachments into the classified bucket; files move out of band.');
172
- SELECT migration._allow('recurring_bills', 'public.plg_financial_recurring_bills', 'financial', NULL, '{}', ARRAY['amount'], '{}', 'PRD 05: recurring payables (#141/#142 own the destination).');
173
- SELECT migration._allow('recurring_bill_items', 'public.plg_financial_recurring_bills', 'financial', NULL, '{}', '{}', '{}', 'PRD 05.');
174
- SELECT migration._allow('recurring_bill_occurrences', 'public.plg_financial_recurring_bills', 'financial', NULL, '{}', '{}', '{}', 'PRD 05.');
175
-
176
- -- ── inventory base ──────────────────────────────────────────────────────
177
- SELECT migration._allow('stock_locations', 'public.plg_inventory_stock_locations', 'inventory', NULL, '{}', '{}', '{"uuid":"id","name":"name","description":"description","unit_id":"unit_id@companies","active":"is_active"}', 'PRD 06 R1: locations per unit (unit_id mandatory).');
178
- SELECT migration._allow('stock_positions', 'public.plg_inventory_stock_positions', 'inventory', NULL, '{}', ARRAY['quantity', 'unit_cost'],
179
- '{"uuid":"id","product_id":"product_id@products","stock_location_id":"location_id@stock_locations","unit_id":"unit_id@companies","batch_number":"batch","expiration_date":"expires_at","quantity":"quantity","unit_cost":"unit_cost","unit_type":"jsonb:unit_type","location":"jsonb:v1_location_label"}', 'PRD 06 R1: position per lot/location/cost.');
180
- SELECT migration._allow('stock_movements', 'public.plg_inventory_stock_movements', 'inventory', NULL, '{}', ARRAY['quantity', 'unit_cost', 'total_cost'],
181
- '{"uuid":"id","product_id":"product_id@products","stock_location_id":"from_location_id@stock_locations","destination_stock_location_id":"to_location_id@stock_locations","stock_position_id":"position_id@stock_positions","unit_id":"unit_id@companies","destination_unit_id":"to_unit_id@companies","movement_type":"kind","quantity":"quantity","original_quantity":"jsonb:original_quantity","unit_cost":"unit_cost","total_cost":"total_cost","movement_date":"moved_at","document_number":"document_number","reason":"reason","notes":"notes","supplier_id":"jsonb:v1_supplier_ref","appointment_id":"jsonb:agenda.v1_appointment_ref","danfe_import_item_id":"-","unit_label_id":"jsonb:v1_unit_label_ref","user_id":"jsonb:v1_user_id"}', 'PRD 06 R1: append-only movements with reversal.');
182
- SELECT migration._allow('stock_unit_labels', 'public.plg_inventory_stock_unit_labels', 'inventory', NULL, '{}', '{}', '{}', 'PRD 06 R5.');
183
- SELECT migration._allow('supplier_product_mappings', 'public.plg_inventory_supplier_products', 'inventory', NULL, '{}', '{}', '{"product_id":"product_id@products","supplier_id":"supplier_person_id@contacts"}', 'PRD 06 R5: supplier reference = Person.');
184
-
185
- -- ── never sent ──────────────────────────────────────────────────────────
186
- INSERT INTO migration.excluded_tables (source_table, reason) VALUES
187
- ('orders', 'V1 legacy table without app use (references only in CRM); the V2 orders table is a different thing (Venda). Confirm empty in production.'),
188
- ('guests', 'V1 legacy table without app use.'),
189
- ('payments', 'V1 legacy table without app use; money lives in financial_movements.'),
190
- ('financial_accounts', 'V1 legacy table without app use; superseded by account_central/bank_accounts.'),
191
- ('financial_transactions', 'V1 legacy table without app use; superseded by financial_movements.'),
192
- ('transaction_categories', 'V1 legacy table without app use.'),
193
- ('transaction_category_relations', 'V1 legacy table without app use.'),
194
- ('sales_journey', 'V1 legacy table without app use.'),
195
- ('pending_appointments', 'V1 legacy table without app use.'),
196
- ('for', 'V1 legacy table without app use (accidental name).'),
197
- ('to', 'V1 legacy table without app use (accidental name).'),
198
- ('user_roles', 'Legacy role model without use in the V1 engine (core-beauty-chef §3.1); RBAC comes from the permission catalog (#136).'),
199
- ('import_ef_*', 'The previous vendor''s one-off import for one specific network: never ported (core-beauty-chef §3.3). Any source_table starting with import_ef_ is refused.')
200
- ON CONFLICT (source_table) DO UPDATE SET reason = EXCLUDED.reason;
201
-
202
- SELECT set_config('migration.allowlist_unlock', 'off', false);