@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.
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/api/customer-groups-client.d.ts +27 -0
- package/dist/admin/api/customer-groups-client.d.ts.map +1 -0
- package/dist/admin/api/customer-groups-client.js +17 -0
- package/dist/admin/api/customer-groups-client.js.map +1 -0
- package/dist/admin/index.d.ts +33 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +38 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/CustomerGroupsPage.d.ts +18 -0
- package/dist/admin/pages/CustomerGroupsPage.d.ts.map +1 -0
- package/dist/admin/pages/CustomerGroupsPage.js +108 -0
- package/dist/admin/pages/CustomerGroupsPage.js.map +1 -0
- package/dist/backend/entities/customer-account.entity.d.ts +111 -0
- package/dist/backend/entities/customer-account.entity.d.ts.map +1 -0
- package/dist/backend/entities/customer-account.entity.js +230 -0
- package/dist/backend/entities/customer-account.entity.js.map +1 -0
- package/dist/backend/entities/customer-group.entity.d.ts +29 -0
- package/dist/backend/entities/customer-group.entity.d.ts.map +1 -0
- package/dist/backend/entities/customer-group.entity.js +70 -0
- package/dist/backend/entities/customer-group.entity.js.map +1 -0
- package/dist/backend/entities/password-reset-token.entity.d.ts +16 -0
- package/dist/backend/entities/password-reset-token.entity.d.ts.map +1 -0
- package/dist/backend/entities/password-reset-token.entity.js +59 -0
- package/dist/backend/entities/password-reset-token.entity.js.map +1 -0
- package/dist/backend/index.d.ts +144 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +407 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +26 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +35 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/services/audit-references.d.ts +22 -0
- package/dist/backend/services/audit-references.d.ts.map +1 -0
- package/dist/backend/services/audit-references.js +46 -0
- package/dist/backend/services/audit-references.js.map +1 -0
- package/dist/backend/services/customer-account-lifecycle-ports.d.ts +168 -0
- package/dist/backend/services/customer-account-lifecycle-ports.d.ts.map +1 -0
- package/dist/backend/services/customer-account-lifecycle-ports.js +420 -0
- package/dist/backend/services/customer-account-lifecycle-ports.js.map +1 -0
- package/dist/backend/services/customer-account-ports.d.ts +143 -0
- package/dist/backend/services/customer-account-ports.d.ts.map +1 -0
- package/dist/backend/services/customer-account-ports.js +422 -0
- package/dist/backend/services/customer-account-ports.js.map +1 -0
- package/dist/backend/services/customer-auth-service.d.ts +62 -0
- package/dist/backend/services/customer-auth-service.d.ts.map +1 -0
- package/dist/backend/services/customer-auth-service.js +105 -0
- package/dist/backend/services/customer-auth-service.js.map +1 -0
- package/dist/backend/services/customer-group-read-port.d.ts +24 -0
- package/dist/backend/services/customer-group-read-port.d.ts.map +1 -0
- package/dist/backend/services/customer-group-read-port.js +44 -0
- package/dist/backend/services/customer-group-read-port.js.map +1 -0
- package/dist/backend/services/customer-group-service.d.ts +21 -0
- package/dist/backend/services/customer-group-service.d.ts.map +1 -0
- package/dist/backend/services/customer-group-service.js +97 -0
- package/dist/backend/services/customer-group-service.js.map +1 -0
- package/dist/backend/services/customer-rollup-scope.d.ts +30 -0
- package/dist/backend/services/customer-rollup-scope.d.ts.map +1 -0
- package/dist/backend/services/customer-rollup-scope.js +42 -0
- package/dist/backend/services/customer-rollup-scope.js.map +1 -0
- package/dist/backend/services/password-reset-service.d.ts +15 -0
- package/dist/backend/services/password-reset-service.d.ts.map +1 -0
- package/dist/backend/services/password-reset-service.js +90 -0
- package/dist/backend/services/password-reset-service.js.map +1 -0
- package/dist/backend/services/role-service.d.ts +22 -0
- package/dist/backend/services/role-service.d.ts.map +1 -0
- package/dist/backend/services/role-service.js +83 -0
- package/dist/backend/services/role-service.js.map +1 -0
- package/dist/backend/services/two-factor-enrolments.d.ts +18 -0
- package/dist/backend/services/two-factor-enrolments.d.ts.map +1 -0
- package/dist/backend/services/two-factor-enrolments.js +2 -0
- package/dist/backend/services/two-factor-enrolments.js.map +1 -0
- package/dist/manifest.d.ts +169 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +212 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.d.ts +6 -0
- package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.d.ts.map +1 -0
- package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.js +25 -0
- package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.js.map +1 -0
- package/dist/migrations/20260611T140351_customer_accounts_organization_optional.d.ts +34 -0
- package/dist/migrations/20260611T140351_customer_accounts_organization_optional.d.ts.map +1 -0
- package/dist/migrations/20260611T140351_customer_accounts_organization_optional.js +43 -0
- package/dist/migrations/20260611T140351_customer_accounts_organization_optional.js.map +1 -0
- package/dist/migrations/20260611T140403_customer_accounts_lifecycle.d.ts +54 -0
- package/dist/migrations/20260611T140403_customer_accounts_lifecycle.d.ts.map +1 -0
- package/dist/migrations/20260611T140403_customer_accounts_lifecycle.js +97 -0
- package/dist/migrations/20260611T140403_customer_accounts_lifecycle.js.map +1 -0
- package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts +12 -0
- package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts.map +1 -0
- package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.js +16 -0
- package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.js.map +1 -0
- package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.d.ts +14 -0
- package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.d.ts.map +1 -0
- package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.js +18 -0
- package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.js.map +1 -0
- package/dist/migrations/20260819T074816_customer_accounts_password_set_at.d.ts +22 -0
- package/dist/migrations/20260819T074816_customer_accounts_password_set_at.d.ts.map +1 -0
- package/dist/migrations/20260819T074816_customer_accounts_password_set_at.js +26 -0
- package/dist/migrations/20260819T074816_customer_accounts_password_set_at.js.map +1 -0
- package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.d.ts +46 -0
- package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.d.ts.map +1 -0
- package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.js +97 -0
- package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.js.map +1 -0
- package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts +31 -0
- package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts.map +1 -0
- package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js +35 -0
- package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js.map +1 -0
- package/dist/migrations/20260825T141659_customer_accounts_organization_required.d.ts +58 -0
- package/dist/migrations/20260825T141659_customer_accounts_organization_required.d.ts.map +1 -0
- package/dist/migrations/20260825T141659_customer_accounts_organization_required.js +133 -0
- package/dist/migrations/20260825T141659_customer_accounts_organization_required.js.map +1 -0
- package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.d.ts +27 -0
- package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.d.ts.map +1 -0
- package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.js +44 -0
- package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.js.map +1 -0
- package/dist/migrations/index.d.ts +36 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +47 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/customer_accounts.md +38 -0
- package/i18n/en.json +30 -0
- package/i18n/pl.json +30 -0
- package/package.json +94 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ERROR_CODES } from '@endora-commerce/contracts';
|
|
2
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
3
|
+
import { CustomerAccount } from '../entities/customer-account.entity.js';
|
|
4
|
+
import { recordAuditFromContext } from '@endora-commerce/platform/commands';
|
|
5
|
+
/**
|
|
6
|
+
* RoleService (T174).
|
|
7
|
+
*
|
|
8
|
+
* Members management on the buyer side. Two safety guards:
|
|
9
|
+
* - CANNOT_REMOVE_LAST_ADMIN — DELETE on the only `organization_admin`
|
|
10
|
+
* member of an org returns 409.
|
|
11
|
+
* - CANNOT_DEMOTE_LAST_ADMIN — PATCH /role downgrading the only
|
|
12
|
+
* `organization_admin` returns 409.
|
|
13
|
+
*/
|
|
14
|
+
export class RoleService {
|
|
15
|
+
emFactory;
|
|
16
|
+
auditLog;
|
|
17
|
+
constructor(emFactory, auditLog) {
|
|
18
|
+
this.emFactory = emFactory;
|
|
19
|
+
this.auditLog = auditLog;
|
|
20
|
+
}
|
|
21
|
+
#audit(em, action, objectId, stateBefore, stateAfter) {
|
|
22
|
+
if (this.auditLog) {
|
|
23
|
+
recordAuditFromContext(this.auditLog, em, {
|
|
24
|
+
action,
|
|
25
|
+
objectType: 'customer_account',
|
|
26
|
+
objectId,
|
|
27
|
+
stateBefore,
|
|
28
|
+
stateAfter,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async listMembers(organizationId) {
|
|
33
|
+
const em = this.emFactory();
|
|
34
|
+
return em.find(CustomerAccount, { organizationId, deletedAt: null }, { orderBy: { role: 'asc', createdAt: 'asc' } });
|
|
35
|
+
}
|
|
36
|
+
async changeRole(organizationId, targetCustomerAccountId, newRole) {
|
|
37
|
+
const em = this.emFactory();
|
|
38
|
+
const target = await em.findOne(CustomerAccount, {
|
|
39
|
+
id: targetCustomerAccountId,
|
|
40
|
+
organizationId,
|
|
41
|
+
deletedAt: null,
|
|
42
|
+
});
|
|
43
|
+
if (!target) {
|
|
44
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Member not found.');
|
|
45
|
+
}
|
|
46
|
+
if (target.role === 'organization_admin' &&
|
|
47
|
+
newRole === 'regular_user' &&
|
|
48
|
+
(await this.#countAdmins(em, organizationId)) === 1) {
|
|
49
|
+
throw new HttpError(409, ERROR_CODES.CANNOT_DEMOTE_LAST_ADMIN, 'Cannot demote the only organization admin.');
|
|
50
|
+
}
|
|
51
|
+
const previousRole = target.role;
|
|
52
|
+
target.role = newRole;
|
|
53
|
+
this.#audit(em, 'customer_account.change_role', target.id, { role: previousRole }, { role: newRole });
|
|
54
|
+
await em.flush();
|
|
55
|
+
return target;
|
|
56
|
+
}
|
|
57
|
+
async removeMember(organizationId, targetCustomerAccountId) {
|
|
58
|
+
const em = this.emFactory();
|
|
59
|
+
const target = await em.findOne(CustomerAccount, {
|
|
60
|
+
id: targetCustomerAccountId,
|
|
61
|
+
organizationId,
|
|
62
|
+
deletedAt: null,
|
|
63
|
+
});
|
|
64
|
+
if (!target) {
|
|
65
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Member not found.');
|
|
66
|
+
}
|
|
67
|
+
if (target.role === 'organization_admin' &&
|
|
68
|
+
(await this.#countAdmins(em, organizationId)) === 1) {
|
|
69
|
+
throw new HttpError(409, ERROR_CODES.CANNOT_REMOVE_LAST_ADMIN, 'Cannot remove the only organization admin.');
|
|
70
|
+
}
|
|
71
|
+
target.deletedAt = new Date();
|
|
72
|
+
this.#audit(em, 'customer_account.remove_member', target.id, { role: target.role }, null);
|
|
73
|
+
await em.flush();
|
|
74
|
+
}
|
|
75
|
+
async #countAdmins(em, organizationId) {
|
|
76
|
+
return em.count(CustomerAccount, {
|
|
77
|
+
organizationId,
|
|
78
|
+
role: 'organization_admin',
|
|
79
|
+
deletedAt: null,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=role-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-service.js","sourceRoot":"","sources":["../../../src/backend/services/role-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which customer accounts hold a second factor — this module's own view of a
|
|
3
|
+
* fact `mfa` owns.
|
|
4
|
+
*
|
|
5
|
+
* A function type rather than an interface, and not shared with `admin_users`,
|
|
6
|
+
* because there is nothing to share: the published shape is
|
|
7
|
+
* `MfaEnrolmentStatePort` in `@endora-commerce/contracts`, and this is only the
|
|
8
|
+
* shape in which *this* module's mapper wants the answer — `subjectType` is
|
|
9
|
+
* already decided, and a `Set` is what a list surface asks per row.
|
|
10
|
+
*
|
|
11
|
+
* `backend.ts` builds the one implementation: it decides `mfa`'s presence and
|
|
12
|
+
* then resolves the port, so an absent owner produces an empty set rather than
|
|
13
|
+
* a `ModuleDisabledError` on a customer's own account page. That is a declared
|
|
14
|
+
* degrade — see the `degrades-without` entry for `mfaEnrolmentStatePort` in
|
|
15
|
+
* this module's manifest — and not a caught gate.
|
|
16
|
+
*/
|
|
17
|
+
export type TwoFactorEnrolmentReader = (customerAccountIds: readonly string[]) => Promise<ReadonlySet<string>>;
|
|
18
|
+
//# sourceMappingURL=two-factor-enrolments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"two-factor-enrolments.d.ts","sourceRoot":"","sources":["../../../src/backend/services/two-factor-enrolments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,kBAAkB,EAAE,SAAS,MAAM,EAAE,KAClC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"two-factor-enrolments.js","sourceRoot":"","sources":["../../../src/backend/services/two-factor-enrolments.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Customer Accounts module — manifest backfill (Module Lifecycle, feature 018).
|
|
3
|
+
*
|
|
4
|
+
* Predates the lifecycle system; this manifest is the static record
|
|
5
|
+
* required so the module participates in the registry. No install /
|
|
6
|
+
* uninstall hook today — the module's schema is owned by earlier
|
|
7
|
+
* platform-wide migrations.
|
|
8
|
+
*/
|
|
9
|
+
export declare const manifest: {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
dependencies: string[];
|
|
14
|
+
description?: string | undefined;
|
|
15
|
+
acknowledgedDependencies?: {
|
|
16
|
+
moduleId: string;
|
|
17
|
+
port: string;
|
|
18
|
+
reason: string;
|
|
19
|
+
}[] | undefined;
|
|
20
|
+
nonBindingDependencies?: {
|
|
21
|
+
moduleId: string;
|
|
22
|
+
name: string;
|
|
23
|
+
kind: "contributes-to" | "degrades-without" | "refuses-without";
|
|
24
|
+
reason: string;
|
|
25
|
+
whenAbsent?: string | undefined;
|
|
26
|
+
}[] | undefined;
|
|
27
|
+
activation?: {
|
|
28
|
+
settingCode: string;
|
|
29
|
+
default: boolean;
|
|
30
|
+
} | {
|
|
31
|
+
nonDeactivatable: true;
|
|
32
|
+
reason: string;
|
|
33
|
+
} | undefined;
|
|
34
|
+
settings?: {
|
|
35
|
+
moduleCode: string;
|
|
36
|
+
groups: {
|
|
37
|
+
code: string;
|
|
38
|
+
name: string;
|
|
39
|
+
salesChannelCodes?: string[] | undefined;
|
|
40
|
+
isSystemProtected?: boolean | undefined;
|
|
41
|
+
}[];
|
|
42
|
+
settings: {
|
|
43
|
+
code: string;
|
|
44
|
+
name: string;
|
|
45
|
+
valueType: "string" | "number" | "boolean" | "json" | "string_list" | "secret" | "credential_ref";
|
|
46
|
+
defaultValue: unknown;
|
|
47
|
+
description?: string | undefined;
|
|
48
|
+
groupCode?: string | undefined;
|
|
49
|
+
previousDefaultValues?: unknown[] | undefined;
|
|
50
|
+
salesChannelCodes?: string[] | undefined;
|
|
51
|
+
enumOptions?: string[] | undefined;
|
|
52
|
+
configurationType?: string | undefined;
|
|
53
|
+
hidden?: boolean | undefined;
|
|
54
|
+
}[];
|
|
55
|
+
} | undefined;
|
|
56
|
+
i18n?: {
|
|
57
|
+
bundlesDir: string;
|
|
58
|
+
} | undefined;
|
|
59
|
+
docs?: false | {
|
|
60
|
+
dir: string;
|
|
61
|
+
} | undefined;
|
|
62
|
+
demo?: false | {
|
|
63
|
+
summary: string;
|
|
64
|
+
seed: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoSeedResult>;
|
|
65
|
+
reset: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoResetResult>;
|
|
66
|
+
after?: readonly string[] | undefined;
|
|
67
|
+
package?: string | undefined;
|
|
68
|
+
} | undefined;
|
|
69
|
+
actions?: {
|
|
70
|
+
id: string;
|
|
71
|
+
labelKey: string;
|
|
72
|
+
icon: "Plus" | "Sparkles" | "Settings" | "Search" | "Boxes" | "Layers" | "Menu" | "PlusCircle" | "PlusSquare" | "FilePlus" | "FolderPlus" | "Upload" | "FileUp" | "CloudUpload" | "Download" | "FileDown" | "FileText" | "BookOpen" | "Rss" | "Package" | "Tag" | "ShoppingCart" | "Receipt" | "CreditCard" | "Users" | "UserPlus" | "Inbox" | "ListChecks" | "ClipboardList" | "Image" | "Video" | "LayoutDashboard" | "PanelLeft" | "KeyRound" | "ShieldCheck" | "Edit" | "Archive" | "Box" | "Truck" | "CircleDollarSign" | "Activity" | "LineChart" | "Smartphone" | "Webhook" | "Scale" | "PlugZap" | "PercentDiamond" | "Newspaper" | "Languages" | "Eraser" | "Warehouse" | "TrendingDown" | "Bell" | "PackageOpen" | "Building2" | "Store" | "ClipboardCheck";
|
|
73
|
+
targetRoute: string;
|
|
74
|
+
keywords: string[];
|
|
75
|
+
weight: number;
|
|
76
|
+
descriptionKey?: string | undefined;
|
|
77
|
+
requiredPermission?: string | undefined;
|
|
78
|
+
}[] | undefined;
|
|
79
|
+
permissions?: {
|
|
80
|
+
code: string;
|
|
81
|
+
label: string;
|
|
82
|
+
module?: string | undefined;
|
|
83
|
+
description?: string | undefined;
|
|
84
|
+
requires?: string[] | undefined;
|
|
85
|
+
}[] | undefined;
|
|
86
|
+
transactionalEmails?: {
|
|
87
|
+
code: string;
|
|
88
|
+
name: string;
|
|
89
|
+
variables: {
|
|
90
|
+
key: string;
|
|
91
|
+
label: string;
|
|
92
|
+
sampleValue?: string | undefined;
|
|
93
|
+
description?: string | undefined;
|
|
94
|
+
}[];
|
|
95
|
+
description?: string | undefined;
|
|
96
|
+
group?: string | undefined;
|
|
97
|
+
}[] | undefined;
|
|
98
|
+
capabilities?: string[] | undefined;
|
|
99
|
+
exclusiveCapabilities?: {
|
|
100
|
+
key: string;
|
|
101
|
+
errorCode: string;
|
|
102
|
+
}[] | undefined;
|
|
103
|
+
errorCodes?: {
|
|
104
|
+
code: string;
|
|
105
|
+
tokens?: string[] | undefined;
|
|
106
|
+
}[] | undefined;
|
|
107
|
+
blocks?: {
|
|
108
|
+
name: string;
|
|
109
|
+
labelKey: string;
|
|
110
|
+
category: string;
|
|
111
|
+
contexts: ("email" | "invoice" | "cms" | "newsletter")[];
|
|
112
|
+
fields: Record<string, {
|
|
113
|
+
type: "number" | "object" | "array" | "text" | "textarea" | "select" | "radio" | "external" | "uuid" | "richtext";
|
|
114
|
+
label?: string | undefined;
|
|
115
|
+
required?: boolean | undefined;
|
|
116
|
+
options?: {
|
|
117
|
+
label: string;
|
|
118
|
+
value: string | number;
|
|
119
|
+
}[] | undefined;
|
|
120
|
+
refKind?: string | undefined;
|
|
121
|
+
}>;
|
|
122
|
+
descriptionKey?: string | undefined;
|
|
123
|
+
defaultProps?: Record<string, unknown> | undefined;
|
|
124
|
+
responsiveFields?: string[] | undefined;
|
|
125
|
+
previewIcon?: string | undefined;
|
|
126
|
+
weight?: number | undefined;
|
|
127
|
+
}[] | undefined;
|
|
128
|
+
blockCategories?: {
|
|
129
|
+
key: string;
|
|
130
|
+
titleKey: string;
|
|
131
|
+
contexts: ("email" | "invoice" | "cms" | "newsletter")[];
|
|
132
|
+
weight?: number | undefined;
|
|
133
|
+
visible?: boolean | undefined;
|
|
134
|
+
}[] | undefined;
|
|
135
|
+
env?: {
|
|
136
|
+
name: string;
|
|
137
|
+
describes: {
|
|
138
|
+
en: string;
|
|
139
|
+
pl: string;
|
|
140
|
+
};
|
|
141
|
+
requirement: {
|
|
142
|
+
kind: "required";
|
|
143
|
+
} | {
|
|
144
|
+
kind: "requiredWhen";
|
|
145
|
+
input: string;
|
|
146
|
+
equals: string;
|
|
147
|
+
} | {
|
|
148
|
+
kind: "optional";
|
|
149
|
+
without: {
|
|
150
|
+
en: string;
|
|
151
|
+
pl: string;
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
secret: boolean;
|
|
155
|
+
generable: boolean;
|
|
156
|
+
owner: {
|
|
157
|
+
kind: "platform";
|
|
158
|
+
} | {
|
|
159
|
+
kind: "application";
|
|
160
|
+
application: "admin" | "backend" | "storefront";
|
|
161
|
+
} | {
|
|
162
|
+
kind: "module";
|
|
163
|
+
moduleId: string;
|
|
164
|
+
};
|
|
165
|
+
consumers: ("admin" | "backend" | "storefront")[];
|
|
166
|
+
addressOf: "admin" | "backend" | "storefront" | null;
|
|
167
|
+
}[] | undefined;
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+MnB,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { defineModuleManifest } from '@endora-commerce/contracts';
|
|
2
|
+
/**
|
|
3
|
+
* Customer Accounts module — manifest backfill (Module Lifecycle, feature 018).
|
|
4
|
+
*
|
|
5
|
+
* Predates the lifecycle system; this manifest is the static record
|
|
6
|
+
* required so the module participates in the registry. No install /
|
|
7
|
+
* uninstall hook today — the module's schema is owned by earlier
|
|
8
|
+
* platform-wide migrations.
|
|
9
|
+
*/
|
|
10
|
+
export const manifest = defineModuleManifest({
|
|
11
|
+
id: 'customer_accounts',
|
|
12
|
+
name: 'Customer Accounts',
|
|
13
|
+
description: 'Customer (B2B) account records, including organization membership and role.',
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
// `auth` owns `authSessionPort`, which `CustomerAuthService` resolves to mint
|
|
16
|
+
// and destroy a customer session; the edge became real with the conversion
|
|
17
|
+
// (feature 072, T094) and stays binding — a platform that cannot mint a
|
|
18
|
+
// session must refuse the login rather than issue one nothing can validate.
|
|
19
|
+
// It is *only* that: feature 075's Phase C took password hashing and the TOTP
|
|
20
|
+
// primitives out of this edge, because a pure function has no owner to be
|
|
21
|
+
// switched off.
|
|
22
|
+
// `customer_accounts.organization_id` is a real foreign key, and feature 072
|
|
23
|
+
// is what made it visible: the module exports its entities now, so the ORM
|
|
24
|
+
// registry attributes the table to it and the FK-drift check can see across
|
|
25
|
+
// the boundary. The edge predates the conversion — it was simply
|
|
26
|
+
// unattributable while the table belonged to nobody.
|
|
27
|
+
// `customer_accounts.customer_group_id` is a real foreign key too, and since
|
|
28
|
+
// feature 076 (D-79) it points at `customer_groups`, which this module now
|
|
29
|
+
// owns: the constraint is intra-module and declares nothing.
|
|
30
|
+
// `audit_logs` owns `auditReferenceRegistry`, the registry this module pushes
|
|
31
|
+
// its own "what is this audit row called, and where does the admin app show
|
|
32
|
+
// it?" resolver into (feature 075, D-87). The registry is ungated and its
|
|
33
|
+
// owner is non-deactivatable, so the declaration buys install and migration
|
|
34
|
+
// order rather than a flip-time refusal.
|
|
35
|
+
dependencies: ['audit_logs', 'auth', 'organizations'],
|
|
36
|
+
/**
|
|
37
|
+
* D-96 — `mfaLoginPort`, the second factor on customer login.
|
|
38
|
+
*
|
|
39
|
+
* Real to the container, binding on no operator. `mfa` declares this module
|
|
40
|
+
* in its own `dependencies`, so the ordinary declaration closes a cycle; and
|
|
41
|
+
* an acknowledged edge would put customer login among the dependents that
|
|
42
|
+
* refuse the flip, making a client security policy permanently unswitchable.
|
|
43
|
+
*/
|
|
44
|
+
nonBindingDependencies: [
|
|
45
|
+
{
|
|
46
|
+
moduleId: 'mfa',
|
|
47
|
+
name: 'mfaLoginPort',
|
|
48
|
+
kind: 'degrades-without',
|
|
49
|
+
whenAbsent: 'Customer sign-in stops asking for a second factor and offers no Google/Microsoft ' +
|
|
50
|
+
'button. An account created by social sign-in has no known password: its route in is ' +
|
|
51
|
+
'"forgot password".',
|
|
52
|
+
reason: 'CustomerAuthService verifies the password first and then asks the second factor what ' +
|
|
53
|
+
'to do. With `mfa` absent it asks nobody: `backend.ts` probes ' +
|
|
54
|
+
'`effectiveState.isPresent("mfa")` and passes `undefined`, which selects the ' +
|
|
55
|
+
'password-only branch feature 042 FR-033 requires and this service has always had. ' +
|
|
56
|
+
'Nothing catches `ModuleDisabledError` — the decision is taken before the port is ' +
|
|
57
|
+
'resolved. Org-level TOTP enforcement is `mfa`\'s own policy and goes with it. One ' +
|
|
58
|
+
'edge is not repaired by the degrade and the operator has to know it: an account this ' +
|
|
59
|
+
'module auto-created from a Google/Microsoft sign-in holds a random password nobody ' +
|
|
60
|
+
'was ever told, so with the buttons gone its only route back is a password reset, ' +
|
|
61
|
+
'keyed on the e-mail the provider verified.',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
moduleId: 'mfa',
|
|
65
|
+
name: 'mfaEnrolmentStatePort',
|
|
66
|
+
kind: 'degrades-without',
|
|
67
|
+
whenAbsent: 'Reads "no second factor" for every customer — admin customer detail, both ' +
|
|
68
|
+
'organisation member panels, and the buyer\'s own account page. True while MFA is off; ' +
|
|
69
|
+
'not a claim that nobody is enrolled.',
|
|
70
|
+
reason: '`twoFactorEnabled` on `CustomerAccountRecord` is the live `mfa` enrolment, read in ' +
|
|
71
|
+
'one batch through `mfaEnrolmentStatePort`. It was ' +
|
|
72
|
+
'`Boolean(account.twoFactorConfirmedAt)` until 2026-08-28, and that column\'s only ' +
|
|
73
|
+
'non-null writer was the superseded TOTP path deleted on 2026-08-25 — so GET ' +
|
|
74
|
+
'/api/v1/me/customer told a buyer who had enrolled an hour earlier that their own ' +
|
|
75
|
+
'account was unprotected. Non-binding for the reason the login edge beside it is: ' +
|
|
76
|
+
'`mfa` declares this module in its own `dependencies`, so an ordinary declaration ' +
|
|
77
|
+
'closes a cycle, and an acknowledged edge would make a client security policy ' +
|
|
78
|
+
'unswitchable. The degrade is taken by **not resolving** — `backend.ts` probes ' +
|
|
79
|
+
'presence first and answers an empty set — so nothing catches `ModuleDisabledError`.',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
// Feature 074 (Constitution XVII), test C1 — reachability. The flag used to
|
|
83
|
+
// rest on four port edges another module declares; ruling 2 withdraws that
|
|
84
|
+
// authority, so the ground is now this module's own and it is the stronger
|
|
85
|
+
// one anyway. This module owns the identity a buyer signs in as. Switch it
|
|
86
|
+
// off and no customer-side path exists at all — no registration, no login,
|
|
87
|
+
// no cart belonging to anyone, no order placed by anyone — which is the
|
|
88
|
+
// reachability test rather than a reduction in capability.
|
|
89
|
+
/**
|
|
90
|
+
* Nothing to demonstrate of its own (feature 113, T211/T222 — contract §1.2).
|
|
91
|
+
*
|
|
92
|
+
* The demo shop does have a buyer, and it is not this module's demo data:
|
|
93
|
+
* `customer_accounts.organization_id` is `NOT NULL` (Principle XI), so there
|
|
94
|
+
* is no account to create before an `organizations` row exists to hold it, and
|
|
95
|
+
* "create the account, then join it" cannot be written at all. The account and
|
|
96
|
+
* its organisation are created in one statement, which makes them two modules'
|
|
97
|
+
* rows and a composition step (§5.1) — step 5 of
|
|
98
|
+
* `backend/src/seeds/demo-composition.ts`, which says so in its own words.
|
|
99
|
+
*
|
|
100
|
+
* `false` rather than absent, because the two are different states: this is a
|
|
101
|
+
* decision that the module owes nothing, not a module nobody has looked at.
|
|
102
|
+
*/
|
|
103
|
+
demo: false,
|
|
104
|
+
activation: {
|
|
105
|
+
nonDeactivatable: true,
|
|
106
|
+
reason: 'The identity a buyer signs in as; no customer-side path — registration, login, cart, ' +
|
|
107
|
+
'order or account — exists without it.',
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* The seven error codes this module owns — D-129's remaining sweep, MR 4
|
|
111
|
+
* (`specs/090-module-owned-error-codes/d129-sweep.md` §5.2, Appendix A;
|
|
112
|
+
* D-186 in `specs/080-f4-real-scope/rulings.md`).
|
|
113
|
+
*
|
|
114
|
+
* This module declared none until now. All seven were `_i18n`'s, not because
|
|
115
|
+
* anybody judged them the platform's but because the deleted prefix chain had
|
|
116
|
+
* no rule for them and its last line was `return 'core'`.
|
|
117
|
+
*
|
|
118
|
+
* **Four of them are the `CUSTOMER_*` record family, and D-186 §1 is what put
|
|
119
|
+
* them here rather than in `customers`.** The two modules are a data/behaviour
|
|
120
|
+
* pair — this one holds the `CustomerAccount` row, `customers` holds the
|
|
121
|
+
* lifecycle logic and the admin and storefront surfaces on top of it — and the
|
|
122
|
+
* ruling splits the family by noun: the customer **record** is this module's,
|
|
123
|
+
* `CustomerAddress` is `customers`', which is why `CUSTOMER_ADDRESS_NOT_FOUND`
|
|
124
|
+
* went there in MR 3 and these four come here.
|
|
125
|
+
*
|
|
126
|
+
* **Two of the four are codes `customers` raises and this module owns**, and
|
|
127
|
+
* that is the shape a reviewer will stop on. `CUSTOMER_NOT_FOUND` is raised
|
|
128
|
+
* six times, four of them in `customers`
|
|
129
|
+
* (`routes.self.ts`, `customer-deletion-service.ts`,
|
|
130
|
+
* `customer-moderation-service.ts`, `customer-org-assignment-service.ts`) and
|
|
131
|
+
* two here; `CUSTOMER_ALREADY_DELETED` is raised once in each. In every one of
|
|
132
|
+
* those `customers` sites the module is resolving or re-checking a
|
|
133
|
+
* `CustomerAccount` before doing its own work — it is the caller, and the row
|
|
134
|
+
* whose absence or deleted state it is reporting is this module's. D-95.2
|
|
135
|
+
* already ruled that shape for `INVOICE_NOT_READY`: the owner of a noun is not
|
|
136
|
+
* required to be the module that throws about it, and D-186 §1 accepts this
|
|
137
|
+
* consequence in terms.
|
|
138
|
+
*
|
|
139
|
+
* `CUSTOMER_NOT_DELETED` and `CUSTOMER_RESTORE_WINDOW_ELAPSED` are the same
|
|
140
|
+
* noun read the other way round, and both are raised only here, from
|
|
141
|
+
* `customer-account-lifecycle-ports.ts` — the soft-delete window is a property
|
|
142
|
+
* of the account row and of nothing on top of it.
|
|
143
|
+
*
|
|
144
|
+
* **`ACCOUNT_BLOCKED`** names the account itself: `customer-auth-service.ts`
|
|
145
|
+
* refuses a sign-in for a `CustomerAccount` whose status is blocked, which is
|
|
146
|
+
* this module's own column and its own gate.
|
|
147
|
+
*
|
|
148
|
+
* **`CANNOT_DEMOTE_LAST_ADMIN` and `CANNOT_REMOVE_LAST_ADMIN`** read like
|
|
149
|
+
* `organizations` and are not. The invariant they protect is counted over
|
|
150
|
+
* `CustomerAccount.role` inside one organization, in this module's
|
|
151
|
+
* `role-service.ts`, which is the only thing in the tree that raises either;
|
|
152
|
+
* `organizations` owns the organization, this module owns its membership.
|
|
153
|
+
*
|
|
154
|
+
* **The two of them arrive with a sentence, and it is a new one.** Both
|
|
155
|
+
* carried a placeholder in `_i18n`'s bundle — `"Cannot Demote Last Admin."` /
|
|
156
|
+
* `"Błąd: cannot demote last admin."` — which D-186 §2 deletes rather than
|
|
157
|
+
* moves, because a placeholder in a module's own bundle reads as that module's
|
|
158
|
+
* answer and every instrument then counts the code as translated.
|
|
159
|
+
* `d129-sweep.md` §5.4 keeps writing the prose available and calls it the
|
|
160
|
+
* better outcome; here the reader is an organization administrator managing
|
|
161
|
+
* their own company's users and the refusal is one sentence to explain, so it
|
|
162
|
+
* is written. The other five had no sentence in either language before the
|
|
163
|
+
* move and have none after: they were entries in
|
|
164
|
+
* `check-error-translations.ts`'s `UNTRANSLATED_ERROR_CODES` under `_i18n` and
|
|
165
|
+
* are entries under `customer_accounts`, which changes who owes the sentence
|
|
166
|
+
* and not whether one is owed.
|
|
167
|
+
*
|
|
168
|
+
* **No `tokens`, derived from the raise sites rather than from the bundle**
|
|
169
|
+
* (runbook §5). All eleven raise sites were read by balancing the parentheses
|
|
170
|
+
* of the call itself rather than by a line-wise grep, and not one passes a
|
|
171
|
+
* `details` object at all — so `refusalToken` has nothing to read and a
|
|
172
|
+
* sentence written at `errors.<CODE>` is the key the envelope actually looks
|
|
173
|
+
* up. That mattered enough to measure: where a code always carries a
|
|
174
|
+
* `details.code`, `localizeErrorEnvelope` resolves `errors.<CODE>.<token>`
|
|
175
|
+
* with no fallback to the base key, and a base sentence would be dead text
|
|
176
|
+
* that P1 nevertheless counts as translated.
|
|
177
|
+
*/
|
|
178
|
+
errorCodes: [
|
|
179
|
+
{ code: 'ACCOUNT_BLOCKED' },
|
|
180
|
+
{ code: 'CANNOT_DEMOTE_LAST_ADMIN' },
|
|
181
|
+
{ code: 'CANNOT_REMOVE_LAST_ADMIN' },
|
|
182
|
+
{ code: 'CUSTOMER_ALREADY_DELETED' },
|
|
183
|
+
{ code: 'CUSTOMER_NOT_DELETED' },
|
|
184
|
+
{ code: 'CUSTOMER_NOT_FOUND' },
|
|
185
|
+
{ code: 'CUSTOMER_RESTORE_WINDOW_ELAPSED' },
|
|
186
|
+
],
|
|
187
|
+
i18n: { bundlesDir: 'i18n' },
|
|
188
|
+
docs: { dir: 'docs' },
|
|
189
|
+
// Feature 076 (D-79) — the customer-group admin surface came here with the
|
|
190
|
+
// entity, and its gate came with a correction. `price_lists` served these
|
|
191
|
+
// three routes under `catalog:write`, which asks a pricing question about a
|
|
192
|
+
// customer's segmentation; these two codes ask the right one. Granting them
|
|
193
|
+
// is a deliberate act on each admin role — nothing inherits from
|
|
194
|
+
// `catalog:write`.
|
|
195
|
+
permissions: [
|
|
196
|
+
{ code: 'customer_groups:read', label: 'View customer groups' },
|
|
197
|
+
{ code: 'customer_groups:write', label: 'Manage customer groups' },
|
|
198
|
+
],
|
|
199
|
+
actions: [
|
|
200
|
+
{
|
|
201
|
+
id: 'open-customer-groups',
|
|
202
|
+
labelKey: 'actions.openCustomerGroups.label',
|
|
203
|
+
descriptionKey: 'actions.openCustomerGroups.description',
|
|
204
|
+
icon: 'Users',
|
|
205
|
+
targetRoute: '/customer-groups',
|
|
206
|
+
requiredPermission: 'customer_groups:read',
|
|
207
|
+
keywords: ['customer', 'group', 'segment', 'klient', 'grupa', 'segment'],
|
|
208
|
+
weight: 140,
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
});
|
|
212
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
export declare class Migration20260425T055041CustomerAccountsPasswordResetTokens extends Migration {
|
|
3
|
+
up(): Promise<void>;
|
|
4
|
+
down(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=20260425T055041_customer_accounts_password_reset_tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260425T055041_customer_accounts_password_reset_tokens.d.ts","sourceRoot":"","sources":["../../src/migrations/20260425T055041_customer_accounts_password_reset_tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,qBAAa,2DAA4D,SAAQ,SAAS;IACzE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
export class Migration20260425T055041CustomerAccountsPasswordResetTokens extends Migration {
|
|
3
|
+
async up() {
|
|
4
|
+
this.addSql(`
|
|
5
|
+
create table "password_reset_tokens" (
|
|
6
|
+
"id" uuid not null,
|
|
7
|
+
"customer_account_id" uuid not null,
|
|
8
|
+
"token_hash" varchar(128) not null,
|
|
9
|
+
"expires_at" timestamptz not null,
|
|
10
|
+
"consumed_at" timestamptz null,
|
|
11
|
+
"created_at" timestamptz not null,
|
|
12
|
+
constraint "password_reset_tokens_pkey" primary key ("id"),
|
|
13
|
+
constraint "password_reset_tokens_token_hash_unique" unique ("token_hash"),
|
|
14
|
+
constraint "password_reset_tokens_customer_fk" foreign key ("customer_account_id")
|
|
15
|
+
references "customer_accounts" ("id") on delete cascade
|
|
16
|
+
);
|
|
17
|
+
`);
|
|
18
|
+
this.addSql('create index "password_reset_tokens_customer_account_id_index" on "password_reset_tokens" ("customer_account_id");');
|
|
19
|
+
this.addSql('create index "password_reset_tokens_expires_at_index" on "password_reset_tokens" ("expires_at");');
|
|
20
|
+
}
|
|
21
|
+
async down() {
|
|
22
|
+
this.addSql('drop table if exists "password_reset_tokens" cascade;');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=20260425T055041_customer_accounts_password_reset_tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260425T055041_customer_accounts_password_reset_tokens.js","sourceRoot":"","sources":["../../src/migrations/20260425T055041_customer_accounts_password_reset_tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,OAAO,2DAA4D,SAAQ,SAAS;IAC/E,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAaX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,oHAAoH,CAAC,CAAC;QAClI,IAAI,CAAC,MAAM,CAAC,kGAAkG,CAAC,CAAC;IAClH,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,uDAAuD,CAAC,CAAC;IACvE,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* Relaxes `customer_accounts.organization_id` from NOT NULL to nullable
|
|
4
|
+
* (feature 026 US2 — Customer accounts may exist without an Organization).
|
|
5
|
+
*
|
|
6
|
+
* **This migration's design is dead, and everything below it describes a
|
|
7
|
+
* platform that no longer exists.** Feature 051 replaced it — an individual is
|
|
8
|
+
* backed by a single-member personal Organization — and D-178 re-tightened the
|
|
9
|
+
* column in
|
|
10
|
+
* `20260825T141659_customer_accounts_organization_required`. The paragraphs
|
|
11
|
+
* below are kept because they say what this statement did on the day it ran;
|
|
12
|
+
* read them as history and not as current behaviour. In particular the `down()`
|
|
13
|
+
* here is not a working re-tightening recipe: it sets `organization_id` to the
|
|
14
|
+
* account's own id against a live `customer_accounts_organization_fk`, so it
|
|
15
|
+
* fails rather than corrupting. Do not copy it.
|
|
16
|
+
*
|
|
17
|
+
* Existing rows are unaffected (they keep their organization_id). The
|
|
18
|
+
* column's foreign-key constraint stays in place — when the column IS
|
|
19
|
+
* populated, it still references organizations(id) ON DELETE RESTRICT.
|
|
20
|
+
*
|
|
21
|
+
* Application-side implications (handled in code, not in this migration):
|
|
22
|
+
* - The Customer's effective Organization (for prices, credit limit,
|
|
23
|
+
* payment / delivery / warehouse allow-lists) becomes null → falls
|
|
24
|
+
* back to platform defaults.
|
|
25
|
+
* - Order placement and Quote Request submission still REQUIRE an
|
|
26
|
+
* Organization — the route handlers surface a friendly 422 when the
|
|
27
|
+
* caller has no Organization. Orders and RFQs remain NOT NULL at the
|
|
28
|
+
* schema level.
|
|
29
|
+
*/
|
|
30
|
+
export declare class Migration20260611T140351CustomerAccountsOrganizationOptional extends Migration {
|
|
31
|
+
up(): Promise<void>;
|
|
32
|
+
down(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=20260611T140351_customer_accounts_organization_optional.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260611T140351_customer_accounts_organization_optional.d.ts","sourceRoot":"","sources":["../../src/migrations/20260611T140351_customer_accounts_organization_optional.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,4DAA6D,SAAQ,SAAS;IAC1E,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAInB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAUrC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* Relaxes `customer_accounts.organization_id` from NOT NULL to nullable
|
|
4
|
+
* (feature 026 US2 — Customer accounts may exist without an Organization).
|
|
5
|
+
*
|
|
6
|
+
* **This migration's design is dead, and everything below it describes a
|
|
7
|
+
* platform that no longer exists.** Feature 051 replaced it — an individual is
|
|
8
|
+
* backed by a single-member personal Organization — and D-178 re-tightened the
|
|
9
|
+
* column in
|
|
10
|
+
* `20260825T141659_customer_accounts_organization_required`. The paragraphs
|
|
11
|
+
* below are kept because they say what this statement did on the day it ran;
|
|
12
|
+
* read them as history and not as current behaviour. In particular the `down()`
|
|
13
|
+
* here is not a working re-tightening recipe: it sets `organization_id` to the
|
|
14
|
+
* account's own id against a live `customer_accounts_organization_fk`, so it
|
|
15
|
+
* fails rather than corrupting. Do not copy it.
|
|
16
|
+
*
|
|
17
|
+
* Existing rows are unaffected (they keep their organization_id). The
|
|
18
|
+
* column's foreign-key constraint stays in place — when the column IS
|
|
19
|
+
* populated, it still references organizations(id) ON DELETE RESTRICT.
|
|
20
|
+
*
|
|
21
|
+
* Application-side implications (handled in code, not in this migration):
|
|
22
|
+
* - The Customer's effective Organization (for prices, credit limit,
|
|
23
|
+
* payment / delivery / warehouse allow-lists) becomes null → falls
|
|
24
|
+
* back to platform defaults.
|
|
25
|
+
* - Order placement and Quote Request submission still REQUIRE an
|
|
26
|
+
* Organization — the route handlers surface a friendly 422 when the
|
|
27
|
+
* caller has no Organization. Orders and RFQs remain NOT NULL at the
|
|
28
|
+
* schema level.
|
|
29
|
+
*/
|
|
30
|
+
export class Migration20260611T140351CustomerAccountsOrganizationOptional extends Migration {
|
|
31
|
+
async up() {
|
|
32
|
+
this.addSql(`alter table "customer_accounts" alter column "organization_id" drop not null;`);
|
|
33
|
+
}
|
|
34
|
+
async down() {
|
|
35
|
+
// Safe re-tightening: only re-add NOT NULL if every existing row has a
|
|
36
|
+
// value. (Production should NEVER hit this path while feature 026 is in
|
|
37
|
+
// use — but the down() must be valid even if it cannot succeed against
|
|
38
|
+
// partially-migrated data.)
|
|
39
|
+
this.addSql(`update "customer_accounts" set "organization_id" = "id" where "organization_id" is null;`);
|
|
40
|
+
this.addSql(`alter table "customer_accounts" alter column "organization_id" set not null;`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=20260611T140351_customer_accounts_organization_optional.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260611T140351_customer_accounts_organization_optional.js","sourceRoot":"","sources":["../../src/migrations/20260611T140351_customer_accounts_organization_optional.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAO,4DAA6D,SAAQ,SAAS;IAChF,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC,+EAA+E,CAAC,CAAC;IAC/F,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,uEAAuE;QACvE,wEAAwE;QACxE,uEAAuE;QACvE,4BAA4B;QAC5B,IAAI,CAAC,MAAM,CACT,0FAA0F,CAC3F,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,8EAA8E,CAAC,CAAC;IAC9F,CAAC;CACF"}
|