@endora-commerce/mod-customers 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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/admin/index.d.ts +26 -0
  4. package/dist/admin/index.d.ts.map +1 -0
  5. package/dist/admin/index.js +68 -0
  6. package/dist/admin/index.js.map +1 -0
  7. package/dist/admin/pages/CustomerDetail.d.ts +9 -0
  8. package/dist/admin/pages/CustomerDetail.d.ts.map +1 -0
  9. package/dist/admin/pages/CustomerDetail.js +72 -0
  10. package/dist/admin/pages/CustomerDetail.js.map +1 -0
  11. package/dist/admin/pages/CustomersList.d.ts +9 -0
  12. package/dist/admin/pages/CustomersList.d.ts.map +1 -0
  13. package/dist/admin/pages/CustomersList.js +115 -0
  14. package/dist/admin/pages/CustomersList.js.map +1 -0
  15. package/dist/admin/pages/OnlineCustomers.d.ts +9 -0
  16. package/dist/admin/pages/OnlineCustomers.d.ts.map +1 -0
  17. package/dist/admin/pages/OnlineCustomers.js +77 -0
  18. package/dist/admin/pages/OnlineCustomers.js.map +1 -0
  19. package/dist/admin/panels/HistoryPanels.d.ts +11 -0
  20. package/dist/admin/panels/HistoryPanels.d.ts.map +1 -0
  21. package/dist/admin/panels/HistoryPanels.js +64 -0
  22. package/dist/admin/panels/HistoryPanels.js.map +1 -0
  23. package/dist/admin/panels/ManagementPanels.d.ts +14 -0
  24. package/dist/admin/panels/ManagementPanels.d.ts.map +1 -0
  25. package/dist/admin/panels/ManagementPanels.js +93 -0
  26. package/dist/admin/panels/ManagementPanels.js.map +1 -0
  27. package/dist/backend/entities/customer-address.entity.d.ts +25 -0
  28. package/dist/backend/entities/customer-address.entity.d.ts.map +1 -0
  29. package/dist/backend/entities/customer-address.entity.js +95 -0
  30. package/dist/backend/entities/customer-address.entity.js.map +1 -0
  31. package/dist/backend/index.d.ts +91 -0
  32. package/dist/backend/index.d.ts.map +1 -0
  33. package/dist/backend/index.js +201 -0
  34. package/dist/backend/index.js.map +1 -0
  35. package/dist/backend/plugin.d.ts +168 -0
  36. package/dist/backend/plugin.d.ts.map +1 -0
  37. package/dist/backend/plugin.js +83 -0
  38. package/dist/backend/plugin.js.map +1 -0
  39. package/dist/backend/routes.admin.d.ts +70 -0
  40. package/dist/backend/routes.admin.d.ts.map +1 -0
  41. package/dist/backend/routes.admin.js +313 -0
  42. package/dist/backend/routes.admin.js.map +1 -0
  43. package/dist/backend/routes.register.d.ts +12 -0
  44. package/dist/backend/routes.register.d.ts.map +1 -0
  45. package/dist/backend/routes.register.js +40 -0
  46. package/dist/backend/routes.register.js.map +1 -0
  47. package/dist/backend/routes.self.d.ts +46 -0
  48. package/dist/backend/routes.self.d.ts.map +1 -0
  49. package/dist/backend/routes.self.js +145 -0
  50. package/dist/backend/routes.self.js.map +1 -0
  51. package/dist/backend/serializers.d.ts +13 -0
  52. package/dist/backend/serializers.d.ts.map +1 -0
  53. package/dist/backend/serializers.js +39 -0
  54. package/dist/backend/serializers.js.map +1 -0
  55. package/dist/backend/services/customer-address-read-port.d.ts +29 -0
  56. package/dist/backend/services/customer-address-read-port.d.ts.map +1 -0
  57. package/dist/backend/services/customer-address-read-port.js +53 -0
  58. package/dist/backend/services/customer-address-read-port.js.map +1 -0
  59. package/dist/backend/services/customer-address-service.d.ts +94 -0
  60. package/dist/backend/services/customer-address-service.d.ts.map +1 -0
  61. package/dist/backend/services/customer-address-service.js +176 -0
  62. package/dist/backend/services/customer-address-service.js.map +1 -0
  63. package/dist/backend/services/customer-admin-query-service.d.ts +57 -0
  64. package/dist/backend/services/customer-admin-query-service.d.ts.map +1 -0
  65. package/dist/backend/services/customer-admin-query-service.js +97 -0
  66. package/dist/backend/services/customer-admin-query-service.js.map +1 -0
  67. package/dist/backend/services/customer-authority-service.d.ts +46 -0
  68. package/dist/backend/services/customer-authority-service.d.ts.map +1 -0
  69. package/dist/backend/services/customer-authority-service.js +42 -0
  70. package/dist/backend/services/customer-authority-service.js.map +1 -0
  71. package/dist/backend/services/customer-defaults-service.d.ts +48 -0
  72. package/dist/backend/services/customer-defaults-service.d.ts.map +1 -0
  73. package/dist/backend/services/customer-defaults-service.js +71 -0
  74. package/dist/backend/services/customer-defaults-service.js.map +1 -0
  75. package/dist/backend/services/customer-deletion-service.d.ts +39 -0
  76. package/dist/backend/services/customer-deletion-service.d.ts.map +1 -0
  77. package/dist/backend/services/customer-deletion-service.js +94 -0
  78. package/dist/backend/services/customer-deletion-service.js.map +1 -0
  79. package/dist/backend/services/customer-moderation-service.d.ts +58 -0
  80. package/dist/backend/services/customer-moderation-service.d.ts.map +1 -0
  81. package/dist/backend/services/customer-moderation-service.js +70 -0
  82. package/dist/backend/services/customer-moderation-service.js.map +1 -0
  83. package/dist/backend/services/customer-org-assignment-service.d.ts +52 -0
  84. package/dist/backend/services/customer-org-assignment-service.d.ts.map +1 -0
  85. package/dist/backend/services/customer-org-assignment-service.js +106 -0
  86. package/dist/backend/services/customer-org-assignment-service.js.map +1 -0
  87. package/dist/backend/services/customer-presence-service.d.ts +44 -0
  88. package/dist/backend/services/customer-presence-service.d.ts.map +1 -0
  89. package/dist/backend/services/customer-presence-service.js +47 -0
  90. package/dist/backend/services/customer-presence-service.js.map +1 -0
  91. package/dist/backend/services/customer-registration-service.d.ts +56 -0
  92. package/dist/backend/services/customer-registration-service.d.ts.map +1 -0
  93. package/dist/backend/services/customer-registration-service.js +43 -0
  94. package/dist/backend/services/customer-registration-service.js.map +1 -0
  95. package/dist/backend/workers/anonymization-sweep-worker.d.ts +15 -0
  96. package/dist/backend/workers/anonymization-sweep-worker.d.ts.map +1 -0
  97. package/dist/backend/workers/anonymization-sweep-worker.js +20 -0
  98. package/dist/backend/workers/anonymization-sweep-worker.js.map +1 -0
  99. package/dist/manifest.d.ts +181 -0
  100. package/dist/manifest.d.ts.map +1 -0
  101. package/dist/manifest.js +192 -0
  102. package/dist/manifest.js.map +1 -0
  103. package/dist/migrations/20260611T140404_customers_customer_addresses_init.d.ts +14 -0
  104. package/dist/migrations/20260611T140404_customers_customer_addresses_init.d.ts.map +1 -0
  105. package/dist/migrations/20260611T140404_customers_customer_addresses_init.js +40 -0
  106. package/dist/migrations/20260611T140404_customers_customer_addresses_init.js.map +1 -0
  107. package/dist/migrations/index.d.ts +27 -0
  108. package/dist/migrations/index.d.ts.map +1 -0
  109. package/dist/migrations/index.js +29 -0
  110. package/dist/migrations/index.js.map +1 -0
  111. package/docs/customers.md +108 -0
  112. package/i18n/en.json +94 -0
  113. package/i18n/pl.json +94 -0
  114. package/package.json +101 -0
  115. package/tailwind.css +14 -0
@@ -0,0 +1,14 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 040 (Customers) US2 — the personal address book.
4
+ *
5
+ * Mirrors the org-level `addresses` table but keyed by `customer_account_id`,
6
+ * so standalone (org-less) customers can keep their own billing/delivery
7
+ * addresses. "At most one default per (customer, kind)" is enforced by a
8
+ * partial unique index, exactly like `addresses`.
9
+ */
10
+ export declare class Migration20260611T140404CustomersCustomerAddressesInit extends Migration {
11
+ up(): Promise<void>;
12
+ down(): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=20260611T140404_customers_customer_addresses_init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260611T140404_customers_customer_addresses_init.d.ts","sourceRoot":"","sources":["../../src/migrations/20260611T140404_customers_customer_addresses_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;GAOG;AACH,qBAAa,sDAAuD,SAAQ,SAAS;IACpE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAgCnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}
@@ -0,0 +1,40 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Feature 040 (Customers) US2 — the personal address book.
4
+ *
5
+ * Mirrors the org-level `addresses` table but keyed by `customer_account_id`,
6
+ * so standalone (org-less) customers can keep their own billing/delivery
7
+ * addresses. "At most one default per (customer, kind)" is enforced by a
8
+ * partial unique index, exactly like `addresses`.
9
+ */
10
+ export class Migration20260611T140404CustomersCustomerAddressesInit extends Migration {
11
+ async up() {
12
+ this.addSql(`
13
+ create table "customer_addresses" (
14
+ "id" uuid not null,
15
+ "customer_account_id" uuid not null,
16
+ "kind" varchar(16) not null,
17
+ "recipient_name" varchar(160) not null,
18
+ "street" varchar(255) not null,
19
+ "city" varchar(120) not null,
20
+ "postal_code" varchar(20) not null,
21
+ "country" varchar(2) not null,
22
+ "phone" varchar(32) null,
23
+ "is_default" boolean not null default false,
24
+ "created_at" timestamptz not null,
25
+ "updated_at" timestamptz not null,
26
+ "deleted_at" timestamptz null,
27
+ constraint "customer_addresses_pkey" primary key ("id"),
28
+ constraint "customer_addresses_customer_fk" foreign key ("customer_account_id")
29
+ references "customer_accounts" ("id") on delete cascade
30
+ );
31
+ `);
32
+ this.addSql('create index "customer_addresses_customer_account_id_index" on "customer_addresses" ("customer_account_id");');
33
+ this.addSql('create index "customer_addresses_kind_index" on "customer_addresses" ("kind");');
34
+ this.addSql(`create unique index "customer_addresses_one_default_per_kind" on "customer_addresses" ("customer_account_id", "kind") where "is_default" = true and "deleted_at" is null;`);
35
+ }
36
+ async down() {
37
+ this.addSql('drop table if exists "customer_addresses" cascade;');
38
+ }
39
+ }
40
+ //# sourceMappingURL=20260611T140404_customers_customer_addresses_init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260611T140404_customers_customer_addresses_init.js","sourceRoot":"","sources":["../../src/migrations/20260611T140404_customers_customer_addresses_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,OAAO,sDAAuD,SAAQ,SAAS;IAC1E,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;KAmBX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,8GAA8G,CAC/G,CAAC;QACF,IAAI,CAAC,MAAM,CACT,gFAAgF,CACjF,CAAC;QACF,IAAI,CAAC,MAAM,CACT,2KAA2K,CAC5K,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,oDAAoD,CAAC,CAAC;IACpE,CAAC;CACF"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The `./migrations` subpath — every migration class this module owns, as one
3
+ * ordered `migrations` array.
4
+ *
5
+ * The array is what the platform reads when this module is **installed**:
6
+ * `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
7
+ * the package outright when it is absent (D-168).
8
+ *
9
+ * Listed in ascending timestamp, which is the order of this module's own
10
+ * migrations and of nothing else (feature 081): a manifest `dependencies` array
11
+ * is the only thing ordering this block against another module's.
12
+ *
13
+ * The **named** exports stay beside the array, and the asymmetry with
14
+ * `./backend` — which publishes an array and no named class (D-168) — is
15
+ * deliberate. `db/migrations-registry.generated.ts` imports each class by name
16
+ * from this specifier, and a migration class name is contract in a way an entity
17
+ * class name is not: `mikro_orm_migrations` persists it, so it is a string every
18
+ * already-migrated database holds.
19
+ *
20
+ * A class that is in neither the array nor the barrel is a migration that does
21
+ * not run: `migration:pending` reports nothing pending and the first symptom is
22
+ * a query against a table nobody created.
23
+ */
24
+ import { Migration20260611T140404CustomersCustomerAddressesInit } from './20260611T140404_customers_customer_addresses_init.js';
25
+ export declare const migrations: (typeof Migration20260611T140404CustomersCustomerAddressesInit)[];
26
+ export { Migration20260611T140404CustomersCustomerAddressesInit, };
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,sDAAsD,EAAE,MAAM,wDAAwD,CAAC;AAEhI,eAAO,MAAM,UAAU,mEAEtB,CAAC;AAEF,OAAO,EACL,sDAAsD,GACvD,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The `./migrations` subpath — every migration class this module owns, as one
3
+ * ordered `migrations` array.
4
+ *
5
+ * The array is what the platform reads when this module is **installed**:
6
+ * `src/packages/package-runtime.ts` takes `exported['migrations']` and refuses
7
+ * the package outright when it is absent (D-168).
8
+ *
9
+ * Listed in ascending timestamp, which is the order of this module's own
10
+ * migrations and of nothing else (feature 081): a manifest `dependencies` array
11
+ * is the only thing ordering this block against another module's.
12
+ *
13
+ * The **named** exports stay beside the array, and the asymmetry with
14
+ * `./backend` — which publishes an array and no named class (D-168) — is
15
+ * deliberate. `db/migrations-registry.generated.ts` imports each class by name
16
+ * from this specifier, and a migration class name is contract in a way an entity
17
+ * class name is not: `mikro_orm_migrations` persists it, so it is a string every
18
+ * already-migrated database holds.
19
+ *
20
+ * A class that is in neither the array nor the barrel is a migration that does
21
+ * not run: `migration:pending` reports nothing pending and the first symptom is
22
+ * a query against a table nobody created.
23
+ */
24
+ import { Migration20260611T140404CustomersCustomerAddressesInit } from './20260611T140404_customers_customer_addresses_init.js';
25
+ export const migrations = [
26
+ Migration20260611T140404CustomersCustomerAddressesInit,
27
+ ];
28
+ export { Migration20260611T140404CustomersCustomerAddressesInit, };
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,sDAAsD,EAAE,MAAM,wDAAwD,CAAC;AAEhI,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,sDAAsD;CACvD,CAAC;AAEF,OAAO,EACL,sDAAsD,GACvD,CAAC"}
@@ -0,0 +1,108 @@
1
+ ---
2
+ title: customers
3
+ description: Customer lifecycle over `customer_accounts` — company and personal Organizations, sales-rep assignment and the admin customer surface
4
+ ---
5
+
6
+ # `customers`
7
+
8
+ Customer (Klienci) lifecycle business logic layered on top of the
9
+ `customer_accounts` data module. **Every customer belongs to an
10
+ Organization** — a company for B2B, a single-member *personal* organization for
11
+ an individual, and `customer_accounts.organization_id` is
12
+ `NOT NULL`. "Standalone" throughout this page means *outside a company
13
+ organization*, never *without one*: such a customer is their own tenant, and the
14
+ organization-scoped features a company offers (shared addresses, invitations,
15
+ credit limit, a sales-rep assignment) are simply absent for them rather than
16
+ switched off by a special case.
17
+
18
+ ## Capabilities
19
+
20
+ **Storefront (self-service)**
21
+
22
+ - Standalone registration, gated by the
23
+ `customers.allow_registration_without_organization` setting. On success the
24
+ account and its personal organization are written in one transaction and the
25
+ new account is logged in automatically.
26
+ - A personal address book (billing/delivery), one default per kind, plus the
27
+ ability to select the Organization's shared addresses (org-bound customers).
28
+ - Default payment method, delivery method, and default addresses.
29
+ - Change password; read-only history of own orders and quote requests.
30
+
31
+ **Admin (oversight)**
32
+
33
+ - Customer list (search + status/organization/group filters) and a detail view
34
+ showing creation date, customer group, organization, blocked status, and last
35
+ login.
36
+ - Block / unblock and soft-delete / restore, with role-based authority: a
37
+ Platform Administrator may act on anyone; otherwise the authorized salesperson
38
+ is the one inherited from the customer's Organization. A personal organization
39
+ never carries a sales-rep assignment, so the unassigned-organization fallback
40
+ leaves a standalone customer open to any salesperson. An org-owner depletion
41
+ guard refuses blocking or deleting the last organization administrator.
42
+ - Impersonation; audited as `impersonation.start` / `impersonation.end`.
43
+ - Admin-triggered password reset (emails a set-password link).
44
+ - NIP/VAT validation (VIES / Biała lista port).
45
+ - Organization assign, and detach-from-organization, which moves the customer to
46
+ their own personal organization rather than leaving them without one.
47
+ Direct customer-group assignment (overrides the Organization's group when
48
+ resolving pricing and promotions).
49
+ - Read-only orders, quote-requests, and (current + abandoned) carts panels.
50
+ - An "online customers" view backed by recent session activity.
51
+
52
+ ## Deletion & anonymization
53
+
54
+ Deletion is a soft-disable: login is denied, the account is hidden, and sessions
55
+ are revoked, while orders, quote requests, and audit history are retained.
56
+ Within a configurable retention window (`customers.deletion_retention_days`,
57
+ default 365) an authorized actor can restore the account. After the window the
58
+ anonymization sweep (`AnonymizationSweepWorker`) irreversibly scrubs personal
59
+ data, and restore is no longer possible.
60
+
61
+ ## Public surface
62
+
63
+ Admin routes are gated by `customers:read` (reads), `customers:manage`
64
+ (mutations), and `customers:impersonate` (impersonation).
65
+
66
+ | Verb + Path | Audience | Purpose |
67
+ | --- | --- | --- |
68
+ | `POST /api/v1/customers/register` | anon | Standalone registration (setting-gated) |
69
+ | `GET /api/v1/me/customer` | customer | Own profile |
70
+ | `POST /api/v1/me/customer/change-password` | customer | Change password |
71
+ | `GET /api/v1/me/customer/addresses` | customer | Personal + org-shared addresses |
72
+ | `POST/PATCH/DELETE /api/v1/me/customer/addresses[/:id]` | customer | Manage personal addresses |
73
+ | `PUT /api/v1/me/customer/addresses/:id/default` | customer | Set a default address |
74
+ | `GET/PUT /api/v1/me/customer/defaults` | customer | Default payment/delivery method + addresses |
75
+ | `GET /api/v1/me/customer/orders` | customer | Own order history |
76
+ | `GET /api/v1/me/customer/quote-requests` | customer | Own RFQ history |
77
+ | `GET /api/v1/admin/customers` | admin | List (authority-scoped) |
78
+ | `GET /api/v1/admin/customers/:id` | admin | Detail |
79
+ | `POST /api/v1/admin/customers/:id/block` · `/unblock` | admin | Block / unblock |
80
+ | `DELETE /api/v1/admin/customers/:id` · `POST .../restore` | admin | Soft-delete / restore |
81
+ | `POST /api/v1/admin/customers/:id/impersonate` | admin | Start impersonation |
82
+ | `POST /api/v1/admin/customers/:id/password-reset` | admin | Email a set-password link |
83
+ | `POST/DELETE /api/v1/admin/customers/:id/organization` | admin | Assign / unassign organization |
84
+ | `PUT /api/v1/admin/customers/:id/customer-group` | admin | Set / clear customer group |
85
+ | `GET/POST/PATCH/DELETE /api/v1/admin/customers/:id/addresses[/:addressId]` | admin | Manage addresses |
86
+ | `POST /api/v1/admin/customers/:id/vat-validate` | admin | Validate a NIP/VAT number |
87
+ | `GET /api/v1/admin/customers/:id/orders` · `/quote-requests` · `/carts` | admin | Read-only history panels |
88
+ | `GET /api/v1/admin/customers/online` | admin | Currently-online customers |
89
+
90
+ ## Settings
91
+
92
+ | Code | Type | Default | Purpose |
93
+ | --- | --- | --- | --- |
94
+ | `customers.allow_registration_without_organization` | boolean | `false` | Gate standalone registration |
95
+ | `customers.deletion_retention_days` | number | `365` | Restore window before permanent anonymization |
96
+ | `customers.presence_freshness_minutes` | number | `10` | "Online" threshold |
97
+
98
+ ## Schema
99
+
100
+ - `060_customer_accounts_lifecycle` — adds `customer_group_id`, block state
101
+ (`blocked_at`, `block_reason`, `block_source`, `blocked_by_*`), and
102
+ deletion/anonymization state (`deletion_requested_by_admin_user_id`,
103
+ `anonymized_at`) to `customer_accounts`.
104
+ - `061_customer_addresses_init` — the `customer_addresses` table (one default
105
+ per `(customer, kind)`).
106
+
107
+ Default payment/delivery preferences reuse the `quick_order_default_preferences`
108
+ table; no new table is introduced for them.
package/i18n/en.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "nav.customers.label": "Customers",
3
+ "nav.customersOnline.label": "Online customers",
4
+
5
+ "actions.openCustomers.label": "Customers",
6
+ "actions.openCustomers.description": "Browse and manage customer accounts",
7
+ "actions.onlineCustomers.label": "Online customers",
8
+ "actions.onlineCustomers.description": "See which customers are currently online",
9
+
10
+ "status.active": "Active",
11
+ "status.blocked": "Blocked",
12
+ "status.deleted": "Deleted",
13
+
14
+ "list.title": "Customers",
15
+ "list.description": "Browse and manage customer accounts",
16
+ "list.error": "Could not load customers.",
17
+ "list.loading": "Loading…",
18
+ "list.empty": "No customers found.",
19
+ "list.none": "None",
20
+ "list.field.status": "Status",
21
+ "list.field.search": "Search",
22
+ "list.field.organization": "Organization",
23
+ "list.filter.all": "All",
24
+ "list.filter.allOrgs": "All organizations",
25
+ "list.action.resetOrgMfa": "Reset 2FA for organization",
26
+ "list.action.resetOrgMfaDone": "2FA reset complete",
27
+ "list.column.customer": "Customer",
28
+ "list.column.status": "Status",
29
+ "list.column.organization": "Organization",
30
+ "list.column.group": "Customer group",
31
+ "list.column.created": "Created",
32
+ "list.action.open": "Open",
33
+
34
+ "detail.title": "Customer",
35
+ "detail.loading": "Loading…",
36
+ "detail.error": "Could not load the customer.",
37
+ "detail.actionError": "The action could not be completed.",
38
+ "detail.info.title": "Account information",
39
+ "detail.actions.title": "Actions",
40
+ "detail.field.email": "Email",
41
+ "detail.field.created": "Created",
42
+ "detail.field.group": "Customer group",
43
+ "detail.field.organization": "Organization",
44
+ "detail.field.status": "Status",
45
+ "detail.field.lastLogin": "Last login",
46
+ "detail.action.block": "Block",
47
+ "detail.action.unblock": "Unblock",
48
+ "detail.action.passwordReset": "Reset password",
49
+ "detail.action.resetMfa": "Reset 2FA",
50
+ "detail.action.impersonate": "Impersonate",
51
+ "detail.action.restore": "Restore",
52
+ "detail.action.delete": "Delete",
53
+
54
+ "online.title": "Online customers",
55
+ "online.description": "Customers active within the freshness window",
56
+ "online.error": "Could not load online customers.",
57
+ "online.loading": "Loading…",
58
+ "online.empty": "No customers are currently online.",
59
+ "online.column.lastSeen": "Last seen",
60
+ "online.refresh": "Refresh",
61
+ "online.autoRefresh": "Auto-refresh",
62
+ "online.intervalLabel": "Interval (seconds)",
63
+ "online.refreshedAt": "Updated {time}",
64
+
65
+ "detail.panel.loading": "Loading…",
66
+ "detail.panel.error": "Could not load this section.",
67
+ "detail.orders.title": "Orders",
68
+ "detail.orders.empty": "No orders.",
69
+ "detail.rfqs.title": "Quote requests",
70
+ "detail.rfqs.empty": "No quote requests.",
71
+ "detail.carts.title": "Carts",
72
+ "detail.carts.items": "items",
73
+ "detail.carts.noCurrent": "No active cart.",
74
+ "detail.carts.empty": "No carts.",
75
+
76
+ "detail.org.title": "Organization",
77
+ "detail.org.assignLabel": "Assign to organization",
78
+ "detail.org.assign": "Assign",
79
+ "detail.org.unassign": "Detach from organization",
80
+ "detail.org.unassignHint": "The customer keeps their account and moves to their own personal organization.",
81
+ "detail.group.title": "Customer group",
82
+ "detail.group.setLabel": "Set customer group",
83
+ "detail.group.set": "Set",
84
+ "detail.group.clear": "Clear group",
85
+ "detail.addresses.title": "Addresses",
86
+ "detail.addresses.empty": "No personal addresses.",
87
+ "detail.addresses.default": "default",
88
+ "detail.addresses.recipient": "Recipient",
89
+ "detail.addresses.street": "Street",
90
+ "detail.addresses.city": "City",
91
+ "detail.addresses.postal": "Postal code",
92
+ "detail.addresses.country": "Country",
93
+ "detail.addresses.add": "Add address"
94
+ }
package/i18n/pl.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "nav.customers.label": "Klienci",
3
+ "nav.customersOnline.label": "Klienci online",
4
+
5
+ "actions.openCustomers.label": "Klienci",
6
+ "actions.openCustomers.description": "Przeglądaj i zarządzaj kontami klientów",
7
+ "actions.onlineCustomers.label": "Klienci online",
8
+ "actions.onlineCustomers.description": "Zobacz, którzy klienci są teraz online",
9
+
10
+ "status.active": "Aktywne",
11
+ "status.blocked": "Zablokowane",
12
+ "status.deleted": "Usunięte",
13
+
14
+ "list.title": "Klienci",
15
+ "list.description": "Przeglądaj i zarządzaj kontami klientów",
16
+ "list.error": "Nie udało się wczytać klientów.",
17
+ "list.loading": "Wczytywanie…",
18
+ "list.empty": "Nie znaleziono klientów.",
19
+ "list.none": "Brak",
20
+ "list.field.status": "Status",
21
+ "list.field.search": "Szukaj",
22
+ "list.field.organization": "Organizacja",
23
+ "list.filter.all": "Wszyscy",
24
+ "list.filter.allOrgs": "Wszystkie organizacje",
25
+ "list.action.resetOrgMfa": "Resetuj 2FA dla organizacji",
26
+ "list.action.resetOrgMfaDone": "Reset 2FA zakończony",
27
+ "list.column.customer": "Klient",
28
+ "list.column.status": "Status",
29
+ "list.column.organization": "Organizacja",
30
+ "list.column.group": "Grupa klientów",
31
+ "list.column.created": "Utworzono",
32
+ "list.action.open": "Otwórz",
33
+
34
+ "detail.title": "Klient",
35
+ "detail.loading": "Wczytywanie…",
36
+ "detail.error": "Nie udało się wczytać klienta.",
37
+ "detail.actionError": "Nie udało się wykonać akcji.",
38
+ "detail.info.title": "Informacje o koncie",
39
+ "detail.actions.title": "Akcje",
40
+ "detail.field.email": "E-mail",
41
+ "detail.field.created": "Utworzono",
42
+ "detail.field.group": "Grupa klientów",
43
+ "detail.field.organization": "Organizacja",
44
+ "detail.field.status": "Status",
45
+ "detail.field.lastLogin": "Ostatnie logowanie",
46
+ "detail.action.block": "Zablokuj",
47
+ "detail.action.unblock": "Odblokuj",
48
+ "detail.action.passwordReset": "Zresetuj hasło",
49
+ "detail.action.resetMfa": "Resetuj 2FA",
50
+ "detail.action.impersonate": "Zaloguj jako klient",
51
+ "detail.action.restore": "Przywróć",
52
+ "detail.action.delete": "Usuń",
53
+
54
+ "online.title": "Klienci online",
55
+ "online.description": "Klienci aktywni w oknie świeżości",
56
+ "online.error": "Nie udało się wczytać klientów online.",
57
+ "online.loading": "Wczytywanie…",
58
+ "online.empty": "Żaden klient nie jest teraz online.",
59
+ "online.column.lastSeen": "Ostatnio widziany",
60
+ "online.refresh": "Odśwież",
61
+ "online.autoRefresh": "Automatyczne odświeżanie",
62
+ "online.intervalLabel": "Interwał (sekundy)",
63
+ "online.refreshedAt": "Zaktualizowano {time}",
64
+
65
+ "detail.panel.loading": "Wczytywanie…",
66
+ "detail.panel.error": "Nie udało się wczytać tej sekcji.",
67
+ "detail.orders.title": "Zamówienia",
68
+ "detail.orders.empty": "Brak zamówień.",
69
+ "detail.rfqs.title": "Zapytania ofertowe",
70
+ "detail.rfqs.empty": "Brak zapytań ofertowych.",
71
+ "detail.carts.title": "Koszyki",
72
+ "detail.carts.items": "pozycji",
73
+ "detail.carts.noCurrent": "Brak aktywnego koszyka.",
74
+ "detail.carts.empty": "Brak koszyków.",
75
+
76
+ "detail.org.title": "Organizacja",
77
+ "detail.org.assignLabel": "Przypisz do organizacji",
78
+ "detail.org.assign": "Przypisz",
79
+ "detail.org.unassign": "Odłącz od organizacji",
80
+ "detail.org.unassignHint": "Klient zachowuje konto i przechodzi do własnej organizacji osobistej.",
81
+ "detail.group.title": "Grupa klientów",
82
+ "detail.group.setLabel": "Ustaw grupę klientów",
83
+ "detail.group.set": "Ustaw",
84
+ "detail.group.clear": "Wyczyść grupę",
85
+ "detail.addresses.title": "Adresy",
86
+ "detail.addresses.empty": "Brak adresów osobistych.",
87
+ "detail.addresses.default": "domyślny",
88
+ "detail.addresses.recipient": "Odbiorca",
89
+ "detail.addresses.street": "Ulica",
90
+ "detail.addresses.city": "Miasto",
91
+ "detail.addresses.postal": "Kod pocztowy",
92
+ "detail.addresses.country": "Kraj",
93
+ "detail.addresses.add": "Dodaj adres"
94
+ }
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "@endora-commerce/mod-customers",
3
+ "version": "0.100.0",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "description": "Customer lifecycle business logic: registration, self-service, blocking, impersonation, groups, deletion, and presence.",
7
+ "license": "MIT",
8
+ "endora": {
9
+ "type": "module",
10
+ "id": "customers"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/endora-commerce/endora-commerce.git",
15
+ "directory": "packages/modules/customers"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/manifest.d.ts",
23
+ "default": "./dist/manifest.js"
24
+ },
25
+ "./backend": {
26
+ "types": "./dist/backend/index.d.ts",
27
+ "default": "./dist/backend/index.js"
28
+ },
29
+ "./migrations": {
30
+ "types": "./dist/migrations/index.d.ts",
31
+ "default": "./dist/migrations/index.js"
32
+ },
33
+ "./admin": {
34
+ "types": "./dist/admin/index.d.ts",
35
+ "default": "./dist/admin/index.js"
36
+ },
37
+ "./tailwind.css": "./tailwind.css",
38
+ "./package.json": "./package.json"
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "i18n",
43
+ "docs",
44
+ "tailwind.css"
45
+ ],
46
+ "engines": {
47
+ "node": ">=22.18.0"
48
+ },
49
+ "peerDependencies": {
50
+ "@fastify/cookie": "^11",
51
+ "@mikro-orm/core": "^6",
52
+ "@mikro-orm/migrations": "^6",
53
+ "@mikro-orm/postgresql": "^6",
54
+ "fastify": "^5",
55
+ "lucide-react": "^1",
56
+ "react": "^19",
57
+ "react-router-dom": "^7",
58
+ "zod": "^4",
59
+ "@endora-commerce/admin-kit": "0.100.0",
60
+ "@endora-commerce/contracts": "0.100.0",
61
+ "@endora-commerce/platform": "0.100.0"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "@endora-commerce/admin-kit": {
65
+ "optional": true
66
+ },
67
+ "lucide-react": {
68
+ "optional": true
69
+ },
70
+ "react": {
71
+ "optional": true
72
+ },
73
+ "react-router-dom": {
74
+ "optional": true
75
+ }
76
+ },
77
+ "devDependencies": {
78
+ "@fastify/cookie": "^11.0.2",
79
+ "@mikro-orm/core": "^6.6.13",
80
+ "@mikro-orm/migrations": "^6.6.13",
81
+ "@mikro-orm/postgresql": "^6.6.13",
82
+ "@types/node": "^22.9.0",
83
+ "@types/react": "^19.2.14",
84
+ "fastify": "^5.12.5",
85
+ "lucide-react": "^1.11.0",
86
+ "react": "^19.2.5",
87
+ "react-router-dom": "^7.18.2",
88
+ "typescript": "^5.9.3",
89
+ "vitest": "^4.1.11",
90
+ "zod": "^4.2.0",
91
+ "@endora-commerce/platform": "0.100.0",
92
+ "@endora-commerce/contracts": "0.100.0",
93
+ "@endora-commerce/admin-kit": "0.100.0"
94
+ },
95
+ "scripts": {
96
+ "build": "tsc -p tsconfig.build.json && tsc -p tsconfig.ui.json",
97
+ "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.ui.json --noEmit",
98
+ "lint": "eslint src",
99
+ "test": "vitest run"
100
+ }
101
+ }
package/tailwind.css ADDED
@@ -0,0 +1,14 @@
1
+ /* @endora-commerce/mod-customers — AUTO-GENERATED by `pnpm --filter backend run manifests:generate`.
2
+ *
3
+ * The `@source` directives this package asks its host to scan
4
+ * (`specs/110-instance-repository/contracts/admin-stylesheet-composition.md` R1).
5
+ * They resolve relative to **this file**, so they hold wherever the package is
6
+ * installed — a workspace link here, `node_modules` in a client's instance.
7
+ *
8
+ * The `dist` line is what a published tarball ships and is what an instance
9
+ * scans; the `src` line is inert there and is what keeps `pnpm --filter admin
10
+ * run dev` reading source in this repository. Do not edit: run
11
+ * `pnpm --filter backend run manifests:generate`.
12
+ */
13
+ @source "./dist/admin";
14
+ @source "./src/admin";