@endora-commerce/mod-customer-accounts 0.100.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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/admin/api/customer-groups-client.d.ts +27 -0
  4. package/dist/admin/api/customer-groups-client.d.ts.map +1 -0
  5. package/dist/admin/api/customer-groups-client.js +17 -0
  6. package/dist/admin/api/customer-groups-client.js.map +1 -0
  7. package/dist/admin/index.d.ts +33 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +38 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/CustomerGroupsPage.d.ts +18 -0
  12. package/dist/admin/pages/CustomerGroupsPage.d.ts.map +1 -0
  13. package/dist/admin/pages/CustomerGroupsPage.js +108 -0
  14. package/dist/admin/pages/CustomerGroupsPage.js.map +1 -0
  15. package/dist/backend/entities/customer-account.entity.d.ts +111 -0
  16. package/dist/backend/entities/customer-account.entity.d.ts.map +1 -0
  17. package/dist/backend/entities/customer-account.entity.js +230 -0
  18. package/dist/backend/entities/customer-account.entity.js.map +1 -0
  19. package/dist/backend/entities/customer-group.entity.d.ts +29 -0
  20. package/dist/backend/entities/customer-group.entity.d.ts.map +1 -0
  21. package/dist/backend/entities/customer-group.entity.js +70 -0
  22. package/dist/backend/entities/customer-group.entity.js.map +1 -0
  23. package/dist/backend/entities/password-reset-token.entity.d.ts +16 -0
  24. package/dist/backend/entities/password-reset-token.entity.d.ts.map +1 -0
  25. package/dist/backend/entities/password-reset-token.entity.js +59 -0
  26. package/dist/backend/entities/password-reset-token.entity.js.map +1 -0
  27. package/dist/backend/index.d.ts +144 -0
  28. package/dist/backend/index.d.ts.map +1 -0
  29. package/dist/backend/index.js +407 -0
  30. package/dist/backend/index.js.map +1 -0
  31. package/dist/backend/routes.admin.d.ts +26 -0
  32. package/dist/backend/routes.admin.d.ts.map +1 -0
  33. package/dist/backend/routes.admin.js +35 -0
  34. package/dist/backend/routes.admin.js.map +1 -0
  35. package/dist/backend/services/audit-references.d.ts +22 -0
  36. package/dist/backend/services/audit-references.d.ts.map +1 -0
  37. package/dist/backend/services/audit-references.js +46 -0
  38. package/dist/backend/services/audit-references.js.map +1 -0
  39. package/dist/backend/services/customer-account-lifecycle-ports.d.ts +168 -0
  40. package/dist/backend/services/customer-account-lifecycle-ports.d.ts.map +1 -0
  41. package/dist/backend/services/customer-account-lifecycle-ports.js +420 -0
  42. package/dist/backend/services/customer-account-lifecycle-ports.js.map +1 -0
  43. package/dist/backend/services/customer-account-ports.d.ts +143 -0
  44. package/dist/backend/services/customer-account-ports.d.ts.map +1 -0
  45. package/dist/backend/services/customer-account-ports.js +422 -0
  46. package/dist/backend/services/customer-account-ports.js.map +1 -0
  47. package/dist/backend/services/customer-auth-service.d.ts +62 -0
  48. package/dist/backend/services/customer-auth-service.d.ts.map +1 -0
  49. package/dist/backend/services/customer-auth-service.js +105 -0
  50. package/dist/backend/services/customer-auth-service.js.map +1 -0
  51. package/dist/backend/services/customer-group-read-port.d.ts +24 -0
  52. package/dist/backend/services/customer-group-read-port.d.ts.map +1 -0
  53. package/dist/backend/services/customer-group-read-port.js +44 -0
  54. package/dist/backend/services/customer-group-read-port.js.map +1 -0
  55. package/dist/backend/services/customer-group-service.d.ts +21 -0
  56. package/dist/backend/services/customer-group-service.d.ts.map +1 -0
  57. package/dist/backend/services/customer-group-service.js +97 -0
  58. package/dist/backend/services/customer-group-service.js.map +1 -0
  59. package/dist/backend/services/customer-rollup-scope.d.ts +30 -0
  60. package/dist/backend/services/customer-rollup-scope.d.ts.map +1 -0
  61. package/dist/backend/services/customer-rollup-scope.js +42 -0
  62. package/dist/backend/services/customer-rollup-scope.js.map +1 -0
  63. package/dist/backend/services/password-reset-service.d.ts +15 -0
  64. package/dist/backend/services/password-reset-service.d.ts.map +1 -0
  65. package/dist/backend/services/password-reset-service.js +90 -0
  66. package/dist/backend/services/password-reset-service.js.map +1 -0
  67. package/dist/backend/services/role-service.d.ts +22 -0
  68. package/dist/backend/services/role-service.d.ts.map +1 -0
  69. package/dist/backend/services/role-service.js +83 -0
  70. package/dist/backend/services/role-service.js.map +1 -0
  71. package/dist/backend/services/two-factor-enrolments.d.ts +18 -0
  72. package/dist/backend/services/two-factor-enrolments.d.ts.map +1 -0
  73. package/dist/backend/services/two-factor-enrolments.js +2 -0
  74. package/dist/backend/services/two-factor-enrolments.js.map +1 -0
  75. package/dist/manifest.d.ts +169 -0
  76. package/dist/manifest.d.ts.map +1 -0
  77. package/dist/manifest.js +212 -0
  78. package/dist/manifest.js.map +1 -0
  79. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.d.ts +6 -0
  80. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.d.ts.map +1 -0
  81. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.js +25 -0
  82. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.js.map +1 -0
  83. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.d.ts +34 -0
  84. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.d.ts.map +1 -0
  85. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.js +43 -0
  86. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.js.map +1 -0
  87. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.d.ts +54 -0
  88. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.d.ts.map +1 -0
  89. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.js +97 -0
  90. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.js.map +1 -0
  91. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts +12 -0
  92. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts.map +1 -0
  93. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.js +16 -0
  94. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.js.map +1 -0
  95. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.d.ts +14 -0
  96. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.d.ts.map +1 -0
  97. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.js +18 -0
  98. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.js.map +1 -0
  99. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.d.ts +22 -0
  100. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.d.ts.map +1 -0
  101. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.js +26 -0
  102. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.js.map +1 -0
  103. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.d.ts +46 -0
  104. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.d.ts.map +1 -0
  105. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.js +97 -0
  106. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.js.map +1 -0
  107. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts +31 -0
  108. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts.map +1 -0
  109. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js +35 -0
  110. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js.map +1 -0
  111. package/dist/migrations/20260825T141659_customer_accounts_organization_required.d.ts +58 -0
  112. package/dist/migrations/20260825T141659_customer_accounts_organization_required.d.ts.map +1 -0
  113. package/dist/migrations/20260825T141659_customer_accounts_organization_required.js +133 -0
  114. package/dist/migrations/20260825T141659_customer_accounts_organization_required.js.map +1 -0
  115. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.d.ts +27 -0
  116. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.d.ts.map +1 -0
  117. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.js +44 -0
  118. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.js.map +1 -0
  119. package/dist/migrations/index.d.ts +36 -0
  120. package/dist/migrations/index.d.ts.map +1 -0
  121. package/dist/migrations/index.js +47 -0
  122. package/dist/migrations/index.js.map +1 -0
  123. package/docs/customer_accounts.md +38 -0
  124. package/i18n/en.json +30 -0
  125. package/i18n/pl.json +30 -0
  126. package/package.json +94 -0
  127. package/tailwind.css +14 -0
@@ -0,0 +1,54 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 040 (Customers) — extends `customer_accounts` with the lifecycle
4
+ * fields the Customers module needs:
5
+ *
6
+ * - `customer_group_id` — direct customer→customer-group membership (FR-022),
7
+ * FK to `customer_groups` ON DELETE SET NULL.
8
+ * - block state + provenance (`blocked_at`, `block_reason`, `block_source`,
9
+ * `blocked_by_admin_user_id`, `blocked_by_customer_account_id`) — FR-012…017.
10
+ * - deletion / anonymization state (`deletion_requested_by_admin_user_id`,
11
+ * `anonymized_at`) paired with the existing `deleted_at` — FR-039/FR-040.
12
+ *
13
+ * All columns are nullable; existing rows are unaffected.
14
+ *
15
+ * **It also creates `customer_groups` since
16
+ * `specs/120-migration-closure-bridge-ownership/` Phase 3.** The table was
17
+ * created by `price_lists`' frozen
18
+ * `Migration20260426T075235PriceListsPricingInit` while this module owns it —
19
+ * its `CustomerGroup` entity declares the table name — because tiered pricing
20
+ * needed customer groups first and created them where it needed them.
21
+ * The table was created by whoever needed it first rather than by whoever owns
22
+ * it, and the comment above used to record that as *"owned by price_lists"*.
23
+ *
24
+ * **Why this site is repaired while 27 other misfiled creations are not.**
25
+ * Moving a *reference* into its owner's module can only move it strictly later
26
+ * in the computed order, which is always safe; moving a *creation* moves it to
27
+ * a position every existing reference must be re-checked against. The other 27
28
+ * fail **safe** — a client omitting `catalog` gets an empty `products` table.
29
+ * This one also produced a fail-**closed** reference: the foreign key below
30
+ * named a table outside this module's closure, and declaring `price_lists`
31
+ * here to fix that would close a cycle, `price_lists` already declaring
32
+ * `customer_accounts`. That, and nothing else, is why it is on the list
33
+ * (owner's ruling, 2026-09-12).
34
+ *
35
+ * **The re-check, derived from the computed order rather than from a stamp.**
36
+ * The only reference to `customer_groups` in the entire corpus is this
37
+ * migration's own foreign key, three statements below. `price_lists` does not
38
+ * reference it: `price_list_assignments.customer_group_id` is a nullable column
39
+ * with an index and no foreign key, and so is `organizations.customer_group_id`.
40
+ * So the creation is placed in the frozen body that carries the only reference,
41
+ * above it, and every position in between is unaffected.
42
+ *
43
+ * **`if not exists`, and it is load-bearing.** A database that applied the
44
+ * April migration and has not yet reached this one already has the table while
45
+ * this migration is pending; a verbatim `create table` would fail there. Both
46
+ * class names are unchanged and `BASELINE_MIGRATIONS` is untouched —
47
+ * `mikro_orm_migrations` persists the class name and no checksum, so neither
48
+ * edited body is re-offered to a database that has applied it.
49
+ */
50
+ export declare class Migration20260611T140403CustomerAccountsLifecycle extends Migration {
51
+ up(): Promise<void>;
52
+ down(): Promise<void>;
53
+ }
54
+ //# sourceMappingURL=20260611T140403_customer_accounts_lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260611T140403_customer_accounts_lifecycle.d.ts","sourceRoot":"","sources":["../../src/migrations/20260611T140403_customer_accounts_lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,qBAAa,iDAAkD,SAAQ,SAAS;IAC/D,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAqCnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBrC"}
@@ -0,0 +1,97 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 040 (Customers) — extends `customer_accounts` with the lifecycle
4
+ * fields the Customers module needs:
5
+ *
6
+ * - `customer_group_id` — direct customer→customer-group membership (FR-022),
7
+ * FK to `customer_groups` ON DELETE SET NULL.
8
+ * - block state + provenance (`blocked_at`, `block_reason`, `block_source`,
9
+ * `blocked_by_admin_user_id`, `blocked_by_customer_account_id`) — FR-012…017.
10
+ * - deletion / anonymization state (`deletion_requested_by_admin_user_id`,
11
+ * `anonymized_at`) paired with the existing `deleted_at` — FR-039/FR-040.
12
+ *
13
+ * All columns are nullable; existing rows are unaffected.
14
+ *
15
+ * **It also creates `customer_groups` since
16
+ * `specs/120-migration-closure-bridge-ownership/` Phase 3.** The table was
17
+ * created by `price_lists`' frozen
18
+ * `Migration20260426T075235PriceListsPricingInit` while this module owns it —
19
+ * its `CustomerGroup` entity declares the table name — because tiered pricing
20
+ * needed customer groups first and created them where it needed them.
21
+ * The table was created by whoever needed it first rather than by whoever owns
22
+ * it, and the comment above used to record that as *"owned by price_lists"*.
23
+ *
24
+ * **Why this site is repaired while 27 other misfiled creations are not.**
25
+ * Moving a *reference* into its owner's module can only move it strictly later
26
+ * in the computed order, which is always safe; moving a *creation* moves it to
27
+ * a position every existing reference must be re-checked against. The other 27
28
+ * fail **safe** — a client omitting `catalog` gets an empty `products` table.
29
+ * This one also produced a fail-**closed** reference: the foreign key below
30
+ * named a table outside this module's closure, and declaring `price_lists`
31
+ * here to fix that would close a cycle, `price_lists` already declaring
32
+ * `customer_accounts`. That, and nothing else, is why it is on the list
33
+ * (owner's ruling, 2026-09-12).
34
+ *
35
+ * **The re-check, derived from the computed order rather than from a stamp.**
36
+ * The only reference to `customer_groups` in the entire corpus is this
37
+ * migration's own foreign key, three statements below. `price_lists` does not
38
+ * reference it: `price_list_assignments.customer_group_id` is a nullable column
39
+ * with an index and no foreign key, and so is `organizations.customer_group_id`.
40
+ * So the creation is placed in the frozen body that carries the only reference,
41
+ * above it, and every position in between is unaffected.
42
+ *
43
+ * **`if not exists`, and it is load-bearing.** A database that applied the
44
+ * April migration and has not yet reached this one already has the table while
45
+ * this migration is pending; a verbatim `create table` would fail there. Both
46
+ * class names are unchanged and `BASELINE_MIGRATIONS` is untouched —
47
+ * `mikro_orm_migrations` persists the class name and no checksum, so neither
48
+ * edited body is re-offered to a database that has applied it.
49
+ */
50
+ export class Migration20260611T140403CustomerAccountsLifecycle extends Migration {
51
+ async up() {
52
+ this.addSql(`
53
+ create table if not exists "customer_groups" (
54
+ "id" uuid not null,
55
+ "code" varchar(64) not null,
56
+ "name" varchar(160) not null,
57
+ "description" varchar(1000) null,
58
+ "created_at" timestamptz not null,
59
+ "updated_at" timestamptz not null,
60
+ constraint "customer_groups_pkey" primary key ("id"),
61
+ constraint "customer_groups_code_unique" unique ("code")
62
+ );
63
+ `);
64
+ this.addSql(`alter table "customer_accounts"
65
+ add column "customer_group_id" uuid null,
66
+ add column "blocked_at" timestamptz null,
67
+ add column "block_reason" text null,
68
+ add column "block_source" varchar(16) null,
69
+ add column "blocked_by_admin_user_id" uuid null,
70
+ add column "blocked_by_customer_account_id" uuid null,
71
+ add column "deletion_requested_by_admin_user_id" uuid null,
72
+ add column "anonymized_at" timestamptz null;`);
73
+ this.addSql(`alter table "customer_accounts"
74
+ add constraint "customer_accounts_customer_group_fk"
75
+ foreign key ("customer_group_id") references "customer_groups" ("id")
76
+ on update cascade on delete set null;`);
77
+ this.addSql(`create index "customer_accounts_customer_group_id_index" on "customer_accounts" ("customer_group_id");`);
78
+ this.addSql(`create index "customer_accounts_blocked_at_index" on "customer_accounts" ("blocked_at");`);
79
+ }
80
+ async down() {
81
+ this.addSql(`alter table "customer_accounts"
82
+ drop constraint if exists "customer_accounts_customer_group_fk";`);
83
+ this.addSql(`drop index if exists "customer_accounts_customer_group_id_index";`);
84
+ this.addSql(`drop index if exists "customer_accounts_blocked_at_index";`);
85
+ this.addSql(`alter table "customer_accounts"
86
+ drop column if exists "customer_group_id",
87
+ drop column if exists "blocked_at",
88
+ drop column if exists "block_reason",
89
+ drop column if exists "block_source",
90
+ drop column if exists "blocked_by_admin_user_id",
91
+ drop column if exists "blocked_by_customer_account_id",
92
+ drop column if exists "deletion_requested_by_admin_user_id",
93
+ drop column if exists "anonymized_at";`);
94
+ this.addSql('drop table if exists "customer_groups" cascade;');
95
+ }
96
+ }
97
+ //# sourceMappingURL=20260611T140403_customer_accounts_lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260611T140403_customer_accounts_lifecycle.js","sourceRoot":"","sources":["../../src/migrations/20260611T140403_customer_accounts_lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,OAAO,iDAAkD,SAAQ,SAAS;IACrE,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;KAWX,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC;;;;;;;;mDAQmC,CAAC,CAAC;QAEjD,IAAI,CAAC,MAAM,CAAC;;;4CAG4B,CAAC,CAAC;QAE1C,IAAI,CAAC,MAAM,CACT,wGAAwG,CACzG,CAAC;QACF,IAAI,CAAC,MAAM,CACT,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC;uEACuD,CAAC,CAAC;QACrE,IAAI,CAAC,MAAM,CAAC,mEAAmE,CAAC,CAAC;QACjF,IAAI,CAAC,MAAM,CAAC,4DAA4D,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,CAAC;;;;;;;;6CAQ6B,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 055 — Custom Fields Layer. Additive: adds the `custom_field_values`
4
+ * JSONB bag to `customer_accounts` so operator-defined fields persist on the host row.
5
+ * The column inherits the host entity's tenant classification (Principle XI);
6
+ * no scoping column is added.
7
+ */
8
+ export declare class Migration20260718T200341CustomerAccountsCustomerAccountCustomFieldValues extends Migration {
9
+ up(): Promise<void>;
10
+ down(): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts","sourceRoot":"","sources":["../../src/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;GAKG;AACH,qBAAa,wEAAyE,SAAQ,SAAS;IACtF,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAMnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
@@ -0,0 +1,16 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 055 — Custom Fields Layer. Additive: adds the `custom_field_values`
4
+ * JSONB bag to `customer_accounts` so operator-defined fields persist on the host row.
5
+ * The column inherits the host entity's tenant classification (Principle XI);
6
+ * no scoping column is added.
7
+ */
8
+ export class Migration20260718T200341CustomerAccountsCustomerAccountCustomFieldValues extends Migration {
9
+ async up() {
10
+ this.addSql(`alter table "customer_accounts" add column "custom_field_values" jsonb not null default '{}';`);
11
+ }
12
+ async down() {
13
+ this.addSql(`alter table "customer_accounts" drop column "custom_field_values";`);
14
+ }
15
+ }
16
+ //# sourceMappingURL=20260718T200341_customer_accounts_customer_account_custom_field_values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260718T200341_customer_accounts_customer_account_custom_field_values.js","sourceRoot":"","sources":["../../src/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,OAAO,wEAAyE,SAAQ,SAAS;IAC5F,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CACT,+FAA+F,CAChG,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,oEAAoE,CAAC,CAAC;IACpF,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 056 (T032) — customer-side roll-up capability.
4
+ *
5
+ * Adds `customer_accounts.subtree_rollup_enabled` (boolean, NOT NULL DEFAULT
6
+ * false). When true, the customer's tenant scope widens from single-org to its
7
+ * organization's subtree (server-derived, Principle XI). Default false ⇒ every
8
+ * existing customer stays node-only, preserving flat behavior byte-for-byte.
9
+ */
10
+ export declare class Migration20260720T044255CustomerAccountsCustomerSubtreeRollup extends Migration {
11
+ up(): Promise<void>;
12
+ down(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=20260720T044255_customer_accounts_customer_subtree_rollup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260720T044255_customer_accounts_customer_subtree_rollup.d.ts","sourceRoot":"","sources":["../../src/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;GAOG;AACH,qBAAa,6DAA8D,SAAQ,SAAS;IAC3E,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAMnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
@@ -0,0 +1,18 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 056 (T032) — customer-side roll-up capability.
4
+ *
5
+ * Adds `customer_accounts.subtree_rollup_enabled` (boolean, NOT NULL DEFAULT
6
+ * false). When true, the customer's tenant scope widens from single-org to its
7
+ * organization's subtree (server-derived, Principle XI). Default false ⇒ every
8
+ * existing customer stays node-only, preserving flat behavior byte-for-byte.
9
+ */
10
+ export class Migration20260720T044255CustomerAccountsCustomerSubtreeRollup extends Migration {
11
+ async up() {
12
+ this.addSql('alter table "customer_accounts" add column "subtree_rollup_enabled" boolean not null default false;');
13
+ }
14
+ async down() {
15
+ this.addSql('alter table "customer_accounts" drop column "subtree_rollup_enabled";');
16
+ }
17
+ }
18
+ //# sourceMappingURL=20260720T044255_customer_accounts_customer_subtree_rollup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260720T044255_customer_accounts_customer_subtree_rollup.js","sourceRoot":"","sources":["../../src/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,OAAO,6DAA8D,SAAQ,SAAS;IACjF,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CACT,qGAAqG,CACtG,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,uEAAuE,CAAC,CAAC;IACvF,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Issue #222 — `customer_accounts.password_set_at`.
4
+ *
5
+ * `password_hash` is NOT NULL for every account, including the ones federated
6
+ * sign-in auto-creates with a random pair of UUIDs nobody is told, so it cannot
7
+ * answer "does the holder have a password they can use". This column can.
8
+ *
9
+ * **Backfilled `null` for every existing row, with no conditional logic.** The
10
+ * alternative considered was `created_at` for everyone except accounts holding
11
+ * a social link — but there are no socially-created accounts anywhere, so that
12
+ * exception has an empty extension and what would actually ship is `created_at`
13
+ * for *every* row: the claim that every existing holder personally chose their
14
+ * password, which is untrue for any account an admin, an import or any other
15
+ * on-their-behalf path created. `null` says what is true — we do not know — and
16
+ * becomes accurate for every account from the first write onwards.
17
+ */
18
+ export declare class Migration20260819T074816CustomerAccountsPasswordSetAt extends Migration {
19
+ up(): Promise<void>;
20
+ down(): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=20260819T074816_customer_accounts_password_set_at.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260819T074816_customer_accounts_password_set_at.d.ts","sourceRoot":"","sources":["../../src/migrations/20260819T074816_customer_accounts_password_set_at.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,qDAAsD,SAAQ,SAAS;IACnE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAInB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
@@ -0,0 +1,26 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Issue #222 — `customer_accounts.password_set_at`.
4
+ *
5
+ * `password_hash` is NOT NULL for every account, including the ones federated
6
+ * sign-in auto-creates with a random pair of UUIDs nobody is told, so it cannot
7
+ * answer "does the holder have a password they can use". This column can.
8
+ *
9
+ * **Backfilled `null` for every existing row, with no conditional logic.** The
10
+ * alternative considered was `created_at` for everyone except accounts holding
11
+ * a social link — but there are no socially-created accounts anywhere, so that
12
+ * exception has an empty extension and what would actually ship is `created_at`
13
+ * for *every* row: the claim that every existing holder personally chose their
14
+ * password, which is untrue for any account an admin, an import or any other
15
+ * on-their-behalf path created. `null` says what is true — we do not know — and
16
+ * becomes accurate for every account from the first write onwards.
17
+ */
18
+ export class Migration20260819T074816CustomerAccountsPasswordSetAt extends Migration {
19
+ async up() {
20
+ this.addSql('alter table "customer_accounts" add column "password_set_at" timestamptz null;');
21
+ }
22
+ async down() {
23
+ this.addSql('alter table "customer_accounts" drop column "password_set_at";');
24
+ }
25
+ }
26
+ //# sourceMappingURL=20260819T074816_customer_accounts_password_set_at.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260819T074816_customer_accounts_password_set_at.js","sourceRoot":"","sources":["../../src/migrations/20260819T074816_customer_accounts_password_set_at.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,qDAAsD,SAAQ,SAAS;IACzE,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC,gFAAgF,CAAC,CAAC;IAChG,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAC;IAChF,CAAC;CACF"}
@@ -0,0 +1,46 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Fold `customer_accounts.email` to the form the code now stores and compares.
4
+ *
5
+ * The writes folded the address and the login read did not, so a buyer who
6
+ * registered as `Jan.Kowalski@example.pl` could never sign in: Postgres' `=` on
7
+ * `text` is case-sensitive and the row said `jan.kowalski@example.pl`. The code
8
+ * side of the repair makes every read and every write go through
9
+ * `normalizeEmailAddress`; this migration brings the rows written before it to
10
+ * the same form, so an address stored mixed-case stays reachable.
11
+ *
12
+ * ## What a collision means, and why it does not fail the deploy
13
+ *
14
+ * Two rows differing only in case are two accounts that the fold turns into one
15
+ * address, and `customer_accounts_email_unique` will not hold both. The
16
+ * migration therefore **folds one row per address and leaves the rest exactly as
17
+ * they are** — it drops nothing, merges nothing and refuses nothing:
18
+ *
19
+ * - a row that **already holds the folded address** wins it, because it is the
20
+ * one every other table's foreign keys have been resolving to by that
21
+ * address all along;
22
+ * - otherwise the **earliest-created** row wins it, since it is the account
23
+ * with the longer history of orders, invoices and addresses behind it;
24
+ * - every other row in the group keeps its stored spelling and is counted by
25
+ * the warning below.
26
+ *
27
+ * A stranded row is not data loss but it is not a working account either: the
28
+ * login read folds, so nothing will match its spelling until an operator merges
29
+ * or renames it. That is a decision about somebody's orders, and a migration
30
+ * running unattended must not take it. The alternative — failing the deploy —
31
+ * would stop every other repair in the same release over a pair of rows that a
32
+ * human has to look at anyway.
33
+ *
34
+ * ## Measured before it was written
35
+ *
36
+ * Zero collisions and zero mixed-case rows across both developer databases
37
+ * (`b2b`: 1 account; `b2b_test`: 3), which is what the two-developer-environment
38
+ * / no-production state of the platform predicts. The rules above are therefore
39
+ * written for the environments this will meet later, not for a pair of rows
40
+ * anybody has today.
41
+ */
42
+ export declare class Migration20260819T142837CustomerAccountsFoldEmailCase extends Migration {
43
+ up(): Promise<void>;
44
+ down(): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=20260819T142837_customer_accounts_fold_email_case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260819T142837_customer_accounts_fold_email_case.d.ts","sourceRoot":"","sources":["../../src/migrations/20260819T142837_customer_accounts_fold_email_case.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,qDAAsD,SAAQ,SAAS;IACnE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IA+CnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQrC"}
@@ -0,0 +1,97 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Fold `customer_accounts.email` to the form the code now stores and compares.
4
+ *
5
+ * The writes folded the address and the login read did not, so a buyer who
6
+ * registered as `Jan.Kowalski@example.pl` could never sign in: Postgres' `=` on
7
+ * `text` is case-sensitive and the row said `jan.kowalski@example.pl`. The code
8
+ * side of the repair makes every read and every write go through
9
+ * `normalizeEmailAddress`; this migration brings the rows written before it to
10
+ * the same form, so an address stored mixed-case stays reachable.
11
+ *
12
+ * ## What a collision means, and why it does not fail the deploy
13
+ *
14
+ * Two rows differing only in case are two accounts that the fold turns into one
15
+ * address, and `customer_accounts_email_unique` will not hold both. The
16
+ * migration therefore **folds one row per address and leaves the rest exactly as
17
+ * they are** — it drops nothing, merges nothing and refuses nothing:
18
+ *
19
+ * - a row that **already holds the folded address** wins it, because it is the
20
+ * one every other table's foreign keys have been resolving to by that
21
+ * address all along;
22
+ * - otherwise the **earliest-created** row wins it, since it is the account
23
+ * with the longer history of orders, invoices and addresses behind it;
24
+ * - every other row in the group keeps its stored spelling and is counted by
25
+ * the warning below.
26
+ *
27
+ * A stranded row is not data loss but it is not a working account either: the
28
+ * login read folds, so nothing will match its spelling until an operator merges
29
+ * or renames it. That is a decision about somebody's orders, and a migration
30
+ * running unattended must not take it. The alternative — failing the deploy —
31
+ * would stop every other repair in the same release over a pair of rows that a
32
+ * human has to look at anyway.
33
+ *
34
+ * ## Measured before it was written
35
+ *
36
+ * Zero collisions and zero mixed-case rows across both developer databases
37
+ * (`b2b`: 1 account; `b2b_test`: 3), which is what the two-developer-environment
38
+ * / no-production state of the platform predicts. The rules above are therefore
39
+ * written for the environments this will meet later, not for a pair of rows
40
+ * anybody has today.
41
+ */
42
+ export class Migration20260819T142837CustomerAccountsFoldEmailCase extends Migration {
43
+ async up() {
44
+ // One winner per folded address: a row that already holds it first
45
+ // (`email = folded` sorts true-first under `desc`), then the earliest
46
+ // created, then the smallest id so the choice is deterministic. The winner
47
+ // is only updated when it does not already hold the folded value, which is
48
+ // also why this statement cannot violate the unique index: an update
49
+ // happens only for a group in which no row holds the target address.
50
+ this.addSql(`
51
+ with ranked as (
52
+ select "id",
53
+ lower(btrim("email")) as folded,
54
+ row_number() over (
55
+ partition by lower(btrim("email"))
56
+ order by ("email" = lower(btrim("email"))) desc,
57
+ "created_at" asc,
58
+ "id" asc
59
+ ) as rank
60
+ from "customer_accounts"
61
+ )
62
+ update "customer_accounts" ca
63
+ set "email" = r.folded
64
+ from ranked r
65
+ where r."id" = ca."id"
66
+ and r.rank = 1
67
+ and ca."email" <> r.folded;
68
+ `);
69
+ // Say out loud what was left behind. A migration that quietly leaves an
70
+ // account nobody can log into is the same class of defect as the one being
71
+ // repaired here.
72
+ this.addSql(`
73
+ do $$
74
+ declare
75
+ stranded integer;
76
+ begin
77
+ select count(*) into stranded
78
+ from "customer_accounts"
79
+ where "email" <> lower(btrim("email"));
80
+ if stranded > 0 then
81
+ raise warning
82
+ 'customer_accounts: % row(s) kept a mixed-case e-mail because another account already holds the folded address. They cannot be signed into until an operator merges or renames them.',
83
+ stranded;
84
+ end if;
85
+ end $$;
86
+ `);
87
+ }
88
+ async down() {
89
+ // Deliberately empty. The original capitalisation is not recorded anywhere
90
+ // — this migration overwrites the only copy of it — so there is nothing to
91
+ // restore, and an `up` that folded a handful of rows must not be paired
92
+ // with a `down` that pretends otherwise. Rolling this back means rolling
93
+ // back the code that reads the folded form; the rows are then already in
94
+ // the shape the old code wrote, which is what it was folding to anyway.
95
+ }
96
+ }
97
+ //# sourceMappingURL=20260819T142837_customer_accounts_fold_email_case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260819T142837_customer_accounts_fold_email_case.js","sourceRoot":"","sources":["../../src/migrations/20260819T142837_customer_accounts_fold_email_case.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,OAAO,qDAAsD,SAAQ,SAAS;IACzE,KAAK,CAAC,EAAE;QACf,mEAAmE;QACnE,sEAAsE;QACtE,2EAA2E;QAC3E,2EAA2E;QAC3E,qEAAqE;QACrE,qEAAqE;QACrE,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;KAkBX,CAAC,CAAC;QAEH,wEAAwE;QACxE,2EAA2E;QAC3E,iBAAiB;QACjB,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;KAcX,CAAC,CAAC;IACL,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,2EAA2E;QAC3E,2EAA2E;QAC3E,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,wEAAwE;IAC1E,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Drops `customer_accounts.two_factor_secret`, the superseded customer 2FA
4
+ * column.
5
+ *
6
+ * The column could never hold a value. `POST /api/v1/me/two-factor/enable`,
7
+ * the only writer, assembled `<32-char base32 secret>|<10 sha256 hashes>` —
8
+ * 682 characters — and the column is `varchar(64)`, on which PostgreSQL
9
+ * raises `22001` rather than truncating. So the route answered 500 for every
10
+ * customer from the day it was written, and the routes, the port and the
11
+ * service that owned it are deleted in the same merge request. The live
12
+ * customer 2FA surface is `mfa`'s `/api/v1/account/mfa/*`, whose own init
13
+ * migration already records these columns as SUPERSEDED.
14
+ *
15
+ * **Nothing is destroyed.** Measured on the dev database on 2026-08-25:
16
+ * `customer_accounts` holds 1 row, of which `count(two_factor_secret)` is 0.
17
+ * `deploy/` carries `example` and `acceptance` only — there is no client
18
+ * deployment and no production database. `down()` therefore re-creates the
19
+ * column's shape and nothing else, because there has never been a value to
20
+ * restore.
21
+ *
22
+ * `two_factor_confirmed_at` deliberately stays: it still feeds a published
23
+ * `twoFactorEnabled` field on six API responses and two admin screens, and
24
+ * what happens to that field is an open owner decision
25
+ * (`specs/087-tenant-scope-enforcement/superseded-2fa-analysis.md` §7).
26
+ */
27
+ export declare class Migration20260825T124759CustomerAccountsDropLegacyTwoFactorSecret extends Migration {
28
+ up(): Promise<void>;
29
+ down(): Promise<void>;
30
+ }
31
+ //# sourceMappingURL=20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts","sourceRoot":"","sources":["../../src/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iEAAkE,SAAQ,SAAS;IAC/E,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAInB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
@@ -0,0 +1,35 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Drops `customer_accounts.two_factor_secret`, the superseded customer 2FA
4
+ * column.
5
+ *
6
+ * The column could never hold a value. `POST /api/v1/me/two-factor/enable`,
7
+ * the only writer, assembled `<32-char base32 secret>|<10 sha256 hashes>` —
8
+ * 682 characters — and the column is `varchar(64)`, on which PostgreSQL
9
+ * raises `22001` rather than truncating. So the route answered 500 for every
10
+ * customer from the day it was written, and the routes, the port and the
11
+ * service that owned it are deleted in the same merge request. The live
12
+ * customer 2FA surface is `mfa`'s `/api/v1/account/mfa/*`, whose own init
13
+ * migration already records these columns as SUPERSEDED.
14
+ *
15
+ * **Nothing is destroyed.** Measured on the dev database on 2026-08-25:
16
+ * `customer_accounts` holds 1 row, of which `count(two_factor_secret)` is 0.
17
+ * `deploy/` carries `example` and `acceptance` only — there is no client
18
+ * deployment and no production database. `down()` therefore re-creates the
19
+ * column's shape and nothing else, because there has never been a value to
20
+ * restore.
21
+ *
22
+ * `two_factor_confirmed_at` deliberately stays: it still feeds a published
23
+ * `twoFactorEnabled` field on six API responses and two admin screens, and
24
+ * what happens to that field is an open owner decision
25
+ * (`specs/087-tenant-scope-enforcement/superseded-2fa-analysis.md` §7).
26
+ */
27
+ export class Migration20260825T124759CustomerAccountsDropLegacyTwoFactorSecret extends Migration {
28
+ async up() {
29
+ this.addSql(`alter table "customer_accounts" drop column "two_factor_secret";`);
30
+ }
31
+ async down() {
32
+ this.addSql(`alter table "customer_accounts" add column "two_factor_secret" varchar(64) null;`);
33
+ }
34
+ }
35
+ //# sourceMappingURL=20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js","sourceRoot":"","sources":["../../src/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,OAAO,iEAAkE,SAAQ,SAAS;IACrF,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC,kEAAkE,CAAC,CAAC;IAClF,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,kFAAkF,CAAC,CAAC;IAClG,CAAC;CACF"}
@@ -0,0 +1,58 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * D-178 — `customer_accounts.organization_id` becomes `NOT NULL`.
4
+ *
5
+ * The column was relaxed by `20260611T140351_customer_accounts_organization_optional`
6
+ * for feature 026 US2 ("Customer accounts may exist without an Organization"), a
7
+ * design feature 051 replaced and D-178 confirms is dead: every transacting
8
+ * customer is backed by an Organization, an individual by a single-member
9
+ * **personal** one, and there is no "no-organization" scoping path
10
+ * (Constitution XI).
11
+ *
12
+ * **The constraint is the only refusal available.** MikroORM applies its tenant
13
+ * filter to `SELECT` / `UPDATE` / `DELETE` and not to `INSERT`, so no guard can
14
+ * stop a tenant-less account being written; the column can.
15
+ *
16
+ * ## Provision, then count, then refuse — never delete
17
+ *
18
+ * These rows are customer logins: a person's credentials, the owner of their
19
+ * order history and the parent of their address book. A migration that deleted
20
+ * one to satisfy a constraint would be deleting a customer, so this one
21
+ * provisions instead and raises on whatever it could not provision.
22
+ *
23
+ * Feature 051's backfill
24
+ * (`organizations/20260717T151403_organizations_personal_organizations`) ran the
25
+ * same provisioning once. It closed the population as of the moment it ran and
26
+ * closed no write path, so three producers went on filling it: standalone
27
+ * registration's two-flush window, federated sign-in (which provisioned no
28
+ * organisation at all), and the admin "un-assign" button. All three are closed
29
+ * in the merge request that carries this migration — without that, the
30
+ * constraint would convert three silent defects into three runtime failures.
31
+ *
32
+ * Two deliberate differences from that backfill:
33
+ *
34
+ * - **Soft-deleted accounts are included.** 051 skipped them with its own
35
+ * `and ca."deleted_at" is null`. A soft-deleted row still has to satisfy the
36
+ * constraint, and `customer_account.restored` would otherwise resurrect an
37
+ * account the platform cannot scope.
38
+ * - **The insert skips an account whose personal organisation already exists**,
39
+ * and a second statement links it. `tax_id` is derived from the account id
40
+ * and is globally unique, so an account that was provisioned once and then
41
+ * un-assigned would otherwise collide — the migration would abort on a
42
+ * constraint violation rather than on the sentence it wants to say.
43
+ *
44
+ * The provisioning mirrors `PersonalOrganizationService.provisionFor`: name from
45
+ * the trimmed "first last" or else the e-mail local part, `tax_id` the account
46
+ * UUID with the dashes stripped (32 hex characters — an individual has no
47
+ * company tax id), `vat_status = 'vat_exempt'`, `status = 'active'`,
48
+ * `is_personal = true`, and the placeholder registered address the column's
49
+ * `not null` demands.
50
+ *
51
+ * `organizations` is a hard `dependencies` entry of this module's manifest, so
52
+ * that module's tables exist by the time this runs.
53
+ */
54
+ export declare class Migration20260825T141659CustomerAccountsOrganizationRequired extends Migration {
55
+ up(): Promise<void>;
56
+ down(): Promise<void>;
57
+ }
58
+ //# sourceMappingURL=20260825T141659_customer_accounts_organization_required.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260825T141659_customer_accounts_organization_required.d.ts","sourceRoot":"","sources":["../../src/migrations/20260825T141659_customer_accounts_organization_required.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,qBAAa,4DAA6D,SAAQ,SAAS;IAC1E,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IA0EnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAOrC"}