@open-mercato/core 0.8.1-develop.7254.1.ab24f26208 → 0.8.1-develop.7263.1.bbc6db3437

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 (46) hide show
  1. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +11 -3
  2. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  3. package/dist/modules/customer_accounts/api/admin/users.js +27 -14
  4. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  5. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +9 -0
  6. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
  7. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/PortalUserDetailPageClient.js +8 -8
  8. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/PortalUserDetailPageClient.js.map +2 -2
  9. package/dist/modules/customers/backend/customers/deals/map/page.js +10 -2
  10. package/dist/modules/customers/backend/customers/deals/map/page.js.map +2 -2
  11. package/dist/modules/customers/backend/customers/deals/page.js +10 -2
  12. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  13. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +41 -66
  14. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
  15. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +6 -2
  16. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  17. package/dist/modules/customers/components/formConfig.js +3 -3
  18. package/dist/modules/customers/components/formConfig.js.map +2 -2
  19. package/dist/modules/customers/data/validators.js +3 -1
  20. package/dist/modules/customers/data/validators.js.map +2 -2
  21. package/package.json +7 -7
  22. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +19 -5
  23. package/src/modules/catalog/i18n/de.json +1 -0
  24. package/src/modules/catalog/i18n/en.json +1 -0
  25. package/src/modules/catalog/i18n/es.json +1 -0
  26. package/src/modules/catalog/i18n/ko.json +1 -0
  27. package/src/modules/catalog/i18n/pl.json +1 -0
  28. package/src/modules/customer_accounts/api/admin/users.ts +30 -14
  29. package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +11 -0
  30. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/PortalUserDetailPageClient.tsx +11 -11
  31. package/src/modules/customer_accounts/i18n/de.json +1 -0
  32. package/src/modules/customer_accounts/i18n/en.json +1 -0
  33. package/src/modules/customer_accounts/i18n/es.json +1 -0
  34. package/src/modules/customer_accounts/i18n/ko.json +1 -0
  35. package/src/modules/customer_accounts/i18n/pl.json +1 -0
  36. package/src/modules/customers/backend/customers/deals/map/page.tsx +13 -2
  37. package/src/modules/customers/backend/customers/deals/page.tsx +13 -2
  38. package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +69 -56
  39. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +8 -2
  40. package/src/modules/customers/components/formConfig.tsx +3 -3
  41. package/src/modules/customers/data/validators.ts +2 -1
  42. package/src/modules/customers/i18n/de.json +1 -0
  43. package/src/modules/customers/i18n/en.json +1 -0
  44. package/src/modules/customers/i18n/es.json +1 -0
  45. package/src/modules/customers/i18n/ko.json +1 -0
  46. package/src/modules/customers/i18n/pl.json +1 -0
@@ -4,6 +4,7 @@ import { COORDINATE_RANGES } from "@open-mercato/shared/lib/location/coordinates
4
4
  import { dictionaryEntrySortModeSchema } from "@open-mercato/core/modules/dictionaries/lib/entrySort";
5
5
  const uuid = () => z.string().uuid();
6
6
  const CUSTOMER_PHONE_INVALID_MESSAGE_KEY = "customers.people.form.primaryPhone.invalid";
7
+ const CUSTOMER_URL_INVALID_MESSAGE_KEY = "customers.people.form.websiteUrl.invalid";
7
8
  const ACTIVITY_DATE_REQUIRED_MESSAGE_KEY = "customers.activities.errors.dateRequired";
8
9
  const ACTIVITY_TIME_REQUIRED_MESSAGE_KEY = "customers.activities.errors.timeRequired";
9
10
  const ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY = "customers.activities.errors.phoneRequired";
@@ -26,7 +27,7 @@ const clearableEmailSchema = z.preprocess(
26
27
  );
27
28
  const clearableUrlSchema = z.preprocess(
28
29
  emptyStringToNull,
29
- z.string().url().max(300).nullable().optional()
30
+ z.string().url(CUSTOMER_URL_INVALID_MESSAGE_KEY).max(300).nullable().optional()
30
31
  );
31
32
  const clearableDomainSchema = z.preprocess(
32
33
  emptyStringToNull,
@@ -561,6 +562,7 @@ export {
561
562
  ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY,
562
563
  ACTIVITY_TIME_REQUIRED_MESSAGE_KEY,
563
564
  CUSTOMER_PHONE_INVALID_MESSAGE_KEY,
565
+ CUSTOMER_URL_INVALID_MESSAGE_KEY,
564
566
  DEAL_DESCRIPTION_MAX_LENGTH,
565
567
  INTERACTION_PARTICIPANT_EMAIL_INVALID_MESSAGE_KEY,
566
568
  INTERACTION_PARTICIPANT_IDENTITY_REQUIRED_MESSAGE_KEY,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/customers/data/validators.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { isValidPhoneNumber } from '@open-mercato/shared/lib/phone'\nimport { COORDINATE_RANGES } from '@open-mercato/shared/lib/location/coordinates'\nimport { dictionaryEntrySortModeSchema } from '@open-mercato/core/modules/dictionaries/lib/entrySort'\n\nconst uuid = () => z.string().uuid()\n\nexport const CUSTOMER_PHONE_INVALID_MESSAGE_KEY = 'customers.people.form.primaryPhone.invalid'\nexport const ACTIVITY_DATE_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.dateRequired'\nexport const ACTIVITY_TIME_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.timeRequired'\nexport const ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.phoneRequired'\nexport const ACTIVITY_PHONE_INVALID_MESSAGE_KEY = 'customers.activities.errors.phoneInvalid'\nexport const INTERACTION_PARTICIPANT_IDENTITY_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.participantIdentityRequired'\nexport const INTERACTION_PARTICIPANT_EMAIL_INVALID_MESSAGE_KEY = 'customers.activities.errors.participantEmailInvalid'\n\n// customer_deals.description is an unbounded `text` column; this cap only exists to keep\n// request bodies, fulltext search documents and query-index documents from growing without limit.\nexport const DEAL_DESCRIPTION_MAX_LENGTH = 50_000\n\nconst emptyStringToNull = (value: unknown): unknown => {\n if (typeof value !== 'string') return value\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nconst phoneSchema = z.preprocess(\n emptyStringToNull,\n z\n .string()\n .trim()\n .max(50)\n .refine((val) => isValidPhoneNumber(val), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .nullable()\n .optional(),\n)\n\nconst clearableEmailSchema = z.preprocess(\n emptyStringToNull,\n z.string().email().max(320).nullable().optional(),\n)\n\nconst clearableUrlSchema = z.preprocess(\n emptyStringToNull,\n z.string().url().max(300).nullable().optional(),\n)\n\n// Domain is a plain (non-URL) string that maps to a nullable column, so blanking\n// a previously-set value on edit must transmit null to clear it. See #2529.\nconst clearableDomainSchema = z.preprocess(\n emptyStringToNull,\n z.string().trim().max(200).nullable().optional(),\n)\n\n// Plain optional string fields that map to nullable columns: blanking a previously-set\n// value on edit must transmit null to clear it, not be silently dropped. See #3050.\nconst clearableStringSchema = (max: number) =>\n z.preprocess(emptyStringToNull, z.string().trim().max(max).nullable().optional())\n\n// Annual revenue maps to a nullable numeric column. `''`/whitespace/null all clear it;\n// `.nullable()` short-circuits before coercion so null does not coerce to 0. See #3050.\nconst clearableRevenueSchema = z.preprocess(\n (value) => {\n if (typeof value === 'string' && value.trim().length === 0) return null\n return value\n },\n z.coerce.number().min(0).nullable().optional(),\n)\n\nconst interactionPhoneNumberSchema = z.string().trim().max(50).optional().nullable()\n\nconst scopedSchema = z.object({\n organizationId: uuid(),\n tenantId: uuid(),\n})\n\nconst nextInteractionSchema = z\n .object({\n at: z.coerce.date(),\n name: z.string().trim().min(1).max(200),\n refId: z.string().trim().max(191).optional().nullable(),\n icon: z.string().trim().max(100).optional().nullable(),\n color: z\n .string()\n .trim()\n .regex(/^#([0-9a-fA-F]{6})$/)\n .optional()\n .nullable(),\n })\n .strict()\n\nconst displayNameSchema = z.string().trim().min(1).max(200)\n\nconst baseEntitySchema = {\n displayName: displayNameSchema,\n // Nullable so a blanked description on edit clears the column instead of being dropped. See #3050.\n description: clearableStringSchema(4000),\n ownerUserId: uuid().optional(),\n primaryEmail: clearableEmailSchema,\n primaryPhone: phoneSchema,\n status: z.string().trim().max(100).optional(),\n lifecycleStage: z.string().trim().max(100).optional(),\n source: z.string().trim().max(150).optional(),\n temperature: z.string().trim().max(100).optional(),\n renewalQuarter: z.string().trim().max(100).optional(),\n isActive: z.boolean().optional(),\n nextInteraction: nextInteractionSchema.nullable().optional(),\n tags: z.array(uuid()).optional(),\n}\n\nconst personDetailsSchema = {\n preferredName: z.string().trim().max(120).optional(),\n jobTitle: z.string().trim().max(150).optional(),\n department: z.string().trim().max(150).optional(),\n seniority: z.string().trim().max(100).optional(),\n timezone: z.string().trim().max(120).optional(),\n linkedInUrl: clearableUrlSchema,\n twitterUrl: clearableUrlSchema,\n companyEntityId: uuid().nullable().optional(),\n}\n\nconst personFirstNameSchema = z.string().trim().min(1).max(120)\nconst personLastNameSchema = z.string().trim().min(1).max(120)\n\nconst companyDetailsSchema = {\n // Nullable so blanked values on edit clear the columns instead of being dropped. See #3050.\n legalName: clearableStringSchema(200),\n brandName: clearableStringSchema(200),\n domain: clearableDomainSchema,\n websiteUrl: clearableUrlSchema,\n industry: z.string().trim().max(150).optional(),\n sizeBucket: clearableStringSchema(100),\n annualRevenue: clearableRevenueSchema,\n}\n\nexport const personCreateSchema = scopedSchema.extend({\n ...baseEntitySchema,\n displayName: displayNameSchema.optional(),\n firstName: personFirstNameSchema,\n lastName: personLastNameSchema,\n ...personDetailsSchema,\n})\n\nexport const personUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(\n scopedSchema.extend({\n ...baseEntitySchema,\n ...personDetailsSchema,\n firstName: personFirstNameSchema.optional(),\n lastName: personLastNameSchema.optional(),\n }).partial()\n )\n\nexport const companyCreateSchema = scopedSchema.extend({\n ...baseEntitySchema,\n displayName: displayNameSchema,\n ...companyDetailsSchema,\n})\n\nexport const companyUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(companyCreateSchema.partial())\n\nexport const dealCreateSchema = scopedSchema.extend({\n title: z.string().min(1).max(200),\n description: z.string().max(DEAL_DESCRIPTION_MAX_LENGTH).optional(),\n status: z.string().max(50).optional(),\n pipelineStage: z.string().max(100).optional(),\n pipelineId: uuid().optional(),\n pipelineStageId: uuid().optional(),\n valueAmount: z.coerce.number().min(0).optional(),\n valueCurrency: z.string().min(3).max(3).optional(),\n probability: z.number().min(0).max(100).optional(),\n expectedCloseAt: z.coerce.date().optional(),\n // Nullable: the bulk owner-update worker passes `null` to clear ownership.\n // Without `.nullable()`, dealUpdateSchema.parse({ ownerUserId: null }) throws\n // ZodError \"expected string, received null\" inside the queue worker (TC-CRM-069).\n ownerUserId: uuid().optional().nullable(),\n source: z.string().max(150).optional(),\n closureOutcome: z.enum(['won', 'lost']).optional(),\n lossReasonId: uuid().optional(),\n lossNotes: z.string().max(4000).optional(),\n companyIds: z.array(uuid()).optional(),\n personIds: z.array(uuid()).optional(),\n primaryPersonEntityId: uuid().nullable().optional(),\n})\n\nexport const dealUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(dealCreateSchema.partial())\n\n// Bulk update schemas \u2014 used by `api/deals/bulk-update-{owner,stage}/route.ts`. Kept here\n// so all deal-write contracts live next to `dealCreateSchema` / `dealUpdateSchema`.\nexport const dealsBulkUpdateOwnerSchema = z.object({\n ids: z.array(uuid()).min(1).max(10000),\n ownerUserId: uuid().nullable(),\n})\n\nexport const dealsBulkUpdateStageSchema = z.object({\n ids: z.array(uuid()).min(1).max(10000),\n pipelineStageId: uuid(),\n})\n\nexport const dealsBulkUpdateResponseSchema = z.object({\n ok: z.boolean(),\n progressJobId: uuid().nullable(),\n message: z.string(),\n})\n\nexport const activityCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n activityType: z.string().min(1).max(100),\n subject: z.string().max(200).optional(),\n body: z.string().max(8000).optional(),\n date: z.string().trim().min(1, ACTIVITY_DATE_REQUIRED_MESSAGE_KEY).optional(),\n time: z.string().trim().min(1, ACTIVITY_TIME_REQUIRED_MESSAGE_KEY).optional(),\n phoneNumber: interactionPhoneNumberSchema,\n occurredAt: z.coerce.date().optional(),\n dealId: uuid().optional(),\n authorUserId: uuid().optional(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z\n .string()\n .trim()\n .regex(/^#([0-9a-fA-F]{6})$/)\n .optional()\n .nullable(),\n})\n\nexport const activityUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(activityCreateSchema.partial())\n\nexport const commentCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n dealId: uuid().optional(),\n body: z.string().min(1).max(8000),\n authorUserId: uuid().optional(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z\n .string()\n .trim()\n .regex(/^#([0-9a-fA-F]{6})$/)\n .optional()\n .nullable(),\n})\n\nexport const commentUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(commentCreateSchema.partial())\n\nexport const addressCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n name: z.string().max(150).optional(),\n purpose: z.string().max(150).optional(),\n companyName: z.string().max(200).optional(),\n addressLine1: z.string().min(1).max(300),\n addressLine2: z.string().max(300).optional(),\n buildingNumber: z.string().max(50).optional(),\n flatNumber: z.string().max(50).optional(),\n city: z.string().max(150).optional(),\n region: z.string().max(150).optional(),\n postalCode: z.string().max(30).optional(),\n country: z.string().max(150).optional(),\n latitude: z.coerce\n .number()\n .min(COORDINATE_RANGES.latitude.min)\n .max(COORDINATE_RANGES.latitude.max)\n .nullable()\n .optional(),\n longitude: z.coerce\n .number()\n .min(COORDINATE_RANGES.longitude.min)\n .max(COORDINATE_RANGES.longitude.max)\n .nullable()\n .optional(),\n isPrimary: z.boolean().optional(),\n})\n\nexport const addressUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(addressCreateSchema.partial())\n\nexport const tagCreateSchema = scopedSchema.extend({\n slug: z\n .string()\n .min(1)\n .max(80)\n .regex(/^[a-z0-9_-]+$/, 'Slug must be lowercase and may contain dashes or underscores'),\n label: z.string().min(1).max(120),\n color: z.string().max(30).optional(),\n description: z.string().max(400).optional(),\n})\n\nexport const tagUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(tagCreateSchema.partial())\n\nconst KNOWN_DICTIONARY_KINDS = [\n 'status',\n 'source',\n 'lifecycle_stage',\n 'address_type',\n 'activity_type',\n 'deal_status',\n 'pipeline_stage',\n 'job_title',\n 'industry',\n 'temperature',\n 'renewal_quarter',\n 'person_company_role',\n] as const\nconst CUSTOM_DICTIONARY_KIND_PATTERN = /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/\nconst dictionaryKindEnum = z.string().trim().refine(\n (value) =>\n (KNOWN_DICTIONARY_KINDS as readonly string[]).includes(value) ||\n CUSTOM_DICTIONARY_KIND_PATTERN.test(value),\n { message: 'Unsupported dictionary kind' },\n)\n\nconst dictionaryValueSchema = z.string().trim().min(1).max(150)\nconst dictionaryLabelSchema = z.string().trim().max(150)\n// Pipeline-stage rows migrated to semantic tone identifiers in\n// Migration20260519120000_pipeline_stage_color_tones; AddStageDialog now writes those\n// directly. Other dictionary kinds still store hex. Accept either format so round-tripping\n// a migrated pipeline-stage entry through the dictionary edit UI doesn't fail validation.\nconst DICTIONARY_COLOR_TONES = ['success', 'warning', 'info', 'error', 'neutral', 'brand', 'pink'] as const\nconst dictionaryColorSchema = z\n .string()\n .trim()\n .regex(\n new RegExp(`^(#[0-9a-fA-F]{6}|${DICTIONARY_COLOR_TONES.join('|')})$`),\n 'Color must be a six-digit hex code (e.g. #3366ff) or a semantic tone identifier',\n )\nconst dictionaryIconSchema = z.string().trim().max(48)\n\nexport const customerDictionaryEntryCreateSchema = scopedSchema.extend({\n kind: dictionaryKindEnum,\n value: dictionaryValueSchema,\n label: dictionaryLabelSchema.optional(),\n color: dictionaryColorSchema.nullable().optional(),\n icon: dictionaryIconSchema.nullable().optional(),\n})\n\nexport type CustomerDictionaryEntryCreateInput = z.infer<typeof customerDictionaryEntryCreateSchema>\n\nexport const customerDictionaryEntryUpdateSchema = scopedSchema\n .extend({\n id: uuid(),\n kind: dictionaryKindEnum,\n value: dictionaryValueSchema.optional(),\n label: dictionaryLabelSchema.optional(),\n color: dictionaryColorSchema.nullable().optional(),\n icon: dictionaryIconSchema.nullable().optional(),\n })\n .refine(\n (payload) =>\n payload.value !== undefined ||\n payload.label !== undefined ||\n payload.color !== undefined ||\n payload.icon !== undefined,\n {\n message: 'Provide at least one field to update.',\n path: ['value'],\n }\n )\n\nexport type CustomerDictionaryEntryUpdateInput = z.infer<typeof customerDictionaryEntryUpdateSchema>\n\nexport const customerDictionaryEntryDeleteSchema = scopedSchema.extend({\n id: uuid(),\n kind: dictionaryKindEnum,\n})\n\nexport type CustomerDictionaryEntryDeleteInput = z.infer<typeof customerDictionaryEntryDeleteSchema>\n\nexport const tagAssignmentSchema = scopedSchema.extend({\n tagId: uuid(),\n entityId: uuid(),\n})\n\nexport const todoLinkCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n todoId: uuid(),\n todoSource: z.string().min(1).max(120).default('customers:interaction'),\n createdByUserId: uuid().optional(),\n})\n\nexport const todoLinkWithTodoCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n title: z.string().min(1).max(200),\n isDone: z.boolean().optional(),\n is_done: z.boolean().optional(),\n todoSource: z.string().min(1).max(120).default('customers:interaction'),\n createdByUserId: uuid().optional(),\n todoCustom: z.record(z.string(), z.any()).optional(),\n custom: z.record(z.string(), z.any()).optional(),\n})\n\n// --- Interaction schemas ---\n\n/**\n * @deprecated Interaction statuses are now dictionary-backed and tenant-configurable\n * (the `interaction-statuses` dictionary). This frozen 3-value list is kept only for\n * backward compatibility; it is no longer the validation source (the API accepts any\n * `z.string().max(50)`). For open/terminal semantics use `lib/interactionStatus.ts`\n * (`isOpenInteractionStatus` / `isTerminalInteractionStatus` / `INTERACTION_STATUS_*`);\n * for the seeded default set use `INTERACTION_STATUS_DEFAULTS` in `cli.ts`. Do not expand\n * this list \u2014 adding members would break exhaustive consumers.\n */\nexport const interactionStatusValues = ['planned', 'done', 'canceled'] as const\n/** @deprecated See {@link interactionStatusValues}. */\nexport type InteractionStatus = typeof interactionStatusValues[number]\n\n// A participant is either a real record (`userId`) or an external guest carrying\n// no id at all. A guest is only addressable through its email, so that email is\n// required and must actually be routable \u2014 an unparseable string would persist\n// and only fail later, at invitation or calendar-sync time. Participants that DO\n// have a userId keep an unvalidated auxiliary email, as before.\nconst interactionParticipantSchema = z\n .object({\n userId: z.string().uuid().optional(),\n name: z.string().trim().max(200).optional(),\n email: z.string().trim().max(320).optional(),\n status: z.string().trim().max(50).optional(),\n })\n .superRefine((participant, ctx) => {\n if (participant.userId) return\n if (!participant.email) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['email'],\n message: INTERACTION_PARTICIPANT_IDENTITY_REQUIRED_MESSAGE_KEY,\n })\n return\n }\n if (!z.string().email().safeParse(participant.email).success) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['email'],\n message: INTERACTION_PARTICIPANT_EMAIL_INVALID_MESSAGE_KEY,\n })\n }\n })\n\nconst interactionLinkedEntitySchema = z.object({\n id: z.string().uuid(),\n // 'resource' links calendar events to bookable resources (rooms, cars,\n // equipment) from the optional resources module (#3552).\n // 'person' links an interaction to a `customer_entities` row with kind='person',\n // a first-class CRM record like a company (#5934).\n type: z.enum(['company', 'deal', 'offer', 'resource', 'person']),\n label: z.string().trim().max(500),\n})\n\nconst interactionGuestPermissionsSchema = z\n .object({\n canInviteOthers: z.boolean().optional(),\n canModify: z.boolean().optional(),\n canSeeList: z.boolean().optional(),\n })\n .strict()\n\nconst interactionExtendedFields = {\n durationMinutes: z.number().int().min(0).optional().nullable(),\n location: z.string().trim().max(500).optional().nullable(),\n allDay: z.boolean().optional().nullable(),\n recurrenceRule: z.string().trim().max(500).optional().nullable(),\n recurrenceEnd: z.coerce.date().optional().nullable(),\n participants: z.array(interactionParticipantSchema).optional().nullable(),\n reminderMinutes: z.number().int().min(0).optional().nullable(),\n visibility: z.string().trim().max(50).optional().nullable(),\n linkedEntities: z.array(interactionLinkedEntitySchema).optional().nullable(),\n guestPermissions: interactionGuestPermissionsSchema.optional().nullable(),\n} as const\n\nconst interactionCreateBaseSchema = scopedSchema.extend({\n id: z.string().uuid().optional(),\n entityId: z.string().uuid(),\n interactionType: z.string().trim().min(1).max(100),\n title: z.string().trim().max(500).optional().nullable(),\n body: z.string().trim().max(10000).optional().nullable(),\n // Lenient like `deal_status` (status: z.string().max(50)). The `interaction-statuses`\n // dictionary drives the UI dropdown; the API accepts any string <=50 chars so existing\n // rows, external writers, and the dispatch-crm MCP keep working. Open/terminal semantics\n // live in lib/interactionStatus.ts, not in this validator.\n status: z.string().max(50).optional().default('planned'),\n date: z.string().trim().min(1, ACTIVITY_DATE_REQUIRED_MESSAGE_KEY).optional(),\n time: z.string().trim().min(1, ACTIVITY_TIME_REQUIRED_MESSAGE_KEY).optional(),\n phoneNumber: interactionPhoneNumberSchema,\n scheduledAt: z.coerce.date().optional().nullable(),\n occurredAt: z.coerce.date().optional().nullable(),\n priority: z.number().int().min(0).max(100).optional().nullable(),\n authorUserId: z.string().uuid().optional().nullable(),\n ownerUserId: z.string().uuid().optional().nullable(),\n dealId: z.string().uuid().optional().nullable(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z.string().trim().regex(/^#([0-9a-fA-F]{6})$/).optional().nullable(),\n source: z.string().trim().max(100).optional().nullable(),\n ...interactionExtendedFields,\n})\n\nfunction deriveScheduledAtFromDateTime(date?: string, time?: string): Date | null {\n if (!date || typeof date !== 'string') return null\n const trimmedDate = date.trim()\n if (!trimmedDate) return null\n const trimmedTime = typeof time === 'string' ? time.trim() : ''\n const iso = trimmedTime ? `${trimmedDate}T${trimmedTime}:00` : `${trimmedDate}T00:00:00`\n const parsed = new Date(iso)\n return Number.isNaN(parsed.getTime()) ? null : parsed\n}\n\nexport const interactionCreateSchema = interactionCreateBaseSchema\n .superRefine((value, ctx) => {\n if (value.interactionType === 'call' && value.phoneNumber !== undefined && value.phoneNumber !== null) {\n const phone = typeof value.phoneNumber === 'string' ? value.phoneNumber.trim() : ''\n if (!phone) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY,\n })\n } else if (!isValidPhoneNumber(phone)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_INVALID_MESSAGE_KEY,\n })\n }\n }\n })\n // Derive `scheduledAt` from `date+time` when only the latter are sent so\n // external API consumers don't silently persist `scheduled_at: null` after\n // the validator already enforced non-empty date/time. The form already\n // computes `scheduledAt` itself, so this branch is a no-op for the form path.\n .transform((value) => {\n if (value.scheduledAt) return value\n const derived = deriveScheduledAtFromDateTime(value.date, value.time)\n return derived ? { ...value, scheduledAt: derived } : value\n })\n\nexport type InteractionCreateInput = z.infer<typeof interactionCreateSchema>\n\nconst interactionUpdateBaseSchema = z\n .object({\n id: z.string().uuid(),\n })\n .merge(\n scopedSchema\n .extend({\n interactionType: z.string().trim().min(1).max(100).optional(),\n title: z.string().trim().max(500).optional().nullable(),\n body: z.string().trim().max(10000).optional().nullable(),\n status: z.string().max(50).optional(),\n date: z.string().trim().min(1, ACTIVITY_DATE_REQUIRED_MESSAGE_KEY).optional(),\n time: z.string().trim().min(1, ACTIVITY_TIME_REQUIRED_MESSAGE_KEY).optional(),\n phoneNumber: interactionPhoneNumberSchema,\n scheduledAt: z.coerce.date().optional().nullable(),\n occurredAt: z.coerce.date().optional().nullable(),\n priority: z.number().int().min(0).max(100).optional().nullable(),\n authorUserId: z.string().uuid().optional().nullable(),\n ownerUserId: z.string().uuid().optional().nullable(),\n dealId: z.string().uuid().optional().nullable(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z.string().trim().regex(/^#([0-9a-fA-F]{6})$/).optional().nullable(),\n pinned: z.boolean().optional(),\n ...interactionExtendedFields,\n })\n .partial(),\n )\n\nexport const interactionUpdateSchema = interactionUpdateBaseSchema\n .superRefine((value, ctx) => {\n if (value.interactionType === 'call' && value.phoneNumber !== undefined) {\n const phone = typeof value.phoneNumber === 'string' ? value.phoneNumber.trim() : ''\n if (!phone) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY,\n })\n } else if (!isValidPhoneNumber(phone)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_INVALID_MESSAGE_KEY,\n })\n }\n }\n })\n // Mirror the create-schema derivation for partial updates: when an external\n // caller supplies `date+time` without `scheduledAt`, derive the timestamp so\n // the update doesn't silently leave `scheduled_at` stale.\n .transform((value) => {\n if (value.scheduledAt !== undefined) return value\n if (!value.date && !value.time) return value\n const derived = deriveScheduledAtFromDateTime(value.date, value.time)\n return derived ? { ...value, scheduledAt: derived } : value\n })\n\nexport type InteractionUpdateInput = z.infer<typeof interactionUpdateSchema>\n\nexport const interactionCompleteSchema = z.object({\n id: z.string().uuid(),\n occurredAt: z.coerce.date().optional(),\n})\n\nexport const interactionCancelSchema = z.object({\n id: z.string().uuid(),\n})\n\nexport const customerAddressFormatSchema = z.enum(['line_first', 'street_first'])\n\nexport const customerSettingsUpsertSchema = scopedSchema.extend({\n addressFormat: customerAddressFormatSchema,\n})\n\nexport const customerStuckThresholdUpsertSchema = scopedSchema.extend({\n stuckThresholdDays: z.number().int().min(1).max(365),\n})\n\nexport const customerDictionarySortModesSchema = z.record(z.string(), dictionaryEntrySortModeSchema)\n\nexport const customerDictionarySortModesUpsertSchema = scopedSchema.extend({\n dictionarySortModes: customerDictionarySortModesSchema,\n})\n\nexport type PersonCreateInput = z.infer<typeof personCreateSchema>\nexport type PersonUpdateInput = z.infer<typeof personUpdateSchema>\nexport type CompanyCreateInput = z.infer<typeof companyCreateSchema>\nexport type CompanyUpdateInput = z.infer<typeof companyUpdateSchema>\nexport type DealCreateInput = z.infer<typeof dealCreateSchema>\nexport type DealUpdateInput = z.infer<typeof dealUpdateSchema>\nexport type ActivityCreateInput = z.infer<typeof activityCreateSchema>\nexport type ActivityUpdateInput = z.infer<typeof activityUpdateSchema>\nexport type CommentCreateInput = z.infer<typeof commentCreateSchema>\nexport type CommentUpdateInput = z.infer<typeof commentUpdateSchema>\nexport type AddressCreateInput = z.infer<typeof addressCreateSchema>\nexport type AddressUpdateInput = z.infer<typeof addressUpdateSchema>\nexport type TagCreateInput = z.infer<typeof tagCreateSchema>\nexport type TagUpdateInput = z.infer<typeof tagUpdateSchema>\nexport type TagAssignmentInput = z.infer<typeof tagAssignmentSchema>\nexport type TodoLinkCreateInput = z.infer<typeof todoLinkCreateSchema>\nexport type TodoLinkWithTodoCreateInput = z.infer<typeof todoLinkWithTodoCreateSchema>\nexport type CustomerSettingsUpsertInput = z.infer<typeof customerSettingsUpsertSchema>\nexport type CustomerStuckThresholdUpsertInput = z.infer<typeof customerStuckThresholdUpsertSchema>\nexport type CustomerDictionarySortModesUpsertInput = z.infer<typeof customerDictionarySortModesUpsertSchema>\nexport type CustomerAddressFormatInput = z.infer<typeof customerAddressFormatSchema>\nexport type InteractionCompleteInput = z.infer<typeof interactionCompleteSchema>\nexport type InteractionCancelInput = z.infer<typeof interactionCancelSchema>\n\n// --- Pipeline schemas ---\n\nexport const pipelineCreateSchema = scopedSchema.extend({\n name: z.string().trim().min(1).max(200),\n isDefault: z.boolean().optional(),\n})\n\nexport const pipelineUpdateSchema = z.object({\n id: uuid(),\n name: z.string().trim().min(1).max(200).optional(),\n isDefault: z.boolean().optional(),\n})\n\nexport const pipelineDeleteSchema = z.object({\n id: uuid(),\n})\n\nexport type PipelineCreateInput = z.infer<typeof pipelineCreateSchema>\nexport type PipelineUpdateInput = z.infer<typeof pipelineUpdateSchema>\nexport type PipelineDeleteInput = z.infer<typeof pipelineDeleteSchema>\n\n// --- Pipeline Stage schemas ---\n\nexport const pipelineStageCreateSchema = scopedSchema.extend({\n pipelineId: uuid(),\n label: z.string().trim().min(1).max(200),\n order: z.number().int().min(0).optional(),\n color: z.string().trim().max(20).nullish(),\n icon: z.string().trim().max(100).nullish(),\n})\n\nexport const pipelineStageUpdateSchema = z.object({\n id: uuid(),\n label: z.string().trim().min(1).max(200).optional(),\n order: z.number().int().min(0).optional(),\n color: z.string().trim().max(20).nullish(),\n icon: z.string().trim().max(100).nullish(),\n})\n\nexport const pipelineStageDeleteSchema = z.object({\n id: uuid(),\n})\n\nexport const pipelineStageReorderSchema = scopedSchema.extend({\n stages: z.array(z.object({\n id: uuid(),\n order: z.number().int().min(0),\n })).min(1),\n})\n\nexport type PipelineStageCreateInput = z.infer<typeof pipelineStageCreateSchema>\nexport type PipelineStageUpdateInput = z.infer<typeof pipelineStageUpdateSchema>\nexport type PipelineStageDeleteInput = z.infer<typeof pipelineStageDeleteSchema>\nexport type PipelineStageReorderInput = z.infer<typeof pipelineStageReorderSchema>\n\nexport const entityRoleCreateSchema = scopedSchema.extend({\n entityType: z.enum(['company', 'person']),\n entityId: uuid(),\n roleType: z.string().trim().min(1).max(100),\n userId: uuid(),\n})\n\nexport const entityRoleUpdateSchema = scopedSchema.extend({\n id: uuid(),\n userId: uuid(),\n})\n\nexport const entityRoleDeleteSchema = scopedSchema.extend({\n id: uuid(),\n})\n\nexport type EntityRoleCreateInput = z.infer<typeof entityRoleCreateSchema>\nexport type EntityRoleUpdateInput = z.infer<typeof entityRoleUpdateSchema>\nexport type EntityRoleDeleteInput = z.infer<typeof entityRoleDeleteSchema>\n\nexport const updateKindSettingSchema = z.object({\n kind: z.string().trim().min(1).max(100),\n selectionMode: z.enum(['single', 'multi']).optional(),\n visibleInTags: z.boolean().optional(),\n sortOrder: z.number().int().min(0).optional(),\n})\n\nexport type UpdateKindSettingInput = z.infer<typeof updateKindSettingSchema>\n\nexport const customerKindSettingsUpsertSchema = scopedSchema.extend({\n kind: z.string().trim().min(1).max(100),\n selectionMode: z.enum(['single', 'multi']).optional(),\n visibleInTags: z.boolean().optional(),\n sortOrder: z.number().int().min(0).optional(),\n})\n\nexport type CustomerKindSettingsUpsertInput = z.infer<typeof customerKindSettingsUpsertSchema>\n\nexport const labelCreateSchema = z.object({\n label: z.string().trim().min(1).max(120),\n slug: z.string().trim().min(1).max(80).regex(/^[a-z0-9_-]+$/).optional(),\n})\n\nexport type LabelCreateInput = z.infer<typeof labelCreateSchema>\n\nexport const labelCreateCommandSchema = scopedSchema.extend({\n label: z.string().trim().min(1).max(120),\n slug: z.string().trim().min(1).max(80).regex(/^[a-z0-9_-]+$/),\n userId: uuid(),\n})\n\nexport type LabelCreateCommandInput = z.infer<typeof labelCreateCommandSchema>\n\nexport const labelAssignmentSchema = z.object({\n labelId: z.string().uuid(),\n entityId: z.string().uuid(),\n})\n\nexport type LabelAssignmentInput = z.infer<typeof labelAssignmentSchema>\n\nexport const labelAssignCommandSchema = scopedSchema.extend({\n labelId: uuid(),\n entityId: uuid(),\n})\n\nexport const labelUnassignCommandSchema = scopedSchema.extend({\n labelId: uuid(),\n entityId: uuid(),\n})\n\nexport type LabelAssignCommandInput = z.infer<typeof labelAssignCommandSchema>\nexport type LabelUnassignCommandInput = z.infer<typeof labelUnassignCommandSchema>\n\nexport const personCompanyLinkCreateSchema = scopedSchema.extend({\n personEntityId: uuid(),\n companyEntityId: uuid(),\n isPrimary: z.boolean().optional(),\n})\n\nexport const personCompanyLinkUpdateSchema = scopedSchema.extend({\n linkId: uuid(),\n isPrimary: z.boolean(),\n})\n\n// Two shapes are accepted, because a person can belong to a company in two ways:\n// through a `customer_person_company_links` row (`linkId`), or through a legacy\n// profile-only assignment where `customer_person_profiles.company_id` is set and no\n// link row was ever created (migrated CRM data, #5114). Both detaches go through the\n// same command so audit, undo and cache invalidation stay consistent.\nexport const personCompanyLinkDeleteSchema = scopedSchema\n .extend({\n linkId: uuid().optional(),\n personEntityId: uuid().optional(),\n companyEntityId: uuid().optional(),\n })\n .refine(\n (payload) => Boolean(payload.linkId) || Boolean(payload.personEntityId && payload.companyEntityId),\n {\n message: 'Provide either linkId or both personEntityId and companyEntityId.',\n path: ['linkId'],\n }\n )\n\nexport type PersonCompanyLinkCreateInput = z.infer<typeof personCompanyLinkCreateSchema>\nexport type PersonCompanyLinkUpdateInput = z.infer<typeof personCompanyLinkUpdateSchema>\nexport type PersonCompanyLinkDeleteInput = z.infer<typeof personCompanyLinkDeleteSchema>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { isValidPhoneNumber } from '@open-mercato/shared/lib/phone'\nimport { COORDINATE_RANGES } from '@open-mercato/shared/lib/location/coordinates'\nimport { dictionaryEntrySortModeSchema } from '@open-mercato/core/modules/dictionaries/lib/entrySort'\n\nconst uuid = () => z.string().uuid()\n\nexport const CUSTOMER_PHONE_INVALID_MESSAGE_KEY = 'customers.people.form.primaryPhone.invalid'\nexport const CUSTOMER_URL_INVALID_MESSAGE_KEY = 'customers.people.form.websiteUrl.invalid'\nexport const ACTIVITY_DATE_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.dateRequired'\nexport const ACTIVITY_TIME_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.timeRequired'\nexport const ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.phoneRequired'\nexport const ACTIVITY_PHONE_INVALID_MESSAGE_KEY = 'customers.activities.errors.phoneInvalid'\nexport const INTERACTION_PARTICIPANT_IDENTITY_REQUIRED_MESSAGE_KEY = 'customers.activities.errors.participantIdentityRequired'\nexport const INTERACTION_PARTICIPANT_EMAIL_INVALID_MESSAGE_KEY = 'customers.activities.errors.participantEmailInvalid'\n\n// customer_deals.description is an unbounded `text` column; this cap only exists to keep\n// request bodies, fulltext search documents and query-index documents from growing without limit.\nexport const DEAL_DESCRIPTION_MAX_LENGTH = 50_000\n\nconst emptyStringToNull = (value: unknown): unknown => {\n if (typeof value !== 'string') return value\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nconst phoneSchema = z.preprocess(\n emptyStringToNull,\n z\n .string()\n .trim()\n .max(50)\n .refine((val) => isValidPhoneNumber(val), { message: CUSTOMER_PHONE_INVALID_MESSAGE_KEY })\n .nullable()\n .optional(),\n)\n\nconst clearableEmailSchema = z.preprocess(\n emptyStringToNull,\n z.string().email().max(320).nullable().optional(),\n)\n\nconst clearableUrlSchema = z.preprocess(\n emptyStringToNull,\n z.string().url(CUSTOMER_URL_INVALID_MESSAGE_KEY).max(300).nullable().optional(),\n)\n\n// Domain is a plain (non-URL) string that maps to a nullable column, so blanking\n// a previously-set value on edit must transmit null to clear it. See #2529.\nconst clearableDomainSchema = z.preprocess(\n emptyStringToNull,\n z.string().trim().max(200).nullable().optional(),\n)\n\n// Plain optional string fields that map to nullable columns: blanking a previously-set\n// value on edit must transmit null to clear it, not be silently dropped. See #3050.\nconst clearableStringSchema = (max: number) =>\n z.preprocess(emptyStringToNull, z.string().trim().max(max).nullable().optional())\n\n// Annual revenue maps to a nullable numeric column. `''`/whitespace/null all clear it;\n// `.nullable()` short-circuits before coercion so null does not coerce to 0. See #3050.\nconst clearableRevenueSchema = z.preprocess(\n (value) => {\n if (typeof value === 'string' && value.trim().length === 0) return null\n return value\n },\n z.coerce.number().min(0).nullable().optional(),\n)\n\nconst interactionPhoneNumberSchema = z.string().trim().max(50).optional().nullable()\n\nconst scopedSchema = z.object({\n organizationId: uuid(),\n tenantId: uuid(),\n})\n\nconst nextInteractionSchema = z\n .object({\n at: z.coerce.date(),\n name: z.string().trim().min(1).max(200),\n refId: z.string().trim().max(191).optional().nullable(),\n icon: z.string().trim().max(100).optional().nullable(),\n color: z\n .string()\n .trim()\n .regex(/^#([0-9a-fA-F]{6})$/)\n .optional()\n .nullable(),\n })\n .strict()\n\nconst displayNameSchema = z.string().trim().min(1).max(200)\n\nconst baseEntitySchema = {\n displayName: displayNameSchema,\n // Nullable so a blanked description on edit clears the column instead of being dropped. See #3050.\n description: clearableStringSchema(4000),\n ownerUserId: uuid().optional(),\n primaryEmail: clearableEmailSchema,\n primaryPhone: phoneSchema,\n status: z.string().trim().max(100).optional(),\n lifecycleStage: z.string().trim().max(100).optional(),\n source: z.string().trim().max(150).optional(),\n temperature: z.string().trim().max(100).optional(),\n renewalQuarter: z.string().trim().max(100).optional(),\n isActive: z.boolean().optional(),\n nextInteraction: nextInteractionSchema.nullable().optional(),\n tags: z.array(uuid()).optional(),\n}\n\nconst personDetailsSchema = {\n preferredName: z.string().trim().max(120).optional(),\n jobTitle: z.string().trim().max(150).optional(),\n department: z.string().trim().max(150).optional(),\n seniority: z.string().trim().max(100).optional(),\n timezone: z.string().trim().max(120).optional(),\n linkedInUrl: clearableUrlSchema,\n twitterUrl: clearableUrlSchema,\n companyEntityId: uuid().nullable().optional(),\n}\n\nconst personFirstNameSchema = z.string().trim().min(1).max(120)\nconst personLastNameSchema = z.string().trim().min(1).max(120)\n\nconst companyDetailsSchema = {\n // Nullable so blanked values on edit clear the columns instead of being dropped. See #3050.\n legalName: clearableStringSchema(200),\n brandName: clearableStringSchema(200),\n domain: clearableDomainSchema,\n websiteUrl: clearableUrlSchema,\n industry: z.string().trim().max(150).optional(),\n sizeBucket: clearableStringSchema(100),\n annualRevenue: clearableRevenueSchema,\n}\n\nexport const personCreateSchema = scopedSchema.extend({\n ...baseEntitySchema,\n displayName: displayNameSchema.optional(),\n firstName: personFirstNameSchema,\n lastName: personLastNameSchema,\n ...personDetailsSchema,\n})\n\nexport const personUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(\n scopedSchema.extend({\n ...baseEntitySchema,\n ...personDetailsSchema,\n firstName: personFirstNameSchema.optional(),\n lastName: personLastNameSchema.optional(),\n }).partial()\n )\n\nexport const companyCreateSchema = scopedSchema.extend({\n ...baseEntitySchema,\n displayName: displayNameSchema,\n ...companyDetailsSchema,\n})\n\nexport const companyUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(companyCreateSchema.partial())\n\nexport const dealCreateSchema = scopedSchema.extend({\n title: z.string().min(1).max(200),\n description: z.string().max(DEAL_DESCRIPTION_MAX_LENGTH).optional(),\n status: z.string().max(50).optional(),\n pipelineStage: z.string().max(100).optional(),\n pipelineId: uuid().optional(),\n pipelineStageId: uuid().optional(),\n valueAmount: z.coerce.number().min(0).optional(),\n valueCurrency: z.string().min(3).max(3).optional(),\n probability: z.number().min(0).max(100).optional(),\n expectedCloseAt: z.coerce.date().optional(),\n // Nullable: the bulk owner-update worker passes `null` to clear ownership.\n // Without `.nullable()`, dealUpdateSchema.parse({ ownerUserId: null }) throws\n // ZodError \"expected string, received null\" inside the queue worker (TC-CRM-069).\n ownerUserId: uuid().optional().nullable(),\n source: z.string().max(150).optional(),\n closureOutcome: z.enum(['won', 'lost']).optional(),\n lossReasonId: uuid().optional(),\n lossNotes: z.string().max(4000).optional(),\n companyIds: z.array(uuid()).optional(),\n personIds: z.array(uuid()).optional(),\n primaryPersonEntityId: uuid().nullable().optional(),\n})\n\nexport const dealUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(dealCreateSchema.partial())\n\n// Bulk update schemas \u2014 used by `api/deals/bulk-update-{owner,stage}/route.ts`. Kept here\n// so all deal-write contracts live next to `dealCreateSchema` / `dealUpdateSchema`.\nexport const dealsBulkUpdateOwnerSchema = z.object({\n ids: z.array(uuid()).min(1).max(10000),\n ownerUserId: uuid().nullable(),\n})\n\nexport const dealsBulkUpdateStageSchema = z.object({\n ids: z.array(uuid()).min(1).max(10000),\n pipelineStageId: uuid(),\n})\n\nexport const dealsBulkUpdateResponseSchema = z.object({\n ok: z.boolean(),\n progressJobId: uuid().nullable(),\n message: z.string(),\n})\n\nexport const activityCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n activityType: z.string().min(1).max(100),\n subject: z.string().max(200).optional(),\n body: z.string().max(8000).optional(),\n date: z.string().trim().min(1, ACTIVITY_DATE_REQUIRED_MESSAGE_KEY).optional(),\n time: z.string().trim().min(1, ACTIVITY_TIME_REQUIRED_MESSAGE_KEY).optional(),\n phoneNumber: interactionPhoneNumberSchema,\n occurredAt: z.coerce.date().optional(),\n dealId: uuid().optional(),\n authorUserId: uuid().optional(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z\n .string()\n .trim()\n .regex(/^#([0-9a-fA-F]{6})$/)\n .optional()\n .nullable(),\n})\n\nexport const activityUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(activityCreateSchema.partial())\n\nexport const commentCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n dealId: uuid().optional(),\n body: z.string().min(1).max(8000),\n authorUserId: uuid().optional(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z\n .string()\n .trim()\n .regex(/^#([0-9a-fA-F]{6})$/)\n .optional()\n .nullable(),\n})\n\nexport const commentUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(commentCreateSchema.partial())\n\nexport const addressCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n name: z.string().max(150).optional(),\n purpose: z.string().max(150).optional(),\n companyName: z.string().max(200).optional(),\n addressLine1: z.string().min(1).max(300),\n addressLine2: z.string().max(300).optional(),\n buildingNumber: z.string().max(50).optional(),\n flatNumber: z.string().max(50).optional(),\n city: z.string().max(150).optional(),\n region: z.string().max(150).optional(),\n postalCode: z.string().max(30).optional(),\n country: z.string().max(150).optional(),\n latitude: z.coerce\n .number()\n .min(COORDINATE_RANGES.latitude.min)\n .max(COORDINATE_RANGES.latitude.max)\n .nullable()\n .optional(),\n longitude: z.coerce\n .number()\n .min(COORDINATE_RANGES.longitude.min)\n .max(COORDINATE_RANGES.longitude.max)\n .nullable()\n .optional(),\n isPrimary: z.boolean().optional(),\n})\n\nexport const addressUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(addressCreateSchema.partial())\n\nexport const tagCreateSchema = scopedSchema.extend({\n slug: z\n .string()\n .min(1)\n .max(80)\n .regex(/^[a-z0-9_-]+$/, 'Slug must be lowercase and may contain dashes or underscores'),\n label: z.string().min(1).max(120),\n color: z.string().max(30).optional(),\n description: z.string().max(400).optional(),\n})\n\nexport const tagUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(tagCreateSchema.partial())\n\nconst KNOWN_DICTIONARY_KINDS = [\n 'status',\n 'source',\n 'lifecycle_stage',\n 'address_type',\n 'activity_type',\n 'deal_status',\n 'pipeline_stage',\n 'job_title',\n 'industry',\n 'temperature',\n 'renewal_quarter',\n 'person_company_role',\n] as const\nconst CUSTOM_DICTIONARY_KIND_PATTERN = /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/\nconst dictionaryKindEnum = z.string().trim().refine(\n (value) =>\n (KNOWN_DICTIONARY_KINDS as readonly string[]).includes(value) ||\n CUSTOM_DICTIONARY_KIND_PATTERN.test(value),\n { message: 'Unsupported dictionary kind' },\n)\n\nconst dictionaryValueSchema = z.string().trim().min(1).max(150)\nconst dictionaryLabelSchema = z.string().trim().max(150)\n// Pipeline-stage rows migrated to semantic tone identifiers in\n// Migration20260519120000_pipeline_stage_color_tones; AddStageDialog now writes those\n// directly. Other dictionary kinds still store hex. Accept either format so round-tripping\n// a migrated pipeline-stage entry through the dictionary edit UI doesn't fail validation.\nconst DICTIONARY_COLOR_TONES = ['success', 'warning', 'info', 'error', 'neutral', 'brand', 'pink'] as const\nconst dictionaryColorSchema = z\n .string()\n .trim()\n .regex(\n new RegExp(`^(#[0-9a-fA-F]{6}|${DICTIONARY_COLOR_TONES.join('|')})$`),\n 'Color must be a six-digit hex code (e.g. #3366ff) or a semantic tone identifier',\n )\nconst dictionaryIconSchema = z.string().trim().max(48)\n\nexport const customerDictionaryEntryCreateSchema = scopedSchema.extend({\n kind: dictionaryKindEnum,\n value: dictionaryValueSchema,\n label: dictionaryLabelSchema.optional(),\n color: dictionaryColorSchema.nullable().optional(),\n icon: dictionaryIconSchema.nullable().optional(),\n})\n\nexport type CustomerDictionaryEntryCreateInput = z.infer<typeof customerDictionaryEntryCreateSchema>\n\nexport const customerDictionaryEntryUpdateSchema = scopedSchema\n .extend({\n id: uuid(),\n kind: dictionaryKindEnum,\n value: dictionaryValueSchema.optional(),\n label: dictionaryLabelSchema.optional(),\n color: dictionaryColorSchema.nullable().optional(),\n icon: dictionaryIconSchema.nullable().optional(),\n })\n .refine(\n (payload) =>\n payload.value !== undefined ||\n payload.label !== undefined ||\n payload.color !== undefined ||\n payload.icon !== undefined,\n {\n message: 'Provide at least one field to update.',\n path: ['value'],\n }\n )\n\nexport type CustomerDictionaryEntryUpdateInput = z.infer<typeof customerDictionaryEntryUpdateSchema>\n\nexport const customerDictionaryEntryDeleteSchema = scopedSchema.extend({\n id: uuid(),\n kind: dictionaryKindEnum,\n})\n\nexport type CustomerDictionaryEntryDeleteInput = z.infer<typeof customerDictionaryEntryDeleteSchema>\n\nexport const tagAssignmentSchema = scopedSchema.extend({\n tagId: uuid(),\n entityId: uuid(),\n})\n\nexport const todoLinkCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n todoId: uuid(),\n todoSource: z.string().min(1).max(120).default('customers:interaction'),\n createdByUserId: uuid().optional(),\n})\n\nexport const todoLinkWithTodoCreateSchema = scopedSchema.extend({\n entityId: uuid(),\n title: z.string().min(1).max(200),\n isDone: z.boolean().optional(),\n is_done: z.boolean().optional(),\n todoSource: z.string().min(1).max(120).default('customers:interaction'),\n createdByUserId: uuid().optional(),\n todoCustom: z.record(z.string(), z.any()).optional(),\n custom: z.record(z.string(), z.any()).optional(),\n})\n\n// --- Interaction schemas ---\n\n/**\n * @deprecated Interaction statuses are now dictionary-backed and tenant-configurable\n * (the `interaction-statuses` dictionary). This frozen 3-value list is kept only for\n * backward compatibility; it is no longer the validation source (the API accepts any\n * `z.string().max(50)`). For open/terminal semantics use `lib/interactionStatus.ts`\n * (`isOpenInteractionStatus` / `isTerminalInteractionStatus` / `INTERACTION_STATUS_*`);\n * for the seeded default set use `INTERACTION_STATUS_DEFAULTS` in `cli.ts`. Do not expand\n * this list \u2014 adding members would break exhaustive consumers.\n */\nexport const interactionStatusValues = ['planned', 'done', 'canceled'] as const\n/** @deprecated See {@link interactionStatusValues}. */\nexport type InteractionStatus = typeof interactionStatusValues[number]\n\n// A participant is either a real record (`userId`) or an external guest carrying\n// no id at all. A guest is only addressable through its email, so that email is\n// required and must actually be routable \u2014 an unparseable string would persist\n// and only fail later, at invitation or calendar-sync time. Participants that DO\n// have a userId keep an unvalidated auxiliary email, as before.\nconst interactionParticipantSchema = z\n .object({\n userId: z.string().uuid().optional(),\n name: z.string().trim().max(200).optional(),\n email: z.string().trim().max(320).optional(),\n status: z.string().trim().max(50).optional(),\n })\n .superRefine((participant, ctx) => {\n if (participant.userId) return\n if (!participant.email) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['email'],\n message: INTERACTION_PARTICIPANT_IDENTITY_REQUIRED_MESSAGE_KEY,\n })\n return\n }\n if (!z.string().email().safeParse(participant.email).success) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['email'],\n message: INTERACTION_PARTICIPANT_EMAIL_INVALID_MESSAGE_KEY,\n })\n }\n })\n\nconst interactionLinkedEntitySchema = z.object({\n id: z.string().uuid(),\n // 'resource' links calendar events to bookable resources (rooms, cars,\n // equipment) from the optional resources module (#3552).\n // 'person' links an interaction to a `customer_entities` row with kind='person',\n // a first-class CRM record like a company (#5934).\n type: z.enum(['company', 'deal', 'offer', 'resource', 'person']),\n label: z.string().trim().max(500),\n})\n\nconst interactionGuestPermissionsSchema = z\n .object({\n canInviteOthers: z.boolean().optional(),\n canModify: z.boolean().optional(),\n canSeeList: z.boolean().optional(),\n })\n .strict()\n\nconst interactionExtendedFields = {\n durationMinutes: z.number().int().min(0).optional().nullable(),\n location: z.string().trim().max(500).optional().nullable(),\n allDay: z.boolean().optional().nullable(),\n recurrenceRule: z.string().trim().max(500).optional().nullable(),\n recurrenceEnd: z.coerce.date().optional().nullable(),\n participants: z.array(interactionParticipantSchema).optional().nullable(),\n reminderMinutes: z.number().int().min(0).optional().nullable(),\n visibility: z.string().trim().max(50).optional().nullable(),\n linkedEntities: z.array(interactionLinkedEntitySchema).optional().nullable(),\n guestPermissions: interactionGuestPermissionsSchema.optional().nullable(),\n} as const\n\nconst interactionCreateBaseSchema = scopedSchema.extend({\n id: z.string().uuid().optional(),\n entityId: z.string().uuid(),\n interactionType: z.string().trim().min(1).max(100),\n title: z.string().trim().max(500).optional().nullable(),\n body: z.string().trim().max(10000).optional().nullable(),\n // Lenient like `deal_status` (status: z.string().max(50)). The `interaction-statuses`\n // dictionary drives the UI dropdown; the API accepts any string <=50 chars so existing\n // rows, external writers, and the dispatch-crm MCP keep working. Open/terminal semantics\n // live in lib/interactionStatus.ts, not in this validator.\n status: z.string().max(50).optional().default('planned'),\n date: z.string().trim().min(1, ACTIVITY_DATE_REQUIRED_MESSAGE_KEY).optional(),\n time: z.string().trim().min(1, ACTIVITY_TIME_REQUIRED_MESSAGE_KEY).optional(),\n phoneNumber: interactionPhoneNumberSchema,\n scheduledAt: z.coerce.date().optional().nullable(),\n occurredAt: z.coerce.date().optional().nullable(),\n priority: z.number().int().min(0).max(100).optional().nullable(),\n authorUserId: z.string().uuid().optional().nullable(),\n ownerUserId: z.string().uuid().optional().nullable(),\n dealId: z.string().uuid().optional().nullable(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z.string().trim().regex(/^#([0-9a-fA-F]{6})$/).optional().nullable(),\n source: z.string().trim().max(100).optional().nullable(),\n ...interactionExtendedFields,\n})\n\nfunction deriveScheduledAtFromDateTime(date?: string, time?: string): Date | null {\n if (!date || typeof date !== 'string') return null\n const trimmedDate = date.trim()\n if (!trimmedDate) return null\n const trimmedTime = typeof time === 'string' ? time.trim() : ''\n const iso = trimmedTime ? `${trimmedDate}T${trimmedTime}:00` : `${trimmedDate}T00:00:00`\n const parsed = new Date(iso)\n return Number.isNaN(parsed.getTime()) ? null : parsed\n}\n\nexport const interactionCreateSchema = interactionCreateBaseSchema\n .superRefine((value, ctx) => {\n if (value.interactionType === 'call' && value.phoneNumber !== undefined && value.phoneNumber !== null) {\n const phone = typeof value.phoneNumber === 'string' ? value.phoneNumber.trim() : ''\n if (!phone) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY,\n })\n } else if (!isValidPhoneNumber(phone)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_INVALID_MESSAGE_KEY,\n })\n }\n }\n })\n // Derive `scheduledAt` from `date+time` when only the latter are sent so\n // external API consumers don't silently persist `scheduled_at: null` after\n // the validator already enforced non-empty date/time. The form already\n // computes `scheduledAt` itself, so this branch is a no-op for the form path.\n .transform((value) => {\n if (value.scheduledAt) return value\n const derived = deriveScheduledAtFromDateTime(value.date, value.time)\n return derived ? { ...value, scheduledAt: derived } : value\n })\n\nexport type InteractionCreateInput = z.infer<typeof interactionCreateSchema>\n\nconst interactionUpdateBaseSchema = z\n .object({\n id: z.string().uuid(),\n })\n .merge(\n scopedSchema\n .extend({\n interactionType: z.string().trim().min(1).max(100).optional(),\n title: z.string().trim().max(500).optional().nullable(),\n body: z.string().trim().max(10000).optional().nullable(),\n status: z.string().max(50).optional(),\n date: z.string().trim().min(1, ACTIVITY_DATE_REQUIRED_MESSAGE_KEY).optional(),\n time: z.string().trim().min(1, ACTIVITY_TIME_REQUIRED_MESSAGE_KEY).optional(),\n phoneNumber: interactionPhoneNumberSchema,\n scheduledAt: z.coerce.date().optional().nullable(),\n occurredAt: z.coerce.date().optional().nullable(),\n priority: z.number().int().min(0).max(100).optional().nullable(),\n authorUserId: z.string().uuid().optional().nullable(),\n ownerUserId: z.string().uuid().optional().nullable(),\n dealId: z.string().uuid().optional().nullable(),\n appearanceIcon: z.string().trim().max(100).optional().nullable(),\n appearanceColor: z.string().trim().regex(/^#([0-9a-fA-F]{6})$/).optional().nullable(),\n pinned: z.boolean().optional(),\n ...interactionExtendedFields,\n })\n .partial(),\n )\n\nexport const interactionUpdateSchema = interactionUpdateBaseSchema\n .superRefine((value, ctx) => {\n if (value.interactionType === 'call' && value.phoneNumber !== undefined) {\n const phone = typeof value.phoneNumber === 'string' ? value.phoneNumber.trim() : ''\n if (!phone) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_REQUIRED_MESSAGE_KEY,\n })\n } else if (!isValidPhoneNumber(phone)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['phoneNumber'],\n message: ACTIVITY_PHONE_INVALID_MESSAGE_KEY,\n })\n }\n }\n })\n // Mirror the create-schema derivation for partial updates: when an external\n // caller supplies `date+time` without `scheduledAt`, derive the timestamp so\n // the update doesn't silently leave `scheduled_at` stale.\n .transform((value) => {\n if (value.scheduledAt !== undefined) return value\n if (!value.date && !value.time) return value\n const derived = deriveScheduledAtFromDateTime(value.date, value.time)\n return derived ? { ...value, scheduledAt: derived } : value\n })\n\nexport type InteractionUpdateInput = z.infer<typeof interactionUpdateSchema>\n\nexport const interactionCompleteSchema = z.object({\n id: z.string().uuid(),\n occurredAt: z.coerce.date().optional(),\n})\n\nexport const interactionCancelSchema = z.object({\n id: z.string().uuid(),\n})\n\nexport const customerAddressFormatSchema = z.enum(['line_first', 'street_first'])\n\nexport const customerSettingsUpsertSchema = scopedSchema.extend({\n addressFormat: customerAddressFormatSchema,\n})\n\nexport const customerStuckThresholdUpsertSchema = scopedSchema.extend({\n stuckThresholdDays: z.number().int().min(1).max(365),\n})\n\nexport const customerDictionarySortModesSchema = z.record(z.string(), dictionaryEntrySortModeSchema)\n\nexport const customerDictionarySortModesUpsertSchema = scopedSchema.extend({\n dictionarySortModes: customerDictionarySortModesSchema,\n})\n\nexport type PersonCreateInput = z.infer<typeof personCreateSchema>\nexport type PersonUpdateInput = z.infer<typeof personUpdateSchema>\nexport type CompanyCreateInput = z.infer<typeof companyCreateSchema>\nexport type CompanyUpdateInput = z.infer<typeof companyUpdateSchema>\nexport type DealCreateInput = z.infer<typeof dealCreateSchema>\nexport type DealUpdateInput = z.infer<typeof dealUpdateSchema>\nexport type ActivityCreateInput = z.infer<typeof activityCreateSchema>\nexport type ActivityUpdateInput = z.infer<typeof activityUpdateSchema>\nexport type CommentCreateInput = z.infer<typeof commentCreateSchema>\nexport type CommentUpdateInput = z.infer<typeof commentUpdateSchema>\nexport type AddressCreateInput = z.infer<typeof addressCreateSchema>\nexport type AddressUpdateInput = z.infer<typeof addressUpdateSchema>\nexport type TagCreateInput = z.infer<typeof tagCreateSchema>\nexport type TagUpdateInput = z.infer<typeof tagUpdateSchema>\nexport type TagAssignmentInput = z.infer<typeof tagAssignmentSchema>\nexport type TodoLinkCreateInput = z.infer<typeof todoLinkCreateSchema>\nexport type TodoLinkWithTodoCreateInput = z.infer<typeof todoLinkWithTodoCreateSchema>\nexport type CustomerSettingsUpsertInput = z.infer<typeof customerSettingsUpsertSchema>\nexport type CustomerStuckThresholdUpsertInput = z.infer<typeof customerStuckThresholdUpsertSchema>\nexport type CustomerDictionarySortModesUpsertInput = z.infer<typeof customerDictionarySortModesUpsertSchema>\nexport type CustomerAddressFormatInput = z.infer<typeof customerAddressFormatSchema>\nexport type InteractionCompleteInput = z.infer<typeof interactionCompleteSchema>\nexport type InteractionCancelInput = z.infer<typeof interactionCancelSchema>\n\n// --- Pipeline schemas ---\n\nexport const pipelineCreateSchema = scopedSchema.extend({\n name: z.string().trim().min(1).max(200),\n isDefault: z.boolean().optional(),\n})\n\nexport const pipelineUpdateSchema = z.object({\n id: uuid(),\n name: z.string().trim().min(1).max(200).optional(),\n isDefault: z.boolean().optional(),\n})\n\nexport const pipelineDeleteSchema = z.object({\n id: uuid(),\n})\n\nexport type PipelineCreateInput = z.infer<typeof pipelineCreateSchema>\nexport type PipelineUpdateInput = z.infer<typeof pipelineUpdateSchema>\nexport type PipelineDeleteInput = z.infer<typeof pipelineDeleteSchema>\n\n// --- Pipeline Stage schemas ---\n\nexport const pipelineStageCreateSchema = scopedSchema.extend({\n pipelineId: uuid(),\n label: z.string().trim().min(1).max(200),\n order: z.number().int().min(0).optional(),\n color: z.string().trim().max(20).nullish(),\n icon: z.string().trim().max(100).nullish(),\n})\n\nexport const pipelineStageUpdateSchema = z.object({\n id: uuid(),\n label: z.string().trim().min(1).max(200).optional(),\n order: z.number().int().min(0).optional(),\n color: z.string().trim().max(20).nullish(),\n icon: z.string().trim().max(100).nullish(),\n})\n\nexport const pipelineStageDeleteSchema = z.object({\n id: uuid(),\n})\n\nexport const pipelineStageReorderSchema = scopedSchema.extend({\n stages: z.array(z.object({\n id: uuid(),\n order: z.number().int().min(0),\n })).min(1),\n})\n\nexport type PipelineStageCreateInput = z.infer<typeof pipelineStageCreateSchema>\nexport type PipelineStageUpdateInput = z.infer<typeof pipelineStageUpdateSchema>\nexport type PipelineStageDeleteInput = z.infer<typeof pipelineStageDeleteSchema>\nexport type PipelineStageReorderInput = z.infer<typeof pipelineStageReorderSchema>\n\nexport const entityRoleCreateSchema = scopedSchema.extend({\n entityType: z.enum(['company', 'person']),\n entityId: uuid(),\n roleType: z.string().trim().min(1).max(100),\n userId: uuid(),\n})\n\nexport const entityRoleUpdateSchema = scopedSchema.extend({\n id: uuid(),\n userId: uuid(),\n})\n\nexport const entityRoleDeleteSchema = scopedSchema.extend({\n id: uuid(),\n})\n\nexport type EntityRoleCreateInput = z.infer<typeof entityRoleCreateSchema>\nexport type EntityRoleUpdateInput = z.infer<typeof entityRoleUpdateSchema>\nexport type EntityRoleDeleteInput = z.infer<typeof entityRoleDeleteSchema>\n\nexport const updateKindSettingSchema = z.object({\n kind: z.string().trim().min(1).max(100),\n selectionMode: z.enum(['single', 'multi']).optional(),\n visibleInTags: z.boolean().optional(),\n sortOrder: z.number().int().min(0).optional(),\n})\n\nexport type UpdateKindSettingInput = z.infer<typeof updateKindSettingSchema>\n\nexport const customerKindSettingsUpsertSchema = scopedSchema.extend({\n kind: z.string().trim().min(1).max(100),\n selectionMode: z.enum(['single', 'multi']).optional(),\n visibleInTags: z.boolean().optional(),\n sortOrder: z.number().int().min(0).optional(),\n})\n\nexport type CustomerKindSettingsUpsertInput = z.infer<typeof customerKindSettingsUpsertSchema>\n\nexport const labelCreateSchema = z.object({\n label: z.string().trim().min(1).max(120),\n slug: z.string().trim().min(1).max(80).regex(/^[a-z0-9_-]+$/).optional(),\n})\n\nexport type LabelCreateInput = z.infer<typeof labelCreateSchema>\n\nexport const labelCreateCommandSchema = scopedSchema.extend({\n label: z.string().trim().min(1).max(120),\n slug: z.string().trim().min(1).max(80).regex(/^[a-z0-9_-]+$/),\n userId: uuid(),\n})\n\nexport type LabelCreateCommandInput = z.infer<typeof labelCreateCommandSchema>\n\nexport const labelAssignmentSchema = z.object({\n labelId: z.string().uuid(),\n entityId: z.string().uuid(),\n})\n\nexport type LabelAssignmentInput = z.infer<typeof labelAssignmentSchema>\n\nexport const labelAssignCommandSchema = scopedSchema.extend({\n labelId: uuid(),\n entityId: uuid(),\n})\n\nexport const labelUnassignCommandSchema = scopedSchema.extend({\n labelId: uuid(),\n entityId: uuid(),\n})\n\nexport type LabelAssignCommandInput = z.infer<typeof labelAssignCommandSchema>\nexport type LabelUnassignCommandInput = z.infer<typeof labelUnassignCommandSchema>\n\nexport const personCompanyLinkCreateSchema = scopedSchema.extend({\n personEntityId: uuid(),\n companyEntityId: uuid(),\n isPrimary: z.boolean().optional(),\n})\n\nexport const personCompanyLinkUpdateSchema = scopedSchema.extend({\n linkId: uuid(),\n isPrimary: z.boolean(),\n})\n\n// Two shapes are accepted, because a person can belong to a company in two ways:\n// through a `customer_person_company_links` row (`linkId`), or through a legacy\n// profile-only assignment where `customer_person_profiles.company_id` is set and no\n// link row was ever created (migrated CRM data, #5114). Both detaches go through the\n// same command so audit, undo and cache invalidation stay consistent.\nexport const personCompanyLinkDeleteSchema = scopedSchema\n .extend({\n linkId: uuid().optional(),\n personEntityId: uuid().optional(),\n companyEntityId: uuid().optional(),\n })\n .refine(\n (payload) => Boolean(payload.linkId) || Boolean(payload.personEntityId && payload.companyEntityId),\n {\n message: 'Provide either linkId or both personEntityId and companyEntityId.',\n path: ['linkId'],\n }\n )\n\nexport type PersonCompanyLinkCreateInput = z.infer<typeof personCompanyLinkCreateSchema>\nexport type PersonCompanyLinkUpdateInput = z.infer<typeof personCompanyLinkUpdateSchema>\nexport type PersonCompanyLinkDeleteInput = z.infer<typeof personCompanyLinkDeleteSchema>\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.8.1-develop.7254.1.ab24f26208",
3
+ "version": "0.8.1-develop.7263.1.bbc6db3437",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -253,16 +253,16 @@
253
253
  "zod": "^4.4.3"
254
254
  },
255
255
  "peerDependencies": {
256
- "@open-mercato/ai-assistant": "0.8.1-develop.7254.1.ab24f26208",
257
- "@open-mercato/shared": "0.8.1-develop.7254.1.ab24f26208",
258
- "@open-mercato/ui": "0.8.1-develop.7254.1.ab24f26208",
256
+ "@open-mercato/ai-assistant": "0.8.1-develop.7263.1.bbc6db3437",
257
+ "@open-mercato/shared": "0.8.1-develop.7263.1.bbc6db3437",
258
+ "@open-mercato/ui": "0.8.1-develop.7263.1.bbc6db3437",
259
259
  "react": "^19.0.0",
260
260
  "react-dom": "^19.0.0"
261
261
  },
262
262
  "devDependencies": {
263
- "@open-mercato/ai-assistant": "0.8.1-develop.7254.1.ab24f26208",
264
- "@open-mercato/shared": "0.8.1-develop.7254.1.ab24f26208",
265
- "@open-mercato/ui": "0.8.1-develop.7254.1.ab24f26208",
263
+ "@open-mercato/ai-assistant": "0.8.1-develop.7263.1.bbc6db3437",
264
+ "@open-mercato/shared": "0.8.1-develop.7263.1.bbc6db3437",
265
+ "@open-mercato/ui": "0.8.1-develop.7263.1.bbc6db3437",
266
266
  "@testing-library/dom": "^10.4.1",
267
267
  "@testing-library/jest-dom": "^7.0.1",
268
268
  "@testing-library/react": "^16.3.3",
@@ -935,6 +935,7 @@ export default function EditCatalogProductPage({
935
935
  values={values as ProductFormValues}
936
936
  setValue={setValue}
937
937
  errors={errors}
938
+ variantCount={variants.length}
938
939
  />
939
940
  ),
940
941
  },
@@ -1628,6 +1629,10 @@ type ProductVariantsSectionProps = Omit<
1628
1629
 
1629
1630
  type ProductDimensionsSectionProps = ProductFormGroupProps;
1630
1631
 
1632
+ type ProductOptionsSectionProps = ProductFormGroupProps & {
1633
+ variantCount?: number;
1634
+ };
1635
+
1631
1636
  function ProductDetailsSection({
1632
1637
  values,
1633
1638
  setValue,
@@ -1923,7 +1928,11 @@ function ProductMetadataSection({ values, setValue }: ProductFormGroupProps) {
1923
1928
  );
1924
1929
  }
1925
1930
 
1926
- function ProductOptionsSection({ values, setValue }: ProductFormGroupProps) {
1931
+ function ProductOptionsSection({
1932
+ values,
1933
+ setValue,
1934
+ variantCount = 0,
1935
+ }: ProductOptionsSectionProps) {
1927
1936
  const t = useT();
1928
1937
  const [schemaDialogOpen, setSchemaDialogOpen] = React.useState(false);
1929
1938
  const [schemaTemplates, setSchemaTemplates] = React.useState<
@@ -2186,10 +2195,15 @@ function ProductOptionsSection({ values, setValue }: ProductFormGroupProps) {
2186
2195
  ))}
2187
2196
  {!values.options?.length ? (
2188
2197
  <p className="text-sm text-muted-foreground">
2189
- {t(
2190
- "catalog.products.create.optionsBuilder.empty",
2191
- "No options yet. Add your first option to generate variants.",
2192
- )}
2198
+ {variantCount > 0
2199
+ ? t(
2200
+ "catalog.products.edit.optionsBuilder.emptyWithVariants",
2201
+ "This product has variants without an option schema. Options are optional.",
2202
+ )
2203
+ : t(
2204
+ "catalog.products.create.optionsBuilder.empty",
2205
+ "No options yet. Add your first option to generate variants.",
2206
+ )}
2193
2207
  </p>
2194
2208
  ) : null}
2195
2209
  </div>
@@ -530,6 +530,7 @@
530
530
  "catalog.products.edit.metadata.title": "Metadaten",
531
531
  "catalog.products.edit.metadata.valuePlaceholder": "Wert",
532
532
  "catalog.products.edit.offers.deleteError": "Vertriebskanal-Angebot konnte nicht entfernt werden.",
533
+ "catalog.products.edit.optionsBuilder.emptyWithVariants": "Dieses Produkt hat Varianten ohne Optionsschema. Optionen sind nicht erforderlich.",
533
534
  "catalog.products.edit.save": "Änderungen speichern",
534
535
  "catalog.products.edit.schemas.apply": "Anwenden",
535
536
  "catalog.products.edit.schemas.delete": "Schema löschen",
@@ -530,6 +530,7 @@
530
530
  "catalog.products.edit.metadata.title": "Metadata",
531
531
  "catalog.products.edit.metadata.valuePlaceholder": "Value",
532
532
  "catalog.products.edit.offers.deleteError": "Failed to remove sales channel offer.",
533
+ "catalog.products.edit.optionsBuilder.emptyWithVariants": "This product has variants without an option schema. Options are optional.",
533
534
  "catalog.products.edit.save": "Save changes",
534
535
  "catalog.products.edit.schemas.apply": "Apply",
535
536
  "catalog.products.edit.schemas.delete": "Delete schema",
@@ -530,6 +530,7 @@
530
530
  "catalog.products.edit.metadata.title": "Metadatos",
531
531
  "catalog.products.edit.metadata.valuePlaceholder": "Valor",
532
532
  "catalog.products.edit.offers.deleteError": "No se pudo eliminar la oferta del canal de ventas.",
533
+ "catalog.products.edit.optionsBuilder.emptyWithVariants": "Este producto tiene variantes sin un esquema de opciones. Las opciones son opcionales.",
533
534
  "catalog.products.edit.save": "Guardar cambios",
534
535
  "catalog.products.edit.schemas.apply": "Aplicar",
535
536
  "catalog.products.edit.schemas.delete": "Eliminar esquema",
@@ -530,6 +530,7 @@
530
530
  "catalog.products.edit.metadata.title": "메타데이터",
531
531
  "catalog.products.edit.metadata.valuePlaceholder": "값",
532
532
  "catalog.products.edit.offers.deleteError": "판매 채널 오퍼 제거에 실패했습니다.",
533
+ "catalog.products.edit.optionsBuilder.emptyWithVariants": "이 상품에는 옵션 스키마 없이 변형이 있습니다. 옵션은 선택 사항입니다.",
533
534
  "catalog.products.edit.save": "변경 사항 저장",
534
535
  "catalog.products.edit.schemas.apply": "적용",
535
536
  "catalog.products.edit.schemas.delete": "스키마 삭제",
@@ -530,6 +530,7 @@
530
530
  "catalog.products.edit.metadata.title": "Metadane",
531
531
  "catalog.products.edit.metadata.valuePlaceholder": "Wartość",
532
532
  "catalog.products.edit.offers.deleteError": "Nie udało się usunąć oferty kanału sprzedaży.",
533
+ "catalog.products.edit.optionsBuilder.emptyWithVariants": "Ten produkt ma warianty bez schematu opcji. Opcje są opcjonalne.",
533
534
  "catalog.products.edit.save": "Zapisz zmiany",
534
535
  "catalog.products.edit.schemas.apply": "Zastosuj",
535
536
  "catalog.products.edit.schemas.delete": "Usuń schemat",
@@ -6,6 +6,7 @@ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
6
6
  import { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
7
7
  import { CustomerUserService } from '@open-mercato/core/modules/customer_accounts/services/customerUserService'
8
8
  import { CustomerUser, CustomerUserRole, CustomerRole } from '@open-mercato/core/modules/customer_accounts/data/entities'
9
+ import { Organization } from '@open-mercato/core/modules/directory/data/entities'
9
10
  import type { EntityManager } from '@mikro-orm/postgresql'
10
11
  import { adminCreateUserSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'
11
12
  import { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'
@@ -181,20 +182,33 @@ export async function GET(req: Request) {
181
182
  else rolesByUserId.set(linkUserId, [entry])
182
183
  }
183
184
 
184
- const items = users.map((user) => ({
185
- id: user.id,
186
- email: user.email,
187
- displayName: user.displayName,
188
- emailVerified: !!user.emailVerifiedAt,
189
- isActive: user.isActive,
190
- lockedUntil: user.lockedUntil || null,
191
- lastLoginAt: user.lastLoginAt || null,
192
- customerEntityId: user.customerEntityId || null,
193
- personEntityId: user.personEntityId || null,
194
- createdAt: user.createdAt,
195
- updatedAt: user.updatedAt || null,
196
- roles: rolesByUserId.get(user.id) ?? [],
197
- }))
185
+ const pageOrganizationIds = Array.from(new Set(
186
+ users.map((user) => user.organizationId).filter((organizationId): organizationId is string => !!organizationId),
187
+ ))
188
+ const organizations = pageOrganizationIds.length > 0
189
+ ? await em.find(Organization, { id: { $in: pageOrganizationIds }, tenant: auth.tenantId, deletedAt: null })
190
+ : []
191
+ const organizationNameById = new Map(organizations.map((organization) => [organization.id, organization.name]))
192
+
193
+ const items = users.map((user) => {
194
+ const organizationId = user.organizationId ?? null
195
+ return {
196
+ id: user.id,
197
+ email: user.email,
198
+ displayName: user.displayName,
199
+ emailVerified: !!user.emailVerifiedAt,
200
+ isActive: user.isActive,
201
+ lockedUntil: user.lockedUntil || null,
202
+ lastLoginAt: user.lastLoginAt || null,
203
+ customerEntityId: user.customerEntityId || null,
204
+ personEntityId: user.personEntityId || null,
205
+ organizationId,
206
+ organizationName: organizationId ? organizationNameById.get(organizationId) ?? null : null,
207
+ createdAt: user.createdAt,
208
+ updatedAt: user.updatedAt || null,
209
+ roles: rolesByUserId.get(user.id) ?? [],
210
+ }
211
+ })
198
212
 
199
213
  const totalPages = Math.max(1, Math.ceil(total / pageSize))
200
214
 
@@ -335,6 +349,8 @@ const userSchema = z.object({
335
349
  lastLoginAt: z.string().datetime().nullable(),
336
350
  customerEntityId: z.string().uuid().nullable(),
337
351
  personEntityId: z.string().uuid().nullable(),
352
+ organizationId: z.string().uuid().nullable().describe('Organization the customer user belongs to'),
353
+ organizationName: z.string().nullable().describe('Resolved organization display name'),
338
354
  createdAt: z.string().datetime(),
339
355
  updatedAt: z.string().datetime().nullable(),
340
356
  roles: z.array(roleSchema),
@@ -36,6 +36,8 @@ type UserRow = {
36
36
  updatedAt?: string | null
37
37
  personEntityId: string | null
38
38
  customerEntityId: string | null
39
+ organizationId: string | null
40
+ organizationName: string | null
39
41
  }
40
42
 
41
43
  type UsersResponse = {
@@ -440,6 +442,15 @@ export function PortalUsersPageClient({ portalOrigin, portalOrgSlug = null }: Po
440
442
  accessorKey: 'email',
441
443
  header: t('customer_accounts.admin.columns.email', 'Email'),
442
444
  },
445
+ {
446
+ accessorKey: 'organizationName',
447
+ header: t('customer_accounts.admin.columns.organization', 'Organization'),
448
+ cell: ({ row }) => {
449
+ const label = row.original.organizationName || row.original.organizationId
450
+ if (!label) return noValue
451
+ return <span className="text-sm">{label}</span>
452
+ },
453
+ },
443
454
  {
444
455
  accessorKey: 'emailVerified',
445
456
  header: t('customer_accounts.admin.columns.emailVerified', 'Verified'),
@@ -259,18 +259,18 @@ export function PortalUserDetailPageClient({ params, portalOrigin }: PortalUserD
259
259
  async function loadPersonName() {
260
260
  if (!data!.personEntityId) return
261
261
  try {
262
- const call = await apiCall<{ id?: string; firstName?: string; lastName?: string }>(`/api/customers/people/${encodeURIComponent(data!.personEntityId)}`)
263
- if (!cancelled && call.ok && call.result) {
264
- setPersonName([call.result.firstName, call.result.lastName].filter(Boolean).join(' ') || call.result.id || null)
262
+ const call = await apiCall<{ person?: { id?: string; displayName?: string | null } }>(`/api/customers/people/${encodeURIComponent(data!.personEntityId)}`)
263
+ if (!cancelled && call.ok && call.result?.person) {
264
+ setPersonName(call.result.person.displayName || call.result.person.id || null)
265
265
  }
266
266
  } catch { /* ignore */ }
267
267
  }
268
268
  async function loadCompanyName() {
269
269
  if (!data!.customerEntityId) return
270
270
  try {
271
- const call = await apiCall<{ id?: string; name?: string }>(`/api/customers/${encodeURIComponent(data!.customerEntityId)}`)
272
- if (!cancelled && call.ok && call.result) {
273
- setCompanyName(call.result.name || call.result.id || null)
271
+ const call = await apiCall<{ company?: { id?: string; displayName?: string | null } }>(`/api/customers/companies/${encodeURIComponent(data!.customerEntityId)}`)
272
+ if (!cancelled && call.ok && call.result?.company) {
273
+ setCompanyName(call.result.company.displayName || call.result.company.id || null)
274
274
  }
275
275
  } catch { /* ignore */ }
276
276
  }
@@ -282,13 +282,13 @@ export function PortalUserDetailPageClient({ params, portalOrigin }: PortalUserD
282
282
  setPersonSearchQuery(query)
283
283
  if (query.trim().length < 2) { setPersonResults([]); return }
284
284
  try {
285
- const call = await apiCall<{ items?: Array<{ id: string; firstName?: string; lastName?: string; email?: string }> }>(
285
+ const call = await apiCall<{ items?: Array<{ id: string; first_name?: string; last_name?: string; primary_email?: string }> }>(
286
286
  `/api/customers/people?search=${encodeURIComponent(query.trim())}&pageSize=10`,
287
287
  )
288
288
  if (call.ok && Array.isArray(call.result?.items)) {
289
289
  setPersonResults(call.result!.items.map((person) => ({
290
290
  id: person.id,
291
- label: [person.firstName, person.lastName].filter(Boolean).join(' ') || person.email || person.id,
291
+ label: [person.first_name, person.last_name].filter(Boolean).join(' ') || person.primary_email || person.id,
292
292
  })))
293
293
  }
294
294
  } catch { /* ignore */ }
@@ -298,13 +298,13 @@ export function PortalUserDetailPageClient({ params, portalOrigin }: PortalUserD
298
298
  setCompanySearchQuery(query)
299
299
  if (query.trim().length < 2) { setCompanyResults([]); return }
300
300
  try {
301
- const call = await apiCall<{ items?: Array<{ id: string; name?: string }> }>(
302
- `/api/customers?search=${encodeURIComponent(query.trim())}&pageSize=10`,
301
+ const call = await apiCall<{ items?: Array<{ id: string; display_name?: string }> }>(
302
+ `/api/customers/companies?search=${encodeURIComponent(query.trim())}&pageSize=10`,
303
303
  )
304
304
  if (call.ok && Array.isArray(call.result?.items)) {
305
305
  setCompanyResults(call.result!.items.map((company) => ({
306
306
  id: company.id,
307
- label: company.name || company.id,
307
+ label: company.display_name || company.id,
308
308
  })))
309
309
  }
310
310
  } catch { /* ignore */ }
@@ -10,6 +10,7 @@
10
10
  "customer_accounts.admin.columns.email": "Email",
11
11
  "customer_accounts.admin.columns.emailVerified": "Verified",
12
12
  "customer_accounts.admin.columns.lastLogin": "Last Login",
13
+ "customer_accounts.admin.columns.organization": "Organisation",
13
14
  "customer_accounts.admin.columns.roles": "Roles",
14
15
  "customer_accounts.admin.columns.status": "Status",
15
16
  "customer_accounts.admin.confirm.delete": "Delete user \"{{name}}\"?",
@@ -10,6 +10,7 @@
10
10
  "customer_accounts.admin.columns.email": "Email",
11
11
  "customer_accounts.admin.columns.emailVerified": "Verified",
12
12
  "customer_accounts.admin.columns.lastLogin": "Last Login",
13
+ "customer_accounts.admin.columns.organization": "Organization",
13
14
  "customer_accounts.admin.columns.roles": "Roles",
14
15
  "customer_accounts.admin.columns.status": "Status",
15
16
  "customer_accounts.admin.confirm.delete": "Delete user \"{{name}}\"?",
@@ -10,6 +10,7 @@
10
10
  "customer_accounts.admin.columns.email": "Email",
11
11
  "customer_accounts.admin.columns.emailVerified": "Verified",
12
12
  "customer_accounts.admin.columns.lastLogin": "Last Login",
13
+ "customer_accounts.admin.columns.organization": "Organización",
13
14
  "customer_accounts.admin.columns.roles": "Roles",
14
15
  "customer_accounts.admin.columns.status": "Status",
15
16
  "customer_accounts.admin.confirm.delete": "Delete user \"{{name}}\"?",
@@ -10,6 +10,7 @@
10
10
  "customer_accounts.admin.columns.email": "이메일",
11
11
  "customer_accounts.admin.columns.emailVerified": "확인됨",
12
12
  "customer_accounts.admin.columns.lastLogin": "마지막 로그인",
13
+ "customer_accounts.admin.columns.organization": "조직",
13
14
  "customer_accounts.admin.columns.roles": "역할",
14
15
  "customer_accounts.admin.columns.status": "상태",
15
16
  "customer_accounts.admin.confirm.delete": "사용자 \"{{name}}\"을(를) 삭제하시겠습니까?",
@@ -10,6 +10,7 @@
10
10
  "customer_accounts.admin.columns.email": "E-mail",
11
11
  "customer_accounts.admin.columns.emailVerified": "Zweryfikowany",
12
12
  "customer_accounts.admin.columns.lastLogin": "Ostatnie logowanie",
13
+ "customer_accounts.admin.columns.organization": "Organizacja",
13
14
  "customer_accounts.admin.columns.roles": "Role",
14
15
  "customer_accounts.admin.columns.status": "Status",
15
16
  "customer_accounts.admin.confirm.delete": "Usunąć użytkownika \"{{name}}\"?",