@open-mercato/core 0.4.8-develop-28cee031d6 → 0.4.8-develop-15259be22b
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/agentic/standalone-guide.md +235 -0
- package/dist/generated/entities/customer_role/index.js +27 -0
- package/dist/generated/entities/customer_role/index.js.map +7 -0
- package/dist/generated/entities/customer_role_acl/index.js +19 -0
- package/dist/generated/entities/customer_role_acl/index.js.map +7 -0
- package/dist/generated/entities/customer_user/index.js +37 -0
- package/dist/generated/entities/customer_user/index.js.map +7 -0
- package/dist/generated/entities/customer_user_acl/index.js +19 -0
- package/dist/generated/entities/customer_user_acl/index.js.map +7 -0
- package/dist/generated/entities/customer_user_email_verification/index.js +17 -0
- package/dist/generated/entities/customer_user_email_verification/index.js.map +7 -0
- package/dist/generated/entities/customer_user_invitation/index.js +33 -0
- package/dist/generated/entities/customer_user_invitation/index.js.map +7 -0
- package/dist/generated/entities/customer_user_password_reset/index.js +15 -0
- package/dist/generated/entities/customer_user_password_reset/index.js.map +7 -0
- package/dist/generated/entities/customer_user_role/index.js +13 -0
- package/dist/generated/entities/customer_user_role/index.js.map +7 -0
- package/dist/generated/entities/customer_user_session/index.js +21 -0
- package/dist/generated/entities/customer_user_session/index.js.map +7 -0
- package/dist/generated/entities/organization/index.js +2 -0
- package/dist/generated/entities/organization/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +14 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +18 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/services/rbacService.js +3 -9
- package/dist/modules/auth/services/rbacService.js.map +2 -2
- package/dist/modules/customer_accounts/acl.js +12 -0
- package/dist/modules/customer_accounts/acl.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +87 -0
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +216 -0
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/roles.js +189 -0
- package/dist/modules/customer_accounts/api/admin/roles.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/users/[id]/reset-password.js +69 -0
- package/dist/modules/customer_accounts/api/admin/users/[id]/reset-password.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/users/[id]/verify-email.js +64 -0
- package/dist/modules/customer_accounts/api/admin/users/[id]/verify-email.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/users/[id].js +253 -0
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/users-invite.js +78 -0
- package/dist/modules/customer_accounts/api/admin/users-invite.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/users.js +251 -0
- package/dist/modules/customer_accounts/api/admin/users.js.map +7 -0
- package/dist/modules/customer_accounts/api/email/verify.js +59 -0
- package/dist/modules/customer_accounts/api/email/verify.js.map +7 -0
- package/dist/modules/customer_accounts/api/interceptors.js +5 -0
- package/dist/modules/customer_accounts/api/interceptors.js.map +7 -0
- package/dist/modules/customer_accounts/api/invitations/accept.js +114 -0
- package/dist/modules/customer_accounts/api/invitations/accept.js.map +7 -0
- package/dist/modules/customer_accounts/api/login.js +143 -0
- package/dist/modules/customer_accounts/api/login.js.map +7 -0
- package/dist/modules/customer_accounts/api/magic-link/request.js +78 -0
- package/dist/modules/customer_accounts/api/magic-link/request.js.map +7 -0
- package/dist/modules/customer_accounts/api/magic-link/verify.js +114 -0
- package/dist/modules/customer_accounts/api/magic-link/verify.js.map +7 -0
- package/dist/modules/customer_accounts/api/password/reset-confirm.js +59 -0
- package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +7 -0
- package/dist/modules/customer_accounts/api/password/reset-request.js +77 -0
- package/dist/modules/customer_accounts/api/password/reset-request.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/events/stream.js +163 -0
- package/dist/modules/customer_accounts/api/portal/events/stream.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/feature-check.js +57 -0
- package/dist/modules/customer_accounts/api/portal/feature-check.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/logout.js +64 -0
- package/dist/modules/customer_accounts/api/portal/logout.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/notifications/[id]/dismiss.js +49 -0
- package/dist/modules/customer_accounts/api/portal/notifications/[id]/dismiss.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/notifications/[id]/read.js +49 -0
- package/dist/modules/customer_accounts/api/portal/notifications/[id]/read.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/notifications/mark-all-read.js +46 -0
- package/dist/modules/customer_accounts/api/portal/notifications/mark-all-read.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/notifications/unread-count.js +42 -0
- package/dist/modules/customer_accounts/api/portal/notifications/unread-count.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/notifications.js +105 -0
- package/dist/modules/customer_accounts/api/portal/notifications.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/password-change.js +57 -0
- package/dist/modules/customer_accounts/api/portal/password-change.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/profile.js +135 -0
- package/dist/modules/customer_accounts/api/portal/profile.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/sessions/[id].js +62 -0
- package/dist/modules/customer_accounts/api/portal/sessions/[id].js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/sessions-refresh.js +75 -0
- package/dist/modules/customer_accounts/api/portal/sessions-refresh.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/sessions.js +77 -0
- package/dist/modules/customer_accounts/api/portal/sessions.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +90 -0
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/users/[id].js +71 -0
- package/dist/modules/customer_accounts/api/portal/users/[id].js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/users-invite.js +92 -0
- package/dist/modules/customer_accounts/api/portal/users-invite.js.map +7 -0
- package/dist/modules/customer_accounts/api/portal/users.js +79 -0
- package/dist/modules/customer_accounts/api/portal/users.js.map +7 -0
- package/dist/modules/customer_accounts/api/signup.js +121 -0
- package/dist/modules/customer_accounts/api/signup.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/[id]/page.js +491 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/[id]/page.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/[id]/page.meta.js +15 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/[id]/page.meta.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +343 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.meta.js +16 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.meta.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/create/page.js +180 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/create/page.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/create/page.meta.js +16 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/create/page.meta.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +176 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.meta.js +33 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.meta.js.map +7 -0
- package/dist/modules/customer_accounts/backend/page.js +466 -0
- package/dist/modules/customer_accounts/backend/page.js.map +7 -0
- package/dist/modules/customer_accounts/backend/page.meta.js +35 -0
- package/dist/modules/customer_accounts/backend/page.meta.js.map +7 -0
- package/dist/modules/customer_accounts/ce.js +26 -0
- package/dist/modules/customer_accounts/ce.js.map +7 -0
- package/dist/modules/customer_accounts/data/enrichers.js +85 -0
- package/dist/modules/customer_accounts/data/enrichers.js.map +7 -0
- package/dist/modules/customer_accounts/data/entities.js +377 -0
- package/dist/modules/customer_accounts/data/entities.js.map +7 -0
- package/dist/modules/customer_accounts/data/extensions.js +8 -0
- package/dist/modules/customer_accounts/data/extensions.js.map +7 -0
- package/dist/modules/customer_accounts/data/validators.js +111 -0
- package/dist/modules/customer_accounts/data/validators.js.map +7 -0
- package/dist/modules/customer_accounts/di.js +17 -0
- package/dist/modules/customer_accounts/di.js.map +7 -0
- package/dist/modules/customer_accounts/events.js +28 -0
- package/dist/modules/customer_accounts/events.js.map +7 -0
- package/dist/modules/customer_accounts/index.js +15 -0
- package/dist/modules/customer_accounts/index.js.map +7 -0
- package/dist/modules/customer_accounts/lib/customerAuth.js +71 -0
- package/dist/modules/customer_accounts/lib/customerAuth.js.map +7 -0
- package/dist/modules/customer_accounts/lib/customerAuthServer.js +29 -0
- package/dist/modules/customer_accounts/lib/customerAuthServer.js.map +7 -0
- package/dist/modules/customer_accounts/lib/rateLimiter.js +63 -0
- package/dist/modules/customer_accounts/lib/rateLimiter.js.map +7 -0
- package/dist/modules/customer_accounts/lib/tokenGenerator.js +12 -0
- package/dist/modules/customer_accounts/lib/tokenGenerator.js.map +7 -0
- package/dist/modules/customer_accounts/migrations/Migration20260313222043.js +49 -0
- package/dist/modules/customer_accounts/migrations/Migration20260313222043.js.map +7 -0
- package/dist/modules/customer_accounts/notifications.client.js +47 -0
- package/dist/modules/customer_accounts/notifications.client.js.map +7 -0
- package/dist/modules/customer_accounts/notifications.js +46 -0
- package/dist/modules/customer_accounts/notifications.js.map +7 -0
- package/dist/modules/customer_accounts/search.js +120 -0
- package/dist/modules/customer_accounts/search.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerInvitationService.js +87 -0
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerRbacService.js +109 -0
- package/dist/modules/customer_accounts/services/customerRbacService.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerSessionService.js +75 -0
- package/dist/modules/customer_accounts/services/customerSessionService.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerTokenService.js +91 -0
- package/dist/modules/customer_accounts/services/customerTokenService.js.map +7 -0
- package/dist/modules/customer_accounts/services/customerUserService.js +92 -0
- package/dist/modules/customer_accounts/services/customerUserService.js.map +7 -0
- package/dist/modules/customer_accounts/setup.js +179 -0
- package/dist/modules/customer_accounts/setup.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js +54 -0
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/autoLinkCrmReverse.js +68 -0
- package/dist/modules/customer_accounts/subscribers/autoLinkCrmReverse.js.map +7 -0
- package/dist/modules/customer_accounts/subscribers/notifyStaffOnSignup.js +29 -0
- package/dist/modules/customer_accounts/subscribers/notifyStaffOnSignup.js.map +7 -0
- package/dist/modules/customer_accounts/translations.js +9 -0
- package/dist/modules/customer_accounts/translations.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +63 -0
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.js +17 -0
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js +55 -0
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.js +17 -0
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js +26 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +7 -0
- package/dist/modules/customer_accounts/workers/cleanupExpiredSessions.js +23 -0
- package/dist/modules/customer_accounts/workers/cleanupExpiredSessions.js.map +7 -0
- package/dist/modules/customer_accounts/workers/cleanupExpiredTokens.js +38 -0
- package/dist/modules/customer_accounts/workers/cleanupExpiredTokens.js.map +7 -0
- package/dist/modules/customers/components/AddressTiles.js +1 -1
- package/dist/modules/customers/components/AddressTiles.js.map +2 -2
- package/dist/modules/directory/api/get/organizations/lookup.js +83 -0
- package/dist/modules/directory/api/get/organizations/lookup.js.map +7 -0
- package/dist/modules/directory/commands/organizations.js +32 -1
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/directory/data/entities.js +6 -2
- package/dist/modules/directory/data/entities.js.map +2 -2
- package/dist/modules/directory/data/validators.js +3 -0
- package/dist/modules/directory/data/validators.js.map +2 -2
- package/dist/modules/directory/migrations/Migration20260314143323.js +15 -0
- package/dist/modules/directory/migrations/Migration20260314143323.js.map +7 -0
- package/dist/modules/directory/setup.js +36 -0
- package/dist/modules/directory/setup.js.map +2 -2
- package/dist/modules/payment_gateways/migrations/Migration20260313222043.js +15 -0
- package/dist/modules/payment_gateways/migrations/Migration20260313222043.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +131 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +96 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +94 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +89 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +104 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +7 -0
- package/dist/modules/portal/index.js +11 -0
- package/dist/modules/portal/index.js.map +7 -0
- package/dist/modules/portal/setup.js +23 -0
- package/dist/modules/portal/setup.js.map +7 -0
- package/generated/entities/customer_role/index.ts +12 -0
- package/generated/entities/customer_role_acl/index.ts +8 -0
- package/generated/entities/customer_user/index.ts +17 -0
- package/generated/entities/customer_user_acl/index.ts +8 -0
- package/generated/entities/customer_user_email_verification/index.ts +7 -0
- package/generated/entities/customer_user_invitation/index.ts +15 -0
- package/generated/entities/customer_user_password_reset/index.ts +6 -0
- package/generated/entities/customer_user_role/index.ts +5 -0
- package/generated/entities/customer_user_session/index.ts +9 -0
- package/generated/entities/organization/index.ts +1 -0
- package/generated/entities.ids.generated.ts +14 -1
- package/generated/entity-fields-registry.ts +18 -0
- package/package.json +3 -3
- package/src/modules/auth/services/rbacService.ts +3 -9
- package/src/modules/customer_accounts/AGENTS.md +377 -0
- package/src/modules/customer_accounts/acl.ts +8 -0
- package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +98 -0
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +246 -0
- package/src/modules/customer_accounts/api/admin/roles.ts +212 -0
- package/src/modules/customer_accounts/api/admin/users/[id]/reset-password.ts +78 -0
- package/src/modules/customer_accounts/api/admin/users/[id]/verify-email.ts +72 -0
- package/src/modules/customer_accounts/api/admin/users/[id].ts +289 -0
- package/src/modules/customer_accounts/api/admin/users-invite.ts +86 -0
- package/src/modules/customer_accounts/api/admin/users.ts +280 -0
- package/src/modules/customer_accounts/api/email/verify.ts +66 -0
- package/src/modules/customer_accounts/api/interceptors.ts +3 -0
- package/src/modules/customer_accounts/api/invitations/accept.ts +128 -0
- package/src/modules/customer_accounts/api/login.ts +163 -0
- package/src/modules/customer_accounts/api/magic-link/request.ts +87 -0
- package/src/modules/customer_accounts/api/magic-link/verify.ts +132 -0
- package/src/modules/customer_accounts/api/password/reset-confirm.ts +69 -0
- package/src/modules/customer_accounts/api/password/reset-request.ts +87 -0
- package/src/modules/customer_accounts/api/portal/events/stream.ts +209 -0
- package/src/modules/customer_accounts/api/portal/feature-check.ts +60 -0
- package/src/modules/customer_accounts/api/portal/logout.ts +71 -0
- package/src/modules/customer_accounts/api/portal/notifications/[id]/dismiss.ts +54 -0
- package/src/modules/customer_accounts/api/portal/notifications/[id]/read.ts +54 -0
- package/src/modules/customer_accounts/api/portal/notifications/mark-all-read.ts +49 -0
- package/src/modules/customer_accounts/api/portal/notifications/unread-count.ts +45 -0
- package/src/modules/customer_accounts/api/portal/notifications.ts +115 -0
- package/src/modules/customer_accounts/api/portal/password-change.ts +65 -0
- package/src/modules/customer_accounts/api/portal/profile.ts +151 -0
- package/src/modules/customer_accounts/api/portal/sessions/[id].ts +70 -0
- package/src/modules/customer_accounts/api/portal/sessions-refresh.ts +87 -0
- package/src/modules/customer_accounts/api/portal/sessions.ts +84 -0
- package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +106 -0
- package/src/modules/customer_accounts/api/portal/users/[id].ts +81 -0
- package/src/modules/customer_accounts/api/portal/users-invite.ts +103 -0
- package/src/modules/customer_accounts/api/portal/users.ts +86 -0
- package/src/modules/customer_accounts/api/signup.ts +136 -0
- package/src/modules/customer_accounts/backend/customer_accounts/[id]/page.meta.ts +11 -0
- package/src/modules/customer_accounts/backend/customer_accounts/[id]/page.tsx +607 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.meta.ts +12 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +385 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/create/page.meta.ts +12 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/create/page.tsx +203 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.meta.ts +31 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +217 -0
- package/src/modules/customer_accounts/backend/page.meta.ts +33 -0
- package/src/modules/customer_accounts/backend/page.tsx +535 -0
- package/src/modules/customer_accounts/ce.ts +22 -0
- package/src/modules/customer_accounts/data/enrichers.ts +117 -0
- package/src/modules/customer_accounts/data/entities.ts +302 -0
- package/src/modules/customer_accounts/data/extensions.ts +4 -0
- package/src/modules/customer_accounts/data/validators.ts +128 -0
- package/src/modules/customer_accounts/di.ts +15 -0
- package/src/modules/customer_accounts/events.ts +28 -0
- package/src/modules/customer_accounts/i18n/de.json +176 -0
- package/src/modules/customer_accounts/i18n/en.json +176 -0
- package/src/modules/customer_accounts/i18n/es.json +176 -0
- package/src/modules/customer_accounts/i18n/pl.json +176 -0
- package/src/modules/customer_accounts/index.ts +13 -0
- package/src/modules/customer_accounts/lib/customerAuth.ts +85 -0
- package/src/modules/customer_accounts/lib/customerAuthServer.ts +54 -0
- package/src/modules/customer_accounts/lib/rateLimiter.ts +36 -0
- package/src/modules/customer_accounts/lib/tokenGenerator.ts +9 -0
- package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +1255 -0
- package/src/modules/customer_accounts/migrations/Migration20260313222043.ts +62 -0
- package/src/modules/customer_accounts/notifications.client.ts +46 -0
- package/src/modules/customer_accounts/notifications.ts +44 -0
- package/src/modules/customer_accounts/search.ts +134 -0
- package/src/modules/customer_accounts/services/customerInvitationService.ts +109 -0
- package/src/modules/customer_accounts/services/customerRbacService.ts +144 -0
- package/src/modules/customer_accounts/services/customerSessionService.ts +90 -0
- package/src/modules/customer_accounts/services/customerTokenService.ts +98 -0
- package/src/modules/customer_accounts/services/customerUserService.ts +105 -0
- package/src/modules/customer_accounts/setup.ts +212 -0
- package/src/modules/customer_accounts/subscribers/autoLinkCrm.ts +65 -0
- package/src/modules/customer_accounts/subscribers/autoLinkCrmReverse.ts +78 -0
- package/src/modules/customer_accounts/subscribers/notifyStaffOnSignup.ts +32 -0
- package/src/modules/customer_accounts/translations.ts +5 -0
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +89 -0
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.ts +16 -0
- package/src/modules/customer_accounts/widgets/injection/company-users/widget.client.tsx +78 -0
- package/src/modules/customer_accounts/widgets/injection/company-users/widget.ts +16 -0
- package/src/modules/customer_accounts/widgets/injection-table.ts +24 -0
- package/src/modules/customer_accounts/workers/cleanupExpiredSessions.ts +33 -0
- package/src/modules/customer_accounts/workers/cleanupExpiredTokens.ts +51 -0
- package/src/modules/customers/components/AddressTiles.tsx +1 -1
- package/src/modules/directory/api/get/organizations/lookup.ts +92 -0
- package/src/modules/directory/commands/organizations.ts +34 -1
- package/src/modules/directory/data/entities.ts +5 -1
- package/src/modules/directory/data/validators.ts +4 -0
- package/src/modules/directory/migrations/.snapshot-open-mercato.json +20 -1
- package/src/modules/directory/migrations/Migration20260314143323.ts +15 -0
- package/src/modules/directory/setup.ts +41 -0
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +4 -1
- package/src/modules/payment_gateways/migrations/Migration20260313222043.ts +17 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +158 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +120 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +118 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +112 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +138 -0
- package/src/modules/portal/i18n/de.json +93 -0
- package/src/modules/portal/i18n/en.json +93 -0
- package/src/modules/portal/i18n/es.json +93 -0
- package/src/modules/portal/i18n/pl.json +93 -0
- package/src/modules/portal/index.ts +9 -0
- package/src/modules/portal/setup.ts +23 -0
- package/src/modules/shipping_carriers/migrations/.snapshot-open-mercato.json +226 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
4
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
5
|
+
import { CustomerUser, CustomerUserRole, CustomerRole, CustomerUserSession } from "@open-mercato/core/modules/customer_accounts/data/entities";
|
|
6
|
+
import { adminUpdateUserSchema } from "@open-mercato/core/modules/customer_accounts/data/validators";
|
|
7
|
+
import { emitCustomerAccountsEvent } from "@open-mercato/core/modules/customer_accounts/events";
|
|
8
|
+
const metadata = {};
|
|
9
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10
|
+
async function GET(req, { params }) {
|
|
11
|
+
if (!UUID_RE.test(params.id)) {
|
|
12
|
+
return NextResponse.json({ ok: false, error: "Invalid user ID" }, { status: 400 });
|
|
13
|
+
}
|
|
14
|
+
const auth = await getAuthFromRequest(req);
|
|
15
|
+
if (!auth) {
|
|
16
|
+
return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
|
|
17
|
+
}
|
|
18
|
+
const container = await createRequestContainer();
|
|
19
|
+
const rbacService = container.resolve("rbacService");
|
|
20
|
+
const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ["customer_accounts.view"], { tenantId: auth.tenantId, organizationId: auth.orgId });
|
|
21
|
+
if (!hasAccess) {
|
|
22
|
+
return NextResponse.json({ ok: false, error: "Insufficient permissions" }, { status: 403 });
|
|
23
|
+
}
|
|
24
|
+
const em = container.resolve("em");
|
|
25
|
+
const user = await em.findOne(CustomerUser, {
|
|
26
|
+
id: params.id,
|
|
27
|
+
tenantId: auth.tenantId,
|
|
28
|
+
deletedAt: null
|
|
29
|
+
});
|
|
30
|
+
if (!user) {
|
|
31
|
+
return NextResponse.json({ ok: false, error: "User not found" }, { status: 404 });
|
|
32
|
+
}
|
|
33
|
+
const userRoles = await em.find(CustomerUserRole, {
|
|
34
|
+
user: user.id,
|
|
35
|
+
deletedAt: null
|
|
36
|
+
}, { populate: ["role"] });
|
|
37
|
+
const roles = userRoles.map((ur) => ({
|
|
38
|
+
id: ur.role.id,
|
|
39
|
+
name: ur.role.name,
|
|
40
|
+
slug: ur.role.slug
|
|
41
|
+
}));
|
|
42
|
+
const activeSessions = await em.find(CustomerUserSession, {
|
|
43
|
+
user: user.id,
|
|
44
|
+
deletedAt: null,
|
|
45
|
+
expiresAt: { $gt: /* @__PURE__ */ new Date() }
|
|
46
|
+
}, { orderBy: { lastUsedAt: "DESC" } });
|
|
47
|
+
const sessions = activeSessions.map((session) => ({
|
|
48
|
+
id: session.id,
|
|
49
|
+
ipAddress: session.ipAddress || null,
|
|
50
|
+
userAgent: session.userAgent || null,
|
|
51
|
+
lastUsedAt: session.lastUsedAt || null,
|
|
52
|
+
createdAt: session.createdAt,
|
|
53
|
+
expiresAt: session.expiresAt
|
|
54
|
+
}));
|
|
55
|
+
return NextResponse.json({
|
|
56
|
+
ok: true,
|
|
57
|
+
id: user.id,
|
|
58
|
+
email: user.email,
|
|
59
|
+
displayName: user.displayName,
|
|
60
|
+
emailVerifiedAt: user.emailVerifiedAt || null,
|
|
61
|
+
isActive: user.isActive,
|
|
62
|
+
lockedUntil: user.lockedUntil || null,
|
|
63
|
+
lastLoginAt: user.lastLoginAt || null,
|
|
64
|
+
customerEntityId: user.customerEntityId || null,
|
|
65
|
+
personEntityId: user.personEntityId || null,
|
|
66
|
+
createdAt: user.createdAt,
|
|
67
|
+
updatedAt: user.updatedAt || null,
|
|
68
|
+
roles,
|
|
69
|
+
sessions
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function PUT(req, { params }) {
|
|
73
|
+
const auth = await getAuthFromRequest(req);
|
|
74
|
+
if (!auth) {
|
|
75
|
+
return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
|
|
76
|
+
}
|
|
77
|
+
const container = await createRequestContainer();
|
|
78
|
+
const rbacService = container.resolve("rbacService");
|
|
79
|
+
const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ["customer_accounts.manage"], { tenantId: auth.tenantId, organizationId: auth.orgId });
|
|
80
|
+
if (!hasAccess) {
|
|
81
|
+
return NextResponse.json({ ok: false, error: "Insufficient permissions" }, { status: 403 });
|
|
82
|
+
}
|
|
83
|
+
let body;
|
|
84
|
+
try {
|
|
85
|
+
body = await req.json();
|
|
86
|
+
} catch {
|
|
87
|
+
return NextResponse.json({ ok: false, error: "Invalid request body" }, { status: 400 });
|
|
88
|
+
}
|
|
89
|
+
const parsed = adminUpdateUserSchema.safeParse(body);
|
|
90
|
+
if (!parsed.success) {
|
|
91
|
+
return NextResponse.json({ ok: false, error: "Validation failed", details: parsed.error.flatten().fieldErrors }, { status: 400 });
|
|
92
|
+
}
|
|
93
|
+
const em = container.resolve("em");
|
|
94
|
+
const user = await em.findOne(CustomerUser, {
|
|
95
|
+
id: params.id,
|
|
96
|
+
tenantId: auth.tenantId,
|
|
97
|
+
deletedAt: null
|
|
98
|
+
});
|
|
99
|
+
if (!user) {
|
|
100
|
+
return NextResponse.json({ ok: false, error: "User not found" }, { status: 404 });
|
|
101
|
+
}
|
|
102
|
+
const updates = {};
|
|
103
|
+
if (parsed.data.displayName !== void 0) updates.displayName = parsed.data.displayName;
|
|
104
|
+
if (parsed.data.isActive !== void 0) updates.isActive = parsed.data.isActive;
|
|
105
|
+
if (parsed.data.lockedUntil !== void 0) updates.lockedUntil = parsed.data.lockedUntil ? new Date(parsed.data.lockedUntil) : null;
|
|
106
|
+
if (parsed.data.personEntityId !== void 0) updates.personEntityId = parsed.data.personEntityId;
|
|
107
|
+
if (parsed.data.customerEntityId !== void 0) updates.customerEntityId = parsed.data.customerEntityId;
|
|
108
|
+
if (Object.keys(updates).length > 0) {
|
|
109
|
+
await em.nativeUpdate(CustomerUser, { id: user.id }, updates);
|
|
110
|
+
}
|
|
111
|
+
let rolesChanged = false;
|
|
112
|
+
if (parsed.data.roleIds !== void 0) {
|
|
113
|
+
const validRoles = [];
|
|
114
|
+
for (const roleId of parsed.data.roleIds) {
|
|
115
|
+
const role = await em.findOne(CustomerRole, { id: roleId, tenantId: auth.tenantId, deletedAt: null });
|
|
116
|
+
if (!role) {
|
|
117
|
+
return NextResponse.json({ ok: false, error: `Role ${roleId} not found` }, { status: 400 });
|
|
118
|
+
}
|
|
119
|
+
validRoles.push(role);
|
|
120
|
+
}
|
|
121
|
+
await em.nativeDelete(CustomerUserRole, { user: user.id });
|
|
122
|
+
for (const role of validRoles) {
|
|
123
|
+
const userRole = em.create(CustomerUserRole, {
|
|
124
|
+
user,
|
|
125
|
+
role,
|
|
126
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
127
|
+
});
|
|
128
|
+
em.persist(userRole);
|
|
129
|
+
}
|
|
130
|
+
await em.flush();
|
|
131
|
+
rolesChanged = true;
|
|
132
|
+
}
|
|
133
|
+
if (rolesChanged) {
|
|
134
|
+
const customerRbacService = container.resolve("customerRbacService");
|
|
135
|
+
await customerRbacService.invalidateUserCache(user.id);
|
|
136
|
+
}
|
|
137
|
+
void emitCustomerAccountsEvent("customer_accounts.user.updated", {
|
|
138
|
+
id: user.id,
|
|
139
|
+
email: user.email,
|
|
140
|
+
tenantId: auth.tenantId,
|
|
141
|
+
organizationId: auth.orgId,
|
|
142
|
+
updatedBy: auth.sub
|
|
143
|
+
}).catch(() => void 0);
|
|
144
|
+
return NextResponse.json({ ok: true });
|
|
145
|
+
}
|
|
146
|
+
async function DELETE(req, { params }) {
|
|
147
|
+
const auth = await getAuthFromRequest(req);
|
|
148
|
+
if (!auth) {
|
|
149
|
+
return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
|
|
150
|
+
}
|
|
151
|
+
const container = await createRequestContainer();
|
|
152
|
+
const rbacService = container.resolve("rbacService");
|
|
153
|
+
const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ["customer_accounts.manage"], { tenantId: auth.tenantId, organizationId: auth.orgId });
|
|
154
|
+
if (!hasAccess) {
|
|
155
|
+
return NextResponse.json({ ok: false, error: "Insufficient permissions" }, { status: 403 });
|
|
156
|
+
}
|
|
157
|
+
const em = container.resolve("em");
|
|
158
|
+
const user = await em.findOne(CustomerUser, {
|
|
159
|
+
id: params.id,
|
|
160
|
+
tenantId: auth.tenantId,
|
|
161
|
+
deletedAt: null
|
|
162
|
+
});
|
|
163
|
+
if (!user) {
|
|
164
|
+
return NextResponse.json({ ok: false, error: "User not found" }, { status: 404 });
|
|
165
|
+
}
|
|
166
|
+
const customerUserService = container.resolve("customerUserService");
|
|
167
|
+
const customerSessionService = container.resolve("customerSessionService");
|
|
168
|
+
await customerUserService.softDelete(user.id);
|
|
169
|
+
await customerSessionService.revokeAllUserSessions(user.id);
|
|
170
|
+
void emitCustomerAccountsEvent("customer_accounts.user.deleted", {
|
|
171
|
+
id: user.id,
|
|
172
|
+
email: user.email,
|
|
173
|
+
tenantId: auth.tenantId,
|
|
174
|
+
organizationId: auth.orgId,
|
|
175
|
+
deletedBy: auth.sub
|
|
176
|
+
}).catch(() => void 0);
|
|
177
|
+
return NextResponse.json({ ok: true });
|
|
178
|
+
}
|
|
179
|
+
const roleSchema = z.object({ id: z.string().uuid(), name: z.string(), slug: z.string() });
|
|
180
|
+
const userDetailSchema = z.object({
|
|
181
|
+
id: z.string().uuid(),
|
|
182
|
+
email: z.string(),
|
|
183
|
+
displayName: z.string(),
|
|
184
|
+
emailVerified: z.boolean(),
|
|
185
|
+
isActive: z.boolean(),
|
|
186
|
+
lockedUntil: z.string().datetime().nullable(),
|
|
187
|
+
lastLoginAt: z.string().datetime().nullable(),
|
|
188
|
+
failedLoginAttempts: z.number(),
|
|
189
|
+
customerEntityId: z.string().uuid().nullable(),
|
|
190
|
+
personEntityId: z.string().uuid().nullable(),
|
|
191
|
+
createdAt: z.string().datetime(),
|
|
192
|
+
updatedAt: z.string().datetime().nullable(),
|
|
193
|
+
roles: z.array(roleSchema),
|
|
194
|
+
activeSessionCount: z.number()
|
|
195
|
+
});
|
|
196
|
+
const successSchema = z.object({ ok: z.literal(true) });
|
|
197
|
+
const errorSchema = z.object({ ok: z.literal(false), error: z.string() });
|
|
198
|
+
const getMethodDoc = {
|
|
199
|
+
summary: "Get customer user detail (admin)",
|
|
200
|
+
description: "Returns full customer user details including CRM links, roles, and active session count.",
|
|
201
|
+
tags: ["Customer Accounts Admin"],
|
|
202
|
+
responses: [{
|
|
203
|
+
status: 200,
|
|
204
|
+
description: "User detail",
|
|
205
|
+
schema: z.object({ ok: z.literal(true), user: userDetailSchema })
|
|
206
|
+
}],
|
|
207
|
+
errors: [
|
|
208
|
+
{ status: 401, description: "Not authenticated", schema: errorSchema },
|
|
209
|
+
{ status: 403, description: "Insufficient permissions", schema: errorSchema },
|
|
210
|
+
{ status: 404, description: "User not found", schema: errorSchema }
|
|
211
|
+
]
|
|
212
|
+
};
|
|
213
|
+
const putMethodDoc = {
|
|
214
|
+
summary: "Update customer user (admin)",
|
|
215
|
+
description: "Updates a customer user. Staff can update status, lock, CRM links, and roles. Role assignment bypasses customer_assignable check.",
|
|
216
|
+
tags: ["Customer Accounts Admin"],
|
|
217
|
+
requestBody: { schema: adminUpdateUserSchema },
|
|
218
|
+
responses: [{ status: 200, description: "User updated", schema: successSchema }],
|
|
219
|
+
errors: [
|
|
220
|
+
{ status: 400, description: "Validation failed or role not found", schema: errorSchema },
|
|
221
|
+
{ status: 401, description: "Not authenticated", schema: errorSchema },
|
|
222
|
+
{ status: 403, description: "Insufficient permissions", schema: errorSchema },
|
|
223
|
+
{ status: 404, description: "User not found", schema: errorSchema }
|
|
224
|
+
]
|
|
225
|
+
};
|
|
226
|
+
const deleteMethodDoc = {
|
|
227
|
+
summary: "Delete customer user (admin)",
|
|
228
|
+
description: "Soft deletes a customer user and revokes all their active sessions.",
|
|
229
|
+
tags: ["Customer Accounts Admin"],
|
|
230
|
+
responses: [{ status: 200, description: "User deleted", schema: successSchema }],
|
|
231
|
+
errors: [
|
|
232
|
+
{ status: 401, description: "Not authenticated", schema: errorSchema },
|
|
233
|
+
{ status: 403, description: "Insufficient permissions", schema: errorSchema },
|
|
234
|
+
{ status: 404, description: "User not found", schema: errorSchema }
|
|
235
|
+
]
|
|
236
|
+
};
|
|
237
|
+
const openApi = {
|
|
238
|
+
summary: "Customer user detail management (admin)",
|
|
239
|
+
pathParams: z.object({ id: z.string().uuid() }),
|
|
240
|
+
methods: {
|
|
241
|
+
GET: getMethodDoc,
|
|
242
|
+
PUT: putMethodDoc,
|
|
243
|
+
DELETE: deleteMethodDoc
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
export {
|
|
247
|
+
DELETE,
|
|
248
|
+
GET,
|
|
249
|
+
PUT,
|
|
250
|
+
metadata,
|
|
251
|
+
openApi
|
|
252
|
+
};
|
|
253
|
+
//# sourceMappingURL=%5Bid%5D.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customer_accounts/api/admin/users/%5Bid%5D.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc, OpenApiMethodDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CustomerUser, CustomerUserRole, CustomerRole, CustomerUserSession } from '@open-mercato/core/modules/customer_accounts/data/entities'\nimport { CustomerUserService } from '@open-mercato/core/modules/customer_accounts/services/customerUserService'\nimport { CustomerSessionService } from '@open-mercato/core/modules/customer_accounts/services/customerSessionService'\nimport { CustomerRbacService } from '@open-mercato/core/modules/customer_accounts/services/customerRbacService'\nimport { adminUpdateUserSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'\nimport { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'\n\nexport const metadata = {}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nexport async function GET(req: Request, { params }: { params: { id: string } }) {\n if (!UUID_RE.test(params.id)) {\n return NextResponse.json({ ok: false, error: 'Invalid user ID' }, { status: 400 })\n }\n\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ ok: false, error: 'Authentication required' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const rbacService = container.resolve('rbacService') as RbacService\n const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ['customer_accounts.view'], { tenantId: auth.tenantId, organizationId: auth.orgId })\n if (!hasAccess) {\n return NextResponse.json({ ok: false, error: 'Insufficient permissions' }, { status: 403 })\n }\n\n const em = container.resolve('em') as import('@mikro-orm/postgresql').EntityManager\n\n const user = await em.findOne(CustomerUser, {\n id: params.id,\n tenantId: auth.tenantId,\n deletedAt: null,\n })\n if (!user) {\n return NextResponse.json({ ok: false, error: 'User not found' }, { status: 404 })\n }\n\n const userRoles = await em.find(CustomerUserRole, {\n user: user.id as any,\n deletedAt: null,\n }, { populate: ['role'] })\n const roles = userRoles.map((ur) => ({\n id: (ur.role as any).id,\n name: (ur.role as any).name,\n slug: (ur.role as any).slug,\n }))\n\n const activeSessions = await em.find(CustomerUserSession, {\n user: user.id as any,\n deletedAt: null,\n expiresAt: { $gt: new Date() },\n }, { orderBy: { lastUsedAt: 'DESC' } })\n\n const sessions = activeSessions.map((session) => ({\n id: session.id,\n ipAddress: (session as any).ipAddress || null,\n userAgent: (session as any).userAgent || null,\n lastUsedAt: (session as any).lastUsedAt || null,\n createdAt: session.createdAt,\n expiresAt: session.expiresAt,\n }))\n\n return NextResponse.json({\n ok: true,\n id: user.id,\n email: user.email,\n displayName: user.displayName,\n emailVerifiedAt: user.emailVerifiedAt || null,\n isActive: user.isActive,\n lockedUntil: user.lockedUntil || null,\n lastLoginAt: user.lastLoginAt || null,\n customerEntityId: user.customerEntityId || null,\n personEntityId: user.personEntityId || null,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt || null,\n roles,\n sessions,\n })\n}\n\nexport async function PUT(req: Request, { params }: { params: { id: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ ok: false, error: 'Authentication required' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const rbacService = container.resolve('rbacService') as RbacService\n const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ['customer_accounts.manage'], { tenantId: auth.tenantId, organizationId: auth.orgId })\n if (!hasAccess) {\n return NextResponse.json({ ok: false, error: 'Insufficient permissions' }, { status: 403 })\n }\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ ok: false, error: 'Invalid request body' }, { status: 400 })\n }\n\n const parsed = adminUpdateUserSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: 'Validation failed', details: parsed.error.flatten().fieldErrors }, { status: 400 })\n }\n\n const em = container.resolve('em') as import('@mikro-orm/postgresql').EntityManager\n\n const user = await em.findOne(CustomerUser, {\n id: params.id,\n tenantId: auth.tenantId,\n deletedAt: null,\n })\n if (!user) {\n return NextResponse.json({ ok: false, error: 'User not found' }, { status: 404 })\n }\n\n const updates: Record<string, unknown> = {}\n if (parsed.data.displayName !== undefined) updates.displayName = parsed.data.displayName\n if (parsed.data.isActive !== undefined) updates.isActive = parsed.data.isActive\n if (parsed.data.lockedUntil !== undefined) updates.lockedUntil = parsed.data.lockedUntil ? new Date(parsed.data.lockedUntil) : null\n if (parsed.data.personEntityId !== undefined) updates.personEntityId = parsed.data.personEntityId\n if (parsed.data.customerEntityId !== undefined) updates.customerEntityId = parsed.data.customerEntityId\n\n if (Object.keys(updates).length > 0) {\n await em.nativeUpdate(CustomerUser, { id: user.id }, updates)\n }\n\n let rolesChanged = false\n if (parsed.data.roleIds !== undefined) {\n const validRoles: InstanceType<typeof CustomerRole>[] = []\n for (const roleId of parsed.data.roleIds) {\n const role = await em.findOne(CustomerRole, { id: roleId, tenantId: auth.tenantId, deletedAt: null })\n if (!role) {\n return NextResponse.json({ ok: false, error: `Role ${roleId} not found` }, { status: 400 })\n }\n validRoles.push(role)\n }\n\n await em.nativeDelete(CustomerUserRole, { user: user.id } as Record<string, unknown>)\n\n for (const role of validRoles) {\n const userRole = em.create(CustomerUserRole, {\n user,\n role,\n createdAt: new Date(),\n } as any)\n em.persist(userRole)\n }\n await em.flush()\n rolesChanged = true\n }\n\n if (rolesChanged) {\n const customerRbacService = container.resolve('customerRbacService') as CustomerRbacService\n await customerRbacService.invalidateUserCache(user.id)\n }\n\n void emitCustomerAccountsEvent('customer_accounts.user.updated', {\n id: user.id,\n email: user.email,\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n updatedBy: auth.sub,\n }).catch(() => undefined)\n\n return NextResponse.json({ ok: true })\n}\n\nexport async function DELETE(req: Request, { params }: { params: { id: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ ok: false, error: 'Authentication required' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const rbacService = container.resolve('rbacService') as RbacService\n const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ['customer_accounts.manage'], { tenantId: auth.tenantId, organizationId: auth.orgId })\n if (!hasAccess) {\n return NextResponse.json({ ok: false, error: 'Insufficient permissions' }, { status: 403 })\n }\n\n const em = container.resolve('em') as import('@mikro-orm/postgresql').EntityManager\n\n const user = await em.findOne(CustomerUser, {\n id: params.id,\n tenantId: auth.tenantId,\n deletedAt: null,\n })\n if (!user) {\n return NextResponse.json({ ok: false, error: 'User not found' }, { status: 404 })\n }\n\n const customerUserService = container.resolve('customerUserService') as CustomerUserService\n const customerSessionService = container.resolve('customerSessionService') as CustomerSessionService\n\n await customerUserService.softDelete(user.id)\n await customerSessionService.revokeAllUserSessions(user.id)\n\n void emitCustomerAccountsEvent('customer_accounts.user.deleted', {\n id: user.id,\n email: user.email,\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n deletedBy: auth.sub,\n }).catch(() => undefined)\n\n return NextResponse.json({ ok: true })\n}\n\nconst roleSchema = z.object({ id: z.string().uuid(), name: z.string(), slug: z.string() })\nconst userDetailSchema = z.object({\n id: z.string().uuid(),\n email: z.string(),\n displayName: z.string(),\n emailVerified: z.boolean(),\n isActive: z.boolean(),\n lockedUntil: z.string().datetime().nullable(),\n lastLoginAt: z.string().datetime().nullable(),\n failedLoginAttempts: z.number(),\n customerEntityId: z.string().uuid().nullable(),\n personEntityId: z.string().uuid().nullable(),\n createdAt: z.string().datetime(),\n updatedAt: z.string().datetime().nullable(),\n roles: z.array(roleSchema),\n activeSessionCount: z.number(),\n})\n\nconst successSchema = z.object({ ok: z.literal(true) })\nconst errorSchema = z.object({ ok: z.literal(false), error: z.string() })\n\nconst getMethodDoc: OpenApiMethodDoc = {\n summary: 'Get customer user detail (admin)',\n description: 'Returns full customer user details including CRM links, roles, and active session count.',\n tags: ['Customer Accounts Admin'],\n responses: [{\n status: 200,\n description: 'User detail',\n schema: z.object({ ok: z.literal(true), user: userDetailSchema }),\n }],\n errors: [\n { status: 401, description: 'Not authenticated', schema: errorSchema },\n { status: 403, description: 'Insufficient permissions', schema: errorSchema },\n { status: 404, description: 'User not found', schema: errorSchema },\n ],\n}\n\nconst putMethodDoc: OpenApiMethodDoc = {\n summary: 'Update customer user (admin)',\n description: 'Updates a customer user. Staff can update status, lock, CRM links, and roles. Role assignment bypasses customer_assignable check.',\n tags: ['Customer Accounts Admin'],\n requestBody: { schema: adminUpdateUserSchema },\n responses: [{ status: 200, description: 'User updated', schema: successSchema }],\n errors: [\n { status: 400, description: 'Validation failed or role not found', schema: errorSchema },\n { status: 401, description: 'Not authenticated', schema: errorSchema },\n { status: 403, description: 'Insufficient permissions', schema: errorSchema },\n { status: 404, description: 'User not found', schema: errorSchema },\n ],\n}\n\nconst deleteMethodDoc: OpenApiMethodDoc = {\n summary: 'Delete customer user (admin)',\n description: 'Soft deletes a customer user and revokes all their active sessions.',\n tags: ['Customer Accounts Admin'],\n responses: [{ status: 200, description: 'User deleted', schema: successSchema }],\n errors: [\n { status: 401, description: 'Not authenticated', schema: errorSchema },\n { status: 403, description: 'Insufficient permissions', schema: errorSchema },\n { status: 404, description: 'User not found', schema: errorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Customer user detail management (admin)',\n pathParams: z.object({ id: z.string().uuid() }),\n methods: {\n GET: getMethodDoc,\n PUT: putMethodDoc,\n DELETE: deleteMethodDoc,\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
4
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
5
|
+
import { inviteUserSchema } from "@open-mercato/core/modules/customer_accounts/data/validators";
|
|
6
|
+
const metadata = {};
|
|
7
|
+
async function POST(req) {
|
|
8
|
+
const auth = await getAuthFromRequest(req);
|
|
9
|
+
if (!auth) {
|
|
10
|
+
return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
|
|
11
|
+
}
|
|
12
|
+
const container = await createRequestContainer();
|
|
13
|
+
const rbacService = container.resolve("rbacService");
|
|
14
|
+
const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ["customer_accounts.invite"], { tenantId: auth.tenantId, organizationId: auth.orgId });
|
|
15
|
+
if (!hasAccess) {
|
|
16
|
+
return NextResponse.json({ ok: false, error: "Insufficient permissions" }, { status: 403 });
|
|
17
|
+
}
|
|
18
|
+
let body;
|
|
19
|
+
try {
|
|
20
|
+
body = await req.json();
|
|
21
|
+
} catch {
|
|
22
|
+
return NextResponse.json({ ok: false, error: "Invalid request body" }, { status: 400 });
|
|
23
|
+
}
|
|
24
|
+
const parsed = inviteUserSchema.safeParse(body);
|
|
25
|
+
if (!parsed.success) {
|
|
26
|
+
return NextResponse.json({ ok: false, error: "Validation failed", details: parsed.error.flatten().fieldErrors }, { status: 400 });
|
|
27
|
+
}
|
|
28
|
+
const customerInvitationService = container.resolve("customerInvitationService");
|
|
29
|
+
const { invitation } = await customerInvitationService.createInvitation(
|
|
30
|
+
parsed.data.email,
|
|
31
|
+
{ tenantId: auth.tenantId, organizationId: auth.orgId },
|
|
32
|
+
{
|
|
33
|
+
customerEntityId: parsed.data.customerEntityId || null,
|
|
34
|
+
roleIds: parsed.data.roleIds,
|
|
35
|
+
invitedByUserId: auth.sub,
|
|
36
|
+
displayName: parsed.data.displayName || null
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
return NextResponse.json({
|
|
40
|
+
ok: true,
|
|
41
|
+
invitation: {
|
|
42
|
+
id: invitation.id,
|
|
43
|
+
email: invitation.email,
|
|
44
|
+
expiresAt: invitation.expiresAt
|
|
45
|
+
}
|
|
46
|
+
}, { status: 201 });
|
|
47
|
+
}
|
|
48
|
+
const successSchema = z.object({
|
|
49
|
+
ok: z.literal(true),
|
|
50
|
+
invitation: z.object({
|
|
51
|
+
id: z.string().uuid(),
|
|
52
|
+
email: z.string(),
|
|
53
|
+
expiresAt: z.string().datetime()
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
const errorSchema = z.object({ ok: z.literal(false), error: z.string() });
|
|
57
|
+
const methodDoc = {
|
|
58
|
+
summary: "Invite customer user (admin)",
|
|
59
|
+
description: "Creates a staff-initiated invitation for a new customer user. The invitedByUserId is set from the staff auth context.",
|
|
60
|
+
tags: ["Customer Accounts Admin"],
|
|
61
|
+
requestBody: { schema: inviteUserSchema },
|
|
62
|
+
responses: [{ status: 201, description: "Invitation created", schema: successSchema }],
|
|
63
|
+
errors: [
|
|
64
|
+
{ status: 400, description: "Validation failed", schema: errorSchema },
|
|
65
|
+
{ status: 401, description: "Not authenticated", schema: errorSchema },
|
|
66
|
+
{ status: 403, description: "Insufficient permissions", schema: errorSchema }
|
|
67
|
+
]
|
|
68
|
+
};
|
|
69
|
+
const openApi = {
|
|
70
|
+
summary: "Invite customer user (admin)",
|
|
71
|
+
methods: { POST: methodDoc }
|
|
72
|
+
};
|
|
73
|
+
export {
|
|
74
|
+
POST,
|
|
75
|
+
metadata,
|
|
76
|
+
openApi
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=users-invite.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/customer_accounts/api/admin/users-invite.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc, OpenApiMethodDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CustomerInvitationService } from '@open-mercato/core/modules/customer_accounts/services/customerInvitationService'\nimport { inviteUserSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'\n\nexport const metadata = {}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ ok: false, error: 'Authentication required' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const rbacService = container.resolve('rbacService') as RbacService\n const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ['customer_accounts.invite'], { tenantId: auth.tenantId, organizationId: auth.orgId })\n if (!hasAccess) {\n return NextResponse.json({ ok: false, error: 'Insufficient permissions' }, { status: 403 })\n }\n\n let body: unknown\n try {\n body = await req.json()\n } catch {\n return NextResponse.json({ ok: false, error: 'Invalid request body' }, { status: 400 })\n }\n\n const parsed = inviteUserSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ ok: false, error: 'Validation failed', details: parsed.error.flatten().fieldErrors }, { status: 400 })\n }\n\n const customerInvitationService = container.resolve('customerInvitationService') as CustomerInvitationService\n\n const { invitation } = await customerInvitationService.createInvitation(\n parsed.data.email,\n { tenantId: auth.tenantId!, organizationId: auth.orgId! },\n {\n customerEntityId: parsed.data.customerEntityId || null,\n roleIds: parsed.data.roleIds,\n invitedByUserId: auth.sub,\n displayName: parsed.data.displayName || null,\n },\n )\n\n return NextResponse.json({\n ok: true,\n invitation: {\n id: invitation.id,\n email: invitation.email,\n expiresAt: invitation.expiresAt,\n },\n }, { status: 201 })\n}\n\nconst successSchema = z.object({\n ok: z.literal(true),\n invitation: z.object({\n id: z.string().uuid(),\n email: z.string(),\n expiresAt: z.string().datetime(),\n }),\n})\nconst errorSchema = z.object({ ok: z.literal(false), error: z.string() })\n\nconst methodDoc: OpenApiMethodDoc = {\n summary: 'Invite customer user (admin)',\n description: 'Creates a staff-initiated invitation for a new customer user. The invitedByUserId is set from the staff auth context.',\n tags: ['Customer Accounts Admin'],\n requestBody: { schema: inviteUserSchema },\n responses: [{ status: 201, description: 'Invitation created', schema: successSchema }],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Not authenticated', schema: errorSchema },\n { status: 403, description: 'Insufficient permissions', schema: errorSchema },\n ],\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Invite customer user (admin)',\n methods: { POST: methodDoc },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAElB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AAGvC,SAAS,wBAAwB;AAE1B,MAAM,WAAW,CAAC;AAEzB,eAAsB,KAAK,KAAc;AACvC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM;AACT,WAAO,aAAa,KAAK,EAAE,IAAI,OAAO,OAAO,0BAA0B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3F;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,cAAc,UAAU,QAAQ,aAAa;AACnD,QAAM,YAAY,MAAM,YAAY,mBAAmB,KAAK,KAAK,CAAC,0BAA0B,GAAG,EAAE,UAAU,KAAK,UAAU,gBAAgB,KAAK,MAAM,CAAC;AACtJ,MAAI,CAAC,WAAW;AACd,WAAO,aAAa,KAAK,EAAE,IAAI,OAAO,OAAO,2BAA2B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC5F;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO,aAAa,KAAK,EAAE,IAAI,OAAO,OAAO,uBAAuB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACxF;AAEA,QAAM,SAAS,iBAAiB,UAAU,IAAI;AAC9C,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,SAAS,OAAO,MAAM,QAAQ,EAAE,YAAY,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClI;AAEA,QAAM,4BAA4B,UAAU,QAAQ,2BAA2B;AAE/E,QAAM,EAAE,WAAW,IAAI,MAAM,0BAA0B;AAAA,IACrD,OAAO,KAAK;AAAA,IACZ,EAAE,UAAU,KAAK,UAAW,gBAAgB,KAAK,MAAO;AAAA,IACxD;AAAA,MACE,kBAAkB,OAAO,KAAK,oBAAoB;AAAA,MAClD,SAAS,OAAO,KAAK;AAAA,MACrB,iBAAiB,KAAK;AAAA,MACtB,aAAa,OAAO,KAAK,eAAe;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO,aAAa,KAAK;AAAA,IACvB,IAAI;AAAA,IACJ,YAAY;AAAA,MACV,IAAI,WAAW;AAAA,MACf,OAAO,WAAW;AAAA,MAClB,WAAW,WAAW;AAAA,IACxB;AAAA,EACF,GAAG,EAAE,QAAQ,IAAI,CAAC;AACpB;AAEA,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,YAAY,EAAE,OAAO;AAAA,IACnB,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,IACpB,OAAO,EAAE,OAAO;AAAA,IAChB,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,CAAC;AACH,CAAC;AACD,MAAM,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,KAAK,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC;AAExE,MAAM,YAA8B;AAAA,EAClC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM,CAAC,yBAAyB;AAAA,EAChC,aAAa,EAAE,QAAQ,iBAAiB;AAAA,EACxC,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,sBAAsB,QAAQ,cAAc,CAAC;AAAA,EACrF,QAAQ;AAAA,IACN,EAAE,QAAQ,KAAK,aAAa,qBAAqB,QAAQ,YAAY;AAAA,IACrE,EAAE,QAAQ,KAAK,aAAa,qBAAqB,QAAQ,YAAY;AAAA,IACrE,EAAE,QAAQ,KAAK,aAAa,4BAA4B,QAAQ,YAAY;AAAA,EAC9E;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,SAAS;AAAA,EACT,SAAS,EAAE,MAAM,UAAU;AAC7B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
4
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
5
|
+
import { CustomerUser, CustomerUserRole, CustomerRole } from "@open-mercato/core/modules/customer_accounts/data/entities";
|
|
6
|
+
import { adminCreateUserSchema } from "@open-mercato/core/modules/customer_accounts/data/validators";
|
|
7
|
+
import { emitCustomerAccountsEvent } from "@open-mercato/core/modules/customer_accounts/events";
|
|
8
|
+
const metadata = {};
|
|
9
|
+
async function GET(req) {
|
|
10
|
+
const auth = await getAuthFromRequest(req);
|
|
11
|
+
if (!auth) {
|
|
12
|
+
return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
|
|
13
|
+
}
|
|
14
|
+
const container = await createRequestContainer();
|
|
15
|
+
const rbacService = container.resolve("rbacService");
|
|
16
|
+
const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ["customer_accounts.view"], { tenantId: auth.tenantId, organizationId: auth.orgId });
|
|
17
|
+
if (!hasAccess) {
|
|
18
|
+
return NextResponse.json({ ok: false, error: "Insufficient permissions" }, { status: 403 });
|
|
19
|
+
}
|
|
20
|
+
const em = container.resolve("em");
|
|
21
|
+
const url = new URL(req.url);
|
|
22
|
+
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1"));
|
|
23
|
+
const pageSize = Math.min(100, Math.max(1, parseInt(url.searchParams.get("pageSize") || "25")));
|
|
24
|
+
const status = url.searchParams.get("status");
|
|
25
|
+
const customerEntityId = url.searchParams.get("customerEntityId");
|
|
26
|
+
const personEntityId = url.searchParams.get("personEntityId");
|
|
27
|
+
const roleId = url.searchParams.get("roleId");
|
|
28
|
+
const search = url.searchParams.get("search");
|
|
29
|
+
const where = {
|
|
30
|
+
tenantId: auth.tenantId,
|
|
31
|
+
organizationId: auth.orgId,
|
|
32
|
+
deletedAt: null
|
|
33
|
+
};
|
|
34
|
+
if (status === "active") {
|
|
35
|
+
where.isActive = true;
|
|
36
|
+
where.$or = [{ lockedUntil: null }, { lockedUntil: { $lt: /* @__PURE__ */ new Date() } }];
|
|
37
|
+
} else if (status === "inactive") {
|
|
38
|
+
where.isActive = false;
|
|
39
|
+
} else if (status === "locked") {
|
|
40
|
+
where.lockedUntil = { $gt: /* @__PURE__ */ new Date() };
|
|
41
|
+
}
|
|
42
|
+
if (customerEntityId) {
|
|
43
|
+
where.customerEntityId = customerEntityId;
|
|
44
|
+
}
|
|
45
|
+
if (personEntityId) {
|
|
46
|
+
where.personEntityId = personEntityId;
|
|
47
|
+
}
|
|
48
|
+
if (search) {
|
|
49
|
+
const escapedSearch = search.replace(/[%_\\]/g, "\\$&");
|
|
50
|
+
const searchFilter = [
|
|
51
|
+
{ email: { $ilike: `%${escapedSearch}%` } },
|
|
52
|
+
{ displayName: { $ilike: `%${escapedSearch}%` } }
|
|
53
|
+
];
|
|
54
|
+
if (where.$or) {
|
|
55
|
+
where.$and = [{ $or: where.$or }, { $or: searchFilter }];
|
|
56
|
+
delete where.$or;
|
|
57
|
+
} else {
|
|
58
|
+
where.$or = searchFilter;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let userIds = null;
|
|
62
|
+
if (roleId) {
|
|
63
|
+
const roleLinks = await em.find(CustomerUserRole, {
|
|
64
|
+
role: roleId,
|
|
65
|
+
deletedAt: null
|
|
66
|
+
});
|
|
67
|
+
userIds = roleLinks.map((link) => link.user?.id || link.user);
|
|
68
|
+
if (userIds.length === 0) {
|
|
69
|
+
return NextResponse.json({
|
|
70
|
+
ok: true,
|
|
71
|
+
items: [],
|
|
72
|
+
total: 0,
|
|
73
|
+
totalPages: 1,
|
|
74
|
+
page
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
where.id = { $in: userIds };
|
|
78
|
+
}
|
|
79
|
+
const offset = (page - 1) * pageSize;
|
|
80
|
+
const [users, total] = await em.findAndCount(CustomerUser, where, {
|
|
81
|
+
orderBy: { createdAt: "DESC" },
|
|
82
|
+
limit: pageSize,
|
|
83
|
+
offset
|
|
84
|
+
});
|
|
85
|
+
const items = await Promise.all(users.map(async (user) => {
|
|
86
|
+
const userRoles = await em.find(CustomerUserRole, {
|
|
87
|
+
user: user.id,
|
|
88
|
+
deletedAt: null
|
|
89
|
+
}, { populate: ["role"] });
|
|
90
|
+
const roles = userRoles.map((ur) => ({
|
|
91
|
+
id: ur.role.id,
|
|
92
|
+
name: ur.role.name,
|
|
93
|
+
slug: ur.role.slug
|
|
94
|
+
}));
|
|
95
|
+
return {
|
|
96
|
+
id: user.id,
|
|
97
|
+
email: user.email,
|
|
98
|
+
displayName: user.displayName,
|
|
99
|
+
emailVerified: !!user.emailVerifiedAt,
|
|
100
|
+
isActive: user.isActive,
|
|
101
|
+
lockedUntil: user.lockedUntil || null,
|
|
102
|
+
lastLoginAt: user.lastLoginAt || null,
|
|
103
|
+
customerEntityId: user.customerEntityId || null,
|
|
104
|
+
personEntityId: user.personEntityId || null,
|
|
105
|
+
createdAt: user.createdAt,
|
|
106
|
+
roles
|
|
107
|
+
};
|
|
108
|
+
}));
|
|
109
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
110
|
+
return NextResponse.json({
|
|
111
|
+
ok: true,
|
|
112
|
+
items,
|
|
113
|
+
total,
|
|
114
|
+
totalPages,
|
|
115
|
+
page
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function POST(req) {
|
|
119
|
+
const auth = await getAuthFromRequest(req);
|
|
120
|
+
if (!auth) {
|
|
121
|
+
return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
|
|
122
|
+
}
|
|
123
|
+
const container = await createRequestContainer();
|
|
124
|
+
const rbacService = container.resolve("rbacService");
|
|
125
|
+
const hasAccess = await rbacService.userHasAllFeatures(auth.sub, ["customer_accounts.manage"], { tenantId: auth.tenantId, organizationId: auth.orgId });
|
|
126
|
+
if (!hasAccess) {
|
|
127
|
+
return NextResponse.json({ ok: false, error: "Insufficient permissions" }, { status: 403 });
|
|
128
|
+
}
|
|
129
|
+
let body;
|
|
130
|
+
try {
|
|
131
|
+
body = await req.json();
|
|
132
|
+
} catch {
|
|
133
|
+
return NextResponse.json({ ok: false, error: "Invalid request body" }, { status: 400 });
|
|
134
|
+
}
|
|
135
|
+
const parsed = adminCreateUserSchema.safeParse(body);
|
|
136
|
+
if (!parsed.success) {
|
|
137
|
+
return NextResponse.json({ ok: false, error: "Validation failed", details: parsed.error.flatten().fieldErrors }, { status: 400 });
|
|
138
|
+
}
|
|
139
|
+
const em = container.resolve("em");
|
|
140
|
+
const customerUserService = container.resolve("customerUserService");
|
|
141
|
+
const existing = await customerUserService.findByEmail(parsed.data.email, auth.tenantId);
|
|
142
|
+
if (existing) {
|
|
143
|
+
return NextResponse.json({ ok: false, error: "A user with this email already exists" }, { status: 409 });
|
|
144
|
+
}
|
|
145
|
+
const user = await customerUserService.createUser(
|
|
146
|
+
parsed.data.email,
|
|
147
|
+
parsed.data.password,
|
|
148
|
+
parsed.data.displayName,
|
|
149
|
+
{ tenantId: auth.tenantId, organizationId: auth.orgId }
|
|
150
|
+
);
|
|
151
|
+
em.persist(user);
|
|
152
|
+
await em.flush();
|
|
153
|
+
if (parsed.data.customerEntityId) {
|
|
154
|
+
await em.nativeUpdate(CustomerUser, { id: user.id }, { customerEntityId: parsed.data.customerEntityId });
|
|
155
|
+
}
|
|
156
|
+
if (parsed.data.roleIds && parsed.data.roleIds.length > 0) {
|
|
157
|
+
const validRoles = [];
|
|
158
|
+
for (const roleId of parsed.data.roleIds) {
|
|
159
|
+
const role = await em.findOne(CustomerRole, { id: roleId, tenantId: auth.tenantId, deletedAt: null });
|
|
160
|
+
if (role) validRoles.push(role);
|
|
161
|
+
}
|
|
162
|
+
for (const role of validRoles) {
|
|
163
|
+
const userRole = em.create(CustomerUserRole, {
|
|
164
|
+
user,
|
|
165
|
+
role,
|
|
166
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
167
|
+
});
|
|
168
|
+
em.persist(userRole);
|
|
169
|
+
}
|
|
170
|
+
await em.flush();
|
|
171
|
+
}
|
|
172
|
+
void emitCustomerAccountsEvent("customer_accounts.user.created", {
|
|
173
|
+
id: user.id,
|
|
174
|
+
email: user.email,
|
|
175
|
+
tenantId: auth.tenantId,
|
|
176
|
+
organizationId: auth.orgId,
|
|
177
|
+
createdBy: auth.sub
|
|
178
|
+
}).catch(() => void 0);
|
|
179
|
+
return NextResponse.json({
|
|
180
|
+
ok: true,
|
|
181
|
+
user: { id: user.id, email: user.email, displayName: user.displayName }
|
|
182
|
+
}, { status: 201 });
|
|
183
|
+
}
|
|
184
|
+
const roleSchema = z.object({ id: z.string().uuid(), name: z.string(), slug: z.string() });
|
|
185
|
+
const userSchema = z.object({
|
|
186
|
+
id: z.string().uuid(),
|
|
187
|
+
email: z.string(),
|
|
188
|
+
displayName: z.string(),
|
|
189
|
+
emailVerified: z.boolean(),
|
|
190
|
+
isActive: z.boolean(),
|
|
191
|
+
lockedUntil: z.string().datetime().nullable(),
|
|
192
|
+
lastLoginAt: z.string().datetime().nullable(),
|
|
193
|
+
customerEntityId: z.string().uuid().nullable(),
|
|
194
|
+
personEntityId: z.string().uuid().nullable(),
|
|
195
|
+
createdAt: z.string().datetime(),
|
|
196
|
+
roles: z.array(roleSchema)
|
|
197
|
+
});
|
|
198
|
+
const successSchema = z.object({
|
|
199
|
+
ok: z.literal(true),
|
|
200
|
+
user: z.object({ id: z.string().uuid(), email: z.string(), displayName: z.string() })
|
|
201
|
+
});
|
|
202
|
+
const errorSchema = z.object({ ok: z.literal(false), error: z.string() });
|
|
203
|
+
const getMethodDoc = {
|
|
204
|
+
summary: "List customer users (admin)",
|
|
205
|
+
description: "Returns a paginated list of customer users with roles. Supports filtering by status, company, role, and search.",
|
|
206
|
+
tags: ["Customer Accounts Admin"],
|
|
207
|
+
query: z.object({
|
|
208
|
+
page: z.number().int().positive().optional(),
|
|
209
|
+
pageSize: z.number().int().positive().max(100).optional(),
|
|
210
|
+
status: z.enum(["active", "inactive", "locked"]).optional(),
|
|
211
|
+
customerEntityId: z.string().uuid().optional(),
|
|
212
|
+
roleId: z.string().uuid().optional(),
|
|
213
|
+
search: z.string().optional()
|
|
214
|
+
}),
|
|
215
|
+
responses: [{
|
|
216
|
+
status: 200,
|
|
217
|
+
description: "Paginated user list",
|
|
218
|
+
schema: z.object({ ok: z.literal(true), items: z.array(userSchema), total: z.number(), totalPages: z.number(), page: z.number() })
|
|
219
|
+
}],
|
|
220
|
+
errors: [
|
|
221
|
+
{ status: 401, description: "Not authenticated", schema: errorSchema },
|
|
222
|
+
{ status: 403, description: "Insufficient permissions", schema: errorSchema }
|
|
223
|
+
]
|
|
224
|
+
};
|
|
225
|
+
const postMethodDoc = {
|
|
226
|
+
summary: "Create customer user (admin)",
|
|
227
|
+
description: "Creates a new customer user directly. Staff-initiated, bypasses signup flow.",
|
|
228
|
+
tags: ["Customer Accounts Admin"],
|
|
229
|
+
requestBody: { schema: adminCreateUserSchema },
|
|
230
|
+
responses: [{ status: 201, description: "User created", schema: successSchema }],
|
|
231
|
+
errors: [
|
|
232
|
+
{ status: 400, description: "Validation failed", schema: errorSchema },
|
|
233
|
+
{ status: 401, description: "Not authenticated", schema: errorSchema },
|
|
234
|
+
{ status: 403, description: "Insufficient permissions", schema: errorSchema },
|
|
235
|
+
{ status: 409, description: "Email already exists", schema: errorSchema }
|
|
236
|
+
]
|
|
237
|
+
};
|
|
238
|
+
const openApi = {
|
|
239
|
+
summary: "Customer user management (admin)",
|
|
240
|
+
methods: {
|
|
241
|
+
GET: getMethodDoc,
|
|
242
|
+
POST: postMethodDoc
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
export {
|
|
246
|
+
GET,
|
|
247
|
+
POST,
|
|
248
|
+
metadata,
|
|
249
|
+
openApi
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=users.js.map
|