@open-mercato/core 0.6.6-develop.6515.1.01911d00e2 → 0.6.6-develop.6519.1.bdc91fb755

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 (86) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/configs/lib/upgrade-actions.js +31 -1
  3. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  4. package/dist/modules/customers/ai-tools/activities-tasks-pack.js +11 -2
  5. package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +2 -2
  6. package/dist/modules/customers/api/companies/[id]/route.js +3 -2
  7. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  8. package/dist/modules/customers/api/dictionaries/context.js +4 -2
  9. package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
  10. package/dist/modules/customers/api/interactions/conflicts/route.js +2 -1
  11. package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
  12. package/dist/modules/customers/api/interactions/counts/route.js +7 -2
  13. package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
  14. package/dist/modules/customers/api/people/[id]/route.js +3 -2
  15. package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
  16. package/dist/modules/customers/cli.js +19 -0
  17. package/dist/modules/customers/cli.js.map +2 -2
  18. package/dist/modules/customers/commands/interactions.js +8 -3
  19. package/dist/modules/customers/commands/interactions.js.map +2 -2
  20. package/dist/modules/customers/commands/shared.js +2 -1
  21. package/dist/modules/customers/commands/shared.js.map +2 -2
  22. package/dist/modules/customers/components/DictionarySettings.js +5 -0
  23. package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
  24. package/dist/modules/customers/components/DictionarySortSettings.js +5 -0
  25. package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
  26. package/dist/modules/customers/components/detail/ActivitiesCard.js +3 -2
  27. package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
  28. package/dist/modules/customers/components/detail/ActivityCard.js +2 -1
  29. package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
  30. package/dist/modules/customers/components/detail/ActivityTimeline.js +3 -2
  31. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  32. package/dist/modules/customers/components/detail/TaskDialog.js +3 -2
  33. package/dist/modules/customers/components/detail/TaskDialog.js.map +2 -2
  34. package/dist/modules/customers/components/detail/TaskForm.js +170 -69
  35. package/dist/modules/customers/components/detail/TaskForm.js.map +2 -2
  36. package/dist/modules/customers/components/detail/TasksSection.js +27 -4
  37. package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
  38. package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
  39. package/dist/modules/customers/data/enrichers.js +2 -2
  40. package/dist/modules/customers/data/enrichers.js.map +2 -2
  41. package/dist/modules/customers/data/validators.js +6 -2
  42. package/dist/modules/customers/data/validators.js.map +2 -2
  43. package/dist/modules/customers/lib/dictionaries.js +2 -1
  44. package/dist/modules/customers/lib/dictionaries.js.map +2 -2
  45. package/dist/modules/customers/lib/interactionProjection.js +2 -1
  46. package/dist/modules/customers/lib/interactionProjection.js.map +2 -2
  47. package/dist/modules/customers/lib/interactionStatus.js +24 -0
  48. package/dist/modules/customers/lib/interactionStatus.js.map +7 -0
  49. package/dist/modules/customers/lib/link-channel-message-handler.js +4 -5
  50. package/dist/modules/customers/lib/link-channel-message-handler.js.map +2 -2
  51. package/dist/modules/dictionaries/components/AppearanceSelector.js +7 -3
  52. package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
  53. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +1 -0
  54. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  55. package/package.json +7 -7
  56. package/src/modules/configs/lib/upgrade-actions.ts +31 -1
  57. package/src/modules/customers/ai-tools/activities-tasks-pack.ts +12 -3
  58. package/src/modules/customers/api/companies/[id]/route.ts +3 -2
  59. package/src/modules/customers/api/dictionaries/context.ts +2 -0
  60. package/src/modules/customers/api/interactions/conflicts/route.ts +2 -1
  61. package/src/modules/customers/api/interactions/counts/route.ts +7 -2
  62. package/src/modules/customers/api/people/[id]/route.ts +3 -2
  63. package/src/modules/customers/cli.ts +19 -0
  64. package/src/modules/customers/commands/interactions.ts +8 -3
  65. package/src/modules/customers/commands/shared.ts +1 -0
  66. package/src/modules/customers/components/DictionarySettings.tsx +5 -0
  67. package/src/modules/customers/components/DictionarySortSettings.tsx +5 -0
  68. package/src/modules/customers/components/detail/ActivitiesCard.tsx +3 -2
  69. package/src/modules/customers/components/detail/ActivityCard.tsx +2 -1
  70. package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -2
  71. package/src/modules/customers/components/detail/TaskDialog.tsx +4 -1
  72. package/src/modules/customers/components/detail/TaskForm.tsx +218 -71
  73. package/src/modules/customers/components/detail/TasksSection.tsx +28 -2
  74. package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +1 -0
  75. package/src/modules/customers/data/enrichers.ts +2 -7
  76. package/src/modules/customers/data/validators.ts +16 -2
  77. package/src/modules/customers/i18n/de.json +10 -0
  78. package/src/modules/customers/i18n/en.json +10 -0
  79. package/src/modules/customers/i18n/es.json +10 -0
  80. package/src/modules/customers/i18n/pl.json +10 -0
  81. package/src/modules/customers/lib/dictionaries.ts +1 -0
  82. package/src/modules/customers/lib/interactionProjection.ts +6 -2
  83. package/src/modules/customers/lib/interactionStatus.ts +30 -0
  84. package/src/modules/customers/lib/link-channel-message-handler.ts +4 -5
  85. package/src/modules/dictionaries/components/AppearanceSelector.tsx +10 -1
  86. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +1 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/api/companies/%5Bid%5D/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerAddress,\n CustomerComment,\n CustomerActivity,\n CustomerTagAssignment,\n CustomerTag,\n CustomerLabelAssignment,\n CustomerLabel,\n CustomerDealCompanyLink,\n CustomerDeal,\n CustomerTodoLink,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n CustomerInteraction,\n} from '../../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n resolveCompanyCustomFieldRouting,\n mergeCompanyCustomFieldValues,\n} from '../../../lib/customFieldRouting'\nimport {\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n EXAMPLE_TODO_SOURCE,\n CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n mapInteractionRecordToActivitySummary,\n mapInteractionRecordToTodoSummary,\n} from '../../../lib/interactionCompatibility'\nimport { resolveCustomerInteractionFeatureFlags } from '../../../lib/interactionFeatureFlags'\nimport { hydrateCanonicalInteractions } from '../../../lib/interactionReadModel'\nimport { buildEmailVisibilityMikroFilter } from '../../../lib/visibilityFilter'\nimport { resolveCustomerDetailTenantScope } from '../../../lib/detailTenantScope'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../lib/personCompanyLinkTable'\nimport { normalizeCustomerDetailCustomFields } from '../../detailCustomFields'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport { runWithCacheTenant } from '@open-mercato/cache'\nimport {\n buildCollectionTags,\n canonicalizeResourceTag,\n isCrudCacheEnabled,\n resolveCrudCache,\n} from '@open-mercato/shared/lib/crud/cache'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst COMPANY_DETAIL_CACHE_TTL_MS = 60_000\n\n// The customers write commands already invalidate these resource collections via\n// invalidateCrudCache using these exact resourceKind strings. Reusing them as\n// cache tags means the cached detail is flushed by those existing commands with\n// no new wiring (#3664, mirroring #3143). Canonicalize each kind the same way\n// invalidateCrudCache does (camelCase split + lowercase) so the tag shapes match.\nconst COMPANY_DETAIL_CACHE_RESOURCE_KINDS = [\n 'customers.company',\n 'customers.address',\n 'customers.tagAssignment',\n 'customers.labelAssignment',\n 'customers.personCompanyLink',\n 'customers.interaction',\n 'customers.activity',\n] as const\n\nfunction buildCompanyDetailCacheTags(tenantId: string | null, organizationId: string | null): string[] {\n const tags = new Set<string>()\n for (const resourceKind of COMPANY_DETAIL_CACHE_RESOURCE_KINDS) {\n const resource = canonicalizeResourceTag(resourceKind) ?? resourceKind\n for (const tag of buildCollectionTags(resource, tenantId, [organizationId])) {\n tags.add(tag)\n }\n }\n return Array.from(tags)\n}\n\nfunction buildCompanyDetailCacheKey(parts: {\n tenantId: string | null\n organizationId: string | null\n companyId: string\n selectedOrganizationId: string | null\n filterIds: string[] | null\n allowedIds: string[] | null\n isSuperAdmin: boolean\n viewerUserId: string | null\n interactionMode: string\n includeTokens: string[]\n}): string {\n const sortKeys = (values: string[]): string[] =>\n [...values].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))\n const filterIds = parts.filterIds ? sortKeys(parts.filterIds).join(',') : 'all'\n const allowedIds = parts.allowedIds ? sortKeys(parts.allowedIds).join(',') : 'all'\n const includeTokens = sortKeys(parts.includeTokens).join(',')\n return [\n 'customers:companies:detail',\n `tenant:${parts.tenantId ?? 'null'}`,\n `org:${parts.organizationId ?? 'null'}`,\n `company:${parts.companyId}`,\n `selected:${parts.selectedOrganizationId ?? 'null'}`,\n `filter:${filterIds}`,\n `allowed:${allowedIds}`,\n `super:${parts.isSuperAdmin ? '1' : '0'}`,\n `viewer:${parts.viewerUserId ?? 'null'}`,\n `mode:${parts.interactionMode}`,\n `include:${includeTokens}`,\n ].join('|')\n}\n\nfunction parseIncludeParams(request: Request): Set<string> {\n const url = new URL(request.url)\n const raw = url.searchParams.getAll('include')\n const tokens = new Set<string>()\n raw.forEach((entry) => {\n if (!entry) return\n entry\n .split(',')\n .map((part) => part.trim().toLowerCase())\n .filter((part) => part.length > 0)\n .forEach((part) => tokens.add(part))\n })\n return tokens\n}\n\nfunction forbidden(message: string) {\n return NextResponse.json({ error: message }, { status: 403 })\n}\n\nfunction notFound(message: string) {\n return NextResponse.json({ error: message }, { status: 404 })\n}\n\nfunction serializeTags(assignments: CustomerTagAssignment[]): Array<{ id: string; label: string; color: string | null }> {\n return assignments\n .map((assignment) => {\n const tag = assignment.tag as CustomerTag | string | null\n if (!tag || typeof tag === 'string') return null\n return {\n id: tag.id,\n label: tag.label,\n color: tag.color ?? null,\n }\n })\n .filter((tag): tag is { id: string; label: string; color: string | null } => tag !== null)\n}\n\ntype TodoDetail = {\n title: string | null\n isDone: boolean | null\n priority: number | null\n severity: string | null\n description: string | null\n dueAt: string | null\n organizationId: string | null\n customValues: Record<string, unknown> | null\n}\n\nfunction extractTodoTitle(record: Record<string, unknown>): string | null {\n const candidates = ['title', 'subject', 'name', 'summary', 'text', 'description']\n for (const key of candidates) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length > 0) {\n return value.trim()\n }\n }\n return null\n}\n\nfunction parseNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = Number(trimmed)\n if (!Number.isNaN(parsed)) return parsed\n }\n return null\n}\n\nfunction parseDateValue(value: unknown): string | null {\n if (value instanceof Date) {\n const ts = value.getTime()\n return Number.isNaN(ts) ? null : value.toISOString()\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const candidate = new Date(trimmed)\n if (!Number.isNaN(candidate.getTime())) return candidate.toISOString()\n }\n return null\n}\n\nfunction readCustomField(record: Record<string, unknown>, key: string): unknown {\n const custom = record.custom ?? record.customFields ?? record.cf\n if (custom && typeof custom === 'object') {\n const bucket = custom as Record<string, unknown>\n if (key in bucket) return bucket[key]\n }\n return undefined\n}\n\ntype CompanyDetailKpiSummary = {\n activeDealsCount: number\n activeDealsValue: number | null\n dealCurrency: string | null\n activityCount: number\n activityTrend: { value: number; direction: 'up' | 'down' | 'unchanged' } | null\n ltvValue: number | null\n completedDealsCount: number\n clientTenureYears: number | null\n}\n\nfunction parseDealAmount(value: string | number | null | undefined): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = Number(trimmed)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nfunction computeActivityTrend(\n timestamps: string[],\n): { value: number; direction: 'up' | 'down' | 'unchanged' } | null {\n if (!timestamps.length) return null\n const now = Date.now()\n const weekMs = 7 * 86_400_000\n let thisWeek = 0\n let lastWeek = 0\n timestamps.forEach((value) => {\n const time = new Date(value).getTime()\n if (Number.isNaN(time)) return\n const diff = now - time\n if (diff < 0 || diff >= weekMs * 2) return\n if (diff < weekMs) {\n thisWeek += 1\n return\n }\n lastWeek += 1\n })\n if (lastWeek === 0 && thisWeek === 0) return null\n if (lastWeek === 0) return { value: 100, direction: 'up' }\n const pct = ((thisWeek - lastWeek) / lastWeek) * 100\n if (Math.abs(pct) < 0.5) return { value: 0, direction: 'unchanged' }\n return { value: Math.round(Math.abs(pct) * 100) / 100, direction: pct > 0 ? 'up' : 'down' }\n}\n\nasync function resolveTodoDetails(\n queryEngine: QueryEngine,\n links: CustomerTodoLink[],\n tenantId: string | null,\n organizationIds: Array<string | null>,\n): Promise<Map<string, TodoDetail>> {\n const details = new Map<string, TodoDetail>()\n if (!links.length || !tenantId) return details\n\n const scopedOrgIds = organizationIds\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n\n const idsBySource = new Map<string, Set<string>>()\n for (const link of links) {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const id = typeof link.todoId === 'string' && link.todoId.trim().length > 0 ? link.todoId : String(link.todoId ?? '')\n if (!id) continue\n if (!idsBySource.has(source)) idsBySource.set(source, new Set<string>())\n idsBySource.get(source)!.add(id)\n }\n\n for (const [source, idSet] of idsBySource.entries()) {\n const ids = Array.from(idSet)\n if (!ids.length) continue\n try {\n const result = await queryEngine.query<Record<string, unknown>>(source as EntityId, {\n tenantId,\n organizationIds: scopedOrgIds.length > 0 ? scopedOrgIds : undefined,\n filters: { id: { $in: ids } },\n includeCustomFields: ['priority', 'due_at', 'severity', 'description'],\n page: { page: 1, pageSize: Math.max(ids.length, 1) },\n })\n for (const item of result.items ?? []) {\n if (!item || typeof item !== 'object') continue\n const record = item as Record<string, unknown>\n const rawId = typeof record.id === 'string' && record.id.trim().length > 0 ? record.id : String(record.id ?? '')\n if (!rawId) continue\n const title = extractTodoTitle(record)\n const isDone = (() => {\n const direct = parseBooleanFromUnknown(record.is_done)\n if (direct !== null) return direct\n const custom = parseBooleanFromUnknown(readCustomField(record, 'is_done'))\n if (custom !== null) return custom\n const generic = parseBooleanFromUnknown(record.isDone)\n if (generic !== null) return generic\n return parseBooleanFromUnknown(readCustomField(record, 'isDone'))\n })()\n const priority = (() => {\n const candidates = [\n record['cf:priority'],\n record['cf_priority'],\n record.priority,\n readCustomField(record, 'priority'),\n ]\n for (const candidate of candidates) {\n const parsed = parseNumber(candidate)\n if (parsed !== null) return parsed\n }\n return null\n })()\n const severity = (() => {\n const candidates = [\n record['cf:severity'],\n record['cf_severity'],\n record.severity,\n readCustomField(record, 'severity'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const dueAt = (() => {\n const candidates = [\n record['cf:due_at'],\n record['cf_due_at'],\n record.due_at,\n readCustomField(record, 'due_at'),\n record.dueAt,\n readCustomField(record, 'dueAt'),\n ]\n for (const candidate of candidates) {\n const parsed = parseDateValue(candidate)\n if (parsed) return parsed\n }\n return null\n })()\n const organizationId = (() => {\n const candidates = [\n record.organization_id,\n record['cf:organization_id'],\n record['cf_organization_id'],\n record.organizationId,\n readCustomField(record, 'organization_id'),\n readCustomField(record, 'organizationId'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const descriptionValue = (() => {\n const direct = typeof record.description === 'string' ? record.description : null\n if (direct) return direct\n const customDescription = readCustomField(record, 'description')\n if (typeof customDescription === 'string' && customDescription.trim().length > 0) {\n return customDescription.trim()\n }\n return null\n })()\n\n const customValues: Record<string, unknown> = {}\n const assignCustomValue = (key: string, value: unknown) => {\n const trimmedKey = key.trim()\n if (!trimmedKey.length) return\n customValues[trimmedKey] = value === undefined ? null : value\n }\n for (const [rawKey, rawValue] of Object.entries(record)) {\n if (rawKey.startsWith('cf:')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n } else if (rawKey.startsWith('cf_')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n }\n }\n const nestedCustom = record.custom ?? record.customFields ?? record.cf\n if (nestedCustom && typeof nestedCustom === 'object') {\n for (const [nestedKey, nestedValue] of Object.entries(nestedCustom as Record<string, unknown>)) {\n assignCustomValue(nestedKey, nestedValue)\n }\n }\n\n details.set(`${source}:${rawId}`, {\n title,\n isDone,\n priority,\n severity,\n description: descriptionValue,\n dueAt,\n organizationId,\n customValues: Object.keys(customValues).length ? customValues : null,\n })\n }\n } catch (err) {\n logger.warn('customers.companies.detail: failed to resolve todos', { source, err })\n }\n }\n\n return details\n}\n\nexport async function GET(_req: Request, ctx: { params?: { id?: string } }) {\n const auth = await getAuthFromRequest(_req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const parse = paramsSchema.safeParse({ id: ctx.params?.id })\n if (!parse.success) return NextResponse.json({ error: 'Invalid company id' }, { status: 400 })\n\n const includeTokens = parseIncludeParams(_req)\n const includeActivities = includeTokens.has('activities')\n const includeAddresses = includeTokens.has('addresses')\n const includeComments = includeTokens.has('comments') || includeTokens.has('notes')\n const includeDeals = includeTokens.has('deals')\n const includeInteractions = includeTokens.has('interactions')\n const includeTodos = includeTokens.has('todos') || includeTokens.has('tasks')\n const includePeople = includeTokens.has('people')\n const plannedPreviewLimit = 5\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: _req })\n const em = (container.resolve('em') as EntityManager)\n const interactionFlags = await resolveCustomerInteractionFeatureFlags(container, scope?.tenantId ?? auth.tenantId)\n const interactionMode = interactionFlags.unified ? 'canonical' : 'legacy'\n\n const tenantScope = resolveCustomerDetailTenantScope(parse.data.id, 'company', auth)\n if (!tenantScope.allowed) return notFound('Company not found')\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n tenantScope.where,\n { populate: ['companyProfile'] },\n {\n tenantId: auth.tenantId ?? null,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n },\n )\n if (!company) return notFound('Company not found')\n\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: company.organizationId })) {\n return forbidden('Access denied')\n }\n\n const companyScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n\n // Per-user email privacy (CRM email integration): exclude private email\n // interactions owned by other users from every read path that returns\n // customer_interactions. Non-email rows, shared emails, and legacy\n // null-visibility rows pass through. v1 is strict owner-only: there is NO\n // admin bypass \u2014 the filter ignores caller features, and\n // `customers.email.view_private` is reserved (inert) for v2 oversight.\n // Mirrors the people detail route. API-key callers resolve to null\n // (no author match \u2014 shared/non-email rows only).\n const viewerUserId = auth.isApiKey ? null : (auth.sub ?? null)\n const emailVisibilityFilter = buildEmailVisibilityMikroFilter({\n currentUserId: viewerUserId,\n userFeatures: undefined,\n })\n\n // Opt-in cache (#3664): the company existence + org read-access checks above\n // always run, so authorization is never served from cache. Only the expensive\n // detail sweeps below are cached. Key on tenant/org/company + the RBAC scope,\n // viewer (email privacy), interaction mode, and the requested include set.\n const cacheTenantId = companyScope.tenantId\n const cache = isCrudCacheEnabled() ? resolveCrudCache(container) : null\n const cacheKey = cache\n ? buildCompanyDetailCacheKey({\n tenantId: cacheTenantId,\n organizationId: companyScope.organizationId,\n companyId: company.id,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n filterIds: scope?.filterIds ?? null,\n allowedIds: scope?.allowedIds ?? null,\n isSuperAdmin: auth.isSuperAdmin === true,\n viewerUserId,\n interactionMode,\n includeTokens: Array.from(includeTokens),\n })\n : null\n if (cache && cacheKey) {\n const cached = await runWithCacheTenant(cacheTenantId, () => cache.get(cacheKey))\n if (cached) return NextResponse.json(cached)\n }\n\n const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos\n\n // These reads only depend on the resolved company + scope + email visibility\n // filter, so dispatch them together to avoid a server-side request waterfall\n // before the detail surface can render (issue #3203).\n const [profile, addresses, tagAssignments, labelAssignments, comments, canonicalInteractionRows] = await Promise.all([\n company.companyProfile\n ? findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n id: company.companyProfile.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n )\n : findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n entity: company,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n ),\n includeAddresses\n ? findWithDecryption(\n em,\n CustomerAddress,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { isPrimary: 'desc', createdAt: 'desc' } },\n companyScope,\n )\n : Promise.resolve<CustomerAddress[]>([]),\n findWithDecryption(\n em,\n CustomerTagAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['tag'] },\n companyScope,\n ),\n findWithDecryption(\n em,\n CustomerLabelAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['label'] },\n companyScope,\n ),\n includeComments\n ? findWithDecryption(\n em,\n CustomerComment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : Promise.resolve<CustomerComment[]>([]),\n shouldLoadCanonicalInteractions\n ? findWithDecryption(\n em,\n CustomerInteraction,\n interactionFlags.unified\n ? {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }\n : {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'asc', createdAt: 'desc' }, limit: 100 },\n companyScope,\n )\n : Promise.resolve<CustomerInteraction[]>([]),\n ])\n const canonicalActiveInteractions = canonicalInteractionRows.filter((interaction) => !interaction.deletedAt)\n const canonicalInteractions = shouldLoadCanonicalInteractions\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: canonicalActiveInteractions,\n enrich: includeInteractions,\n })\n : []\n\n const plannedPreviewRows =\n canonicalActiveInteractions.length > 0\n ? canonicalActiveInteractions\n .filter((interaction) => interaction.status === 'planned' && interaction.interactionType !== 'task')\n .sort((left, right) => {\n const leftTime = new Date(left.scheduledAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.scheduledAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return left.id.localeCompare(right.id)\n return leftTime - rightTime\n })\n .slice(0, plannedPreviewLimit)\n : await findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n status: 'planned',\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'ASC', createdAt: 'ASC' }, limit: plannedPreviewLimit },\n companyScope,\n )\n const plannedActivitiesPreview = plannedPreviewRows.length\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: plannedPreviewRows,\n enrich: true,\n })\n : []\n\n const activities = includeActivities && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerActivity,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { occurredAt: 'desc', createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n const todoLinks = includeTodos && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerTodoLink,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n\n let todoDetails = new Map<string, TodoDetail>()\n if (includeTodos && !interactionFlags.unified && todoLinks.length) {\n const queryEngine = (container.resolve('queryEngine') as QueryEngine)\n try {\n todoDetails = await resolveTodoDetails(\n queryEngine,\n todoLinks,\n company.tenantId ?? auth.tenantId ?? null,\n [company.organizationId ?? null, ...(scope?.filterIds ?? [])],\n )\n } catch (err) {\n logger.warn('customers.companies.detail: failed to enrich todo links', { err })\n }\n }\n\n const canonicalActivityBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n const canonicalTodoBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n\n const canonicalActivityItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType !== 'task')\n .map((interaction) => mapInteractionRecordToActivitySummary(interaction))\n const canonicalTodoItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType === 'task')\n .map((interaction) => mapInteractionRecordToTodoSummary(interaction))\n\n const authorIds = new Set<string>()\n if (includeActivities) {\n for (const activity of activities) {\n if (activity.authorUserId) authorIds.add(activity.authorUserId)\n }\n }\n if (includeComments) {\n for (const comment of comments) {\n if (comment.authorUserId) authorIds.add(comment.authorUserId)\n }\n }\n if (viewerUserId) authorIds.add(viewerUserId)\n\n let userMap = new Map<string, { name: string | null; email: string | null }>()\n if (authorIds.size) {\n const authorIdList = Array.from(authorIds)\n const users = await findWithDecryption(\n em,\n User,\n {\n id: { $in: authorIdList },\n tenantId: company.tenantId,\n },\n {},\n companyScope,\n )\n userMap = new Map(\n users.map((user) => [\n user.id,\n {\n name: user.name ?? null,\n email: user.email ?? null,\n },\n ])\n )\n }\n\n let deals: CustomerDeal[] = []\n if (includeDeals) {\n const dealLinks = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n deals = dealLinks\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n }\n\n const dealLinksForMetrics = includeDeals\n ? deals\n : (\n await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n )\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n\n let relatedPeople: Array<{\n entity: CustomerEntity\n profile: CustomerPersonProfile | null\n linkedAt: string | null\n }> = []\n if (includePeople) {\n const peopleDecryptionScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n const relatedPeopleById = new Map<\n string,\n { entity: CustomerEntity; profile: CustomerPersonProfile | null; linkedAt: string | null }\n >()\n const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n const companyLinks = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyLinkWhere,\n {\n populate: ['person', 'person.personProfile'],\n orderBy: { isPrimary: 'desc', createdAt: 'asc' },\n },\n peopleDecryptionScope,\n ),\n )\n companyLinks.forEach((link) => {\n const entity = typeof link.person === 'string' ? null : link.person\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n const personProfile =\n entity.personProfile && typeof entity.personProfile !== 'string'\n ? entity.personProfile\n : null\n relatedPeopleById.set(entity.id, {\n entity,\n profile: personProfile,\n linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null,\n })\n })\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n entity: { deletedAt: null },\n },\n { populate: ['entity'] },\n peopleDecryptionScope,\n )\n profiles.forEach((entry) => {\n const entity = entry.entity as CustomerEntity | null\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n if (!relatedPeopleById.has(entity.id)) {\n relatedPeopleById.set(entity.id, {\n entity,\n profile: entry ?? null,\n linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null,\n })\n }\n })\n relatedPeople = Array.from(relatedPeopleById.values())\n }\n\n // Entity custom fields, profile custom fields, and the routing lookup do not\n // depend on each other (profileId is already resolved above), so load them in\n // parallel instead of three sequential awaits (issue #3203).\n const profileId = profile?.id ?? null\n const [entityCustomFieldValues, profileCustomFieldValues, routing] = await Promise.all([\n loadCustomFieldValues({\n em,\n entityId: E.customers.customer_entity,\n recordIds: [company.id],\n tenantIdByRecord: { [company.id]: company.tenantId ?? null },\n organizationIdByRecord: { [company.id]: company.organizationId ?? null },\n tenantFallbacks: [\n company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n }),\n profileId\n ? loadCustomFieldValues({\n em,\n entityId: E.customers.customer_company_profile,\n recordIds: [profileId],\n tenantIdByRecord: { [profileId]: profile?.tenantId ?? null },\n organizationIdByRecord: { [profileId]: profile?.organizationId ?? null },\n tenantFallbacks: [\n profile?.tenantId ?? company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n })\n : Promise.resolve<Record<string, Record<string, unknown>>>({}),\n resolveCompanyCustomFieldRouting(em, company.tenantId ?? null, company.organizationId ?? null),\n ])\n const customFields = normalizeCustomerDetailCustomFields(\n mergeCompanyCustomFieldValues(\n routing,\n entityCustomFieldValues?.[company.id] ?? {},\n profileId ? profileCustomFieldValues?.[profileId] ?? {} : {},\n ),\n )\n\n // The count queries, related-people fallback, and KPI interaction fallback are\n // all independent of each other; dispatch them together rather than awaiting\n // each inline so the response counts/KPIs are assembled in one parallel round\n // instead of a waterfall (issue #3203).\n const peopleCountQuery = includePeople\n ? Promise.resolve(relatedPeople.length)\n : (async () => {\n const peopleLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n return filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n peopleLinkWhere,\n {},\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ).length\n })()\n const [\n activityCount,\n interactionCount,\n todoCount,\n commentsCount,\n addressesCount,\n peopleCount,\n kpiInteractionRows,\n ] = await Promise.all([\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n }),\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }),\n interactionFlags.unified\n ? em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: 'task',\n })\n : em.count(CustomerTodoLink, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeComments\n ? Promise.resolve(comments.length)\n : em.count(CustomerComment, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeAddresses\n ? Promise.resolve(addresses.length)\n : em.count(CustomerAddress, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n peopleCountQuery,\n canonicalActiveInteractions.length\n ? Promise.resolve(canonicalActiveInteractions)\n : findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n },\n {\n fields: ['id', 'occurredAt', 'scheduledAt', 'createdAt'],\n orderBy: { createdAt: 'DESC' },\n },\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ])\n const activityTrend = computeActivityTrend(\n kpiInteractionRows\n .map((interaction) => interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt)\n .map((value) => (value instanceof Date ? value.toISOString() : typeof value === 'string' ? value : ''))\n .filter((value) => value.length > 0),\n )\n const activeDeals = dealLinksForMetrics.filter(\n (deal) => deal.status !== 'won' && deal.status !== 'lost' && deal.status !== 'closed',\n )\n const wonDeals = dealLinksForMetrics.filter((deal) => deal.status === 'won')\n const activeDealsValue = activeDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n const ltvValue = wonDeals.length\n ? wonDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n : null\n const earliestInteractionTime = kpiInteractionRows.reduce<number | null>((earliest, interaction) => {\n const candidate = interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt\n const time = candidate instanceof Date ? candidate.getTime() : new Date(candidate).getTime()\n if (Number.isNaN(time)) return earliest\n if (earliest === null) return time\n return Math.min(earliest, time)\n }, null)\n const companyKpis: CompanyDetailKpiSummary = {\n activeDealsCount: activeDeals.length,\n activeDealsValue: activeDeals.length ? activeDealsValue : null,\n dealCurrency:\n activeDeals[0]?.valueCurrency ??\n dealLinksForMetrics[0]?.valueCurrency ??\n null,\n activityCount,\n activityTrend,\n ltvValue,\n completedDealsCount: wonDeals.length,\n clientTenureYears:\n earliestInteractionTime === null\n ? null\n : Math.floor((Date.now() - earliestInteractionTime) / (365.25 * 86_400_000)),\n }\n const counts = {\n tags: tagAssignments.length + labelAssignments.length,\n comments: commentsCount,\n activities: activityCount,\n interactions: interactionCount,\n todos: todoCount,\n deals: includeDeals ? deals.length : dealLinksForMetrics.length,\n people: peopleCount,\n addresses: addressesCount,\n }\n\n const payload = {\n interactionMode,\n company: {\n id: company.id,\n displayName: company.displayName,\n description: company.description,\n ownerUserId: company.ownerUserId,\n primaryEmail: company.primaryEmail,\n primaryPhone: company.primaryPhone,\n status: company.status,\n lifecycleStage: company.lifecycleStage,\n source: company.source,\n nextInteractionAt: company.nextInteractionAt ? company.nextInteractionAt.toISOString() : null,\n nextInteractionName: company.nextInteractionName,\n nextInteractionRefId: company.nextInteractionRefId,\n nextInteractionIcon: company.nextInteractionIcon,\n nextInteractionColor: company.nextInteractionColor,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n isActive: company.isActive,\n temperature: company.temperature ?? null,\n renewalQuarter: company.renewalQuarter ?? null,\n createdAt: company.createdAt.toISOString(),\n updatedAt: company.updatedAt.toISOString(),\n },\n profile: profile\n ? {\n id: profile.id,\n legalName: profile.legalName,\n brandName: profile.brandName,\n domain: profile.domain,\n websiteUrl: profile.websiteUrl,\n industry: profile.industry,\n sizeBucket: profile.sizeBucket,\n annualRevenue: profile.annualRevenue,\n }\n : null,\n customFields,\n tags: [\n ...serializeTags(tagAssignments),\n ...labelAssignments\n .map((assignment) => {\n const label = assignment.label as CustomerLabel | string | null\n if (!label || typeof label === 'string') return null\n return { id: label.id, label: label.label, color: null }\n })\n .filter((tag): tag is { id: string; label: string; color: null } => tag !== null),\n ],\n addresses: includeAddresses\n ? addresses.map((address) => ({\n id: address.id,\n name: address.name,\n purpose: address.purpose,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2,\n buildingNumber: address.buildingNumber,\n flatNumber: address.flatNumber,\n city: address.city,\n region: address.region,\n postalCode: address.postalCode,\n country: address.country,\n latitude: address.latitude,\n longitude: address.longitude,\n isPrimary: address.isPrimary,\n createdAt: address.createdAt.toISOString(),\n }))\n : [],\n comments: includeComments\n ? comments.map((comment) => {\n const authorInfo = comment.authorUserId ? userMap.get(comment.authorUserId) : null\n return {\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId,\n authorName: comment.authorUserId ? authorInfo?.name ?? null : null,\n authorEmail: comment.authorUserId ? authorInfo?.email ?? null : null,\n dealId: comment.deal ? (typeof comment.deal === 'string' ? comment.deal : comment.deal.id) : null,\n createdAt: comment.createdAt.toISOString(),\n appearanceIcon: comment.appearanceIcon ?? null,\n appearanceColor: comment.appearanceColor ?? null,\n }\n })\n : [],\n activities: includeActivities\n ? (\n interactionFlags.unified\n ? canonicalActivityItems\n : [\n ...activities\n .filter((activity) => !canonicalActivityBridgeIds.has(activity.id))\n .map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject,\n body: activity.body,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n authorUserId: activity.authorUserId,\n authorName: activity.authorUserId ? userMap.get(activity.authorUserId)?.name ?? null : null,\n authorEmail: activity.authorUserId ? userMap.get(activity.authorUserId)?.email ?? null : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n })),\n ...canonicalActivityItems.filter(\n (activity) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === activity.id &&\n interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.occurredAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.occurredAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n interactions: includeInteractions\n ? canonicalInteractions\n : [],\n deals: includeDeals\n ? deals.map((deal) => ({\n id: deal.id,\n title: deal.title,\n status: deal.status,\n pipelineStage: deal.pipelineStage,\n pipelineId: deal.pipelineId ?? null,\n pipelineStageId: deal.pipelineStageId ?? null,\n valueAmount: deal.valueAmount,\n valueCurrency: deal.valueCurrency,\n probability: deal.probability,\n expectedCloseAt: deal.expectedCloseAt ? deal.expectedCloseAt.toISOString() : null,\n ownerUserId: deal.ownerUserId,\n source: deal.source,\n createdAt: deal.createdAt.toISOString(),\n updatedAt: deal.updatedAt.toISOString(),\n }))\n : [],\n todos: includeTodos\n ? (\n interactionFlags.unified\n ? canonicalTodoItems\n : [\n ...todoLinks\n .filter((link) => !canonicalTodoBridgeIds.has(link.todoId))\n .map((link) => {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const key = `${source}:${link.todoId}`\n const detail = todoDetails.get(key)\n return {\n id: link.id,\n todoId: link.todoId,\n todoSource: source,\n createdAt: link.createdAt.toISOString(),\n createdByUserId: link.createdByUserId,\n title: detail?.title ?? null,\n isDone: detail?.isDone ?? null,\n priority: detail?.priority ?? null,\n severity: detail?.severity ?? null,\n description: detail?.description ?? null,\n dueAt: detail?.dueAt ?? null,\n todoOrganizationId: detail?.organizationId ?? null,\n customValues: detail?.customValues ?? null,\n }\n }),\n ...canonicalTodoItems.filter(\n (todo) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === todo.todoId &&\n interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.createdAt).getTime()\n const rightTime = new Date(right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n people: includePeople\n ? relatedPeople.map(({ entity, profile: personProfile, linkedAt }) => ({\n id: entity.id,\n displayName: entity.displayName,\n primaryEmail: entity.primaryEmail ?? null,\n primaryPhone: entity.primaryPhone ?? null,\n status: entity.status ?? null,\n lifecycleStage: entity.lifecycleStage ?? null,\n jobTitle: personProfile?.jobTitle ?? null,\n department: personProfile?.department ?? null,\n createdAt: entity.createdAt.toISOString(),\n organizationId: entity.organizationId,\n source: entity.source ?? null,\n temperature: entity.temperature ?? null,\n linkedAt,\n }))\n : [],\n plannedActivitiesPreview,\n counts,\n kpis: companyKpis,\n viewer: {\n userId: viewerUserId,\n name: viewerUserId ? userMap.get(viewerUserId)?.name ?? null : null,\n email: viewerUserId ? userMap.get(viewerUserId)?.email ?? auth.email ?? null : auth.email ?? null,\n },\n }\n\n if (cache && cacheKey) {\n try {\n await runWithCacheTenant(cacheTenantId, () =>\n cache.set(cacheKey, payload, {\n ttl: COMPANY_DETAIL_CACHE_TTL_MS,\n tags: buildCompanyDetailCacheTags(cacheTenantId, companyScope.organizationId),\n }),\n )\n } catch (err) {\n logger.warn('Failed to set company detail cache', { component: 'companies', err })\n }\n }\n\n return NextResponse.json(payload)\n}\n\nconst companyDetailQuerySchema = z.object({\n include: z\n .string()\n .optional()\n .describe('Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people).'),\n}).passthrough()\n\nconst companyDetailResponseSchema = z.object({\n interactionMode: z.enum(['canonical', 'legacy']),\n company: z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n nextInteractionAt: z.string().nullable().optional(),\n nextInteractionName: z.string().nullable().optional(),\n nextInteractionRefId: z.string().nullable().optional(),\n nextInteractionIcon: z.string().nullable().optional(),\n nextInteractionColor: z.string().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n isActive: z.boolean().optional(),\n temperature: z.string().nullable().optional(),\n renewalQuarter: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n profile: z\n .object({\n id: z.string().uuid(),\n legalName: z.string().nullable().optional(),\n brandName: z.string().nullable().optional(),\n domain: z.string().nullable().optional(),\n websiteUrl: z.string().nullable().optional(),\n industry: z.string().nullable().optional(),\n sizeBucket: z.string().nullable().optional(),\n annualRevenue: z.number().nullable().optional(),\n })\n .nullable(),\n customFields: z.record(z.string(), z.unknown()),\n tags: z.array(\n z.object({\n id: z.string().uuid(),\n label: z.string(),\n color: z.string().nullable().optional(),\n }),\n ),\n addresses: z.array(\n z.object({\n id: z.string().uuid(),\n name: z.string().nullable().optional(),\n purpose: z.string().nullable().optional(),\n addressLine1: z.string().nullable().optional(),\n addressLine2: z.string().nullable().optional(),\n buildingNumber: z.string().nullable().optional(),\n flatNumber: z.string().nullable().optional(),\n city: z.string().nullable().optional(),\n region: z.string().nullable().optional(),\n postalCode: z.string().nullable().optional(),\n country: z.string().nullable().optional(),\n latitude: z.number().nullable().optional(),\n longitude: z.number().nullable().optional(),\n isPrimary: z.boolean().nullable().optional(),\n createdAt: z.string(),\n }),\n ),\n comments: z.array(\n z.object({\n id: z.string().uuid(),\n body: z.string().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n activities: z.array(\n z.object({\n id: z.string().uuid(),\n activityType: z.string(),\n subject: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n interactions: z.array(\n z.object({\n id: z.string().uuid(),\n entityId: z.string().uuid().nullable().optional(),\n interactionType: z.string(),\n title: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n status: z.string(),\n scheduledAt: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n priority: z.number().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n deals: z.array(\n z.object({\n id: z.string().uuid(),\n title: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n pipelineStage: z.string().nullable().optional(),\n valueAmount: z.number().nullable().optional(),\n valueCurrency: z.string().nullable().optional(),\n probability: z.number().nullable().optional(),\n expectedCloseAt: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n todos: z.array(\n z.object({\n id: z.string().uuid(),\n todoId: z.string().uuid(),\n todoSource: z.string(),\n createdAt: z.string(),\n createdByUserId: z.string().uuid().nullable().optional(),\n title: z.string().nullable().optional(),\n isDone: z.boolean().nullable().optional(),\n priority: z.number().nullable().optional(),\n severity: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n dueAt: z.string().nullable().optional(),\n todoOrganizationId: z.string().uuid().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n }),\n ),\n people: z.array(\n z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n jobTitle: z.string().nullable().optional(),\n department: z.string().nullable().optional(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n temperature: z.string().nullable().optional(),\n linkedAt: z.string().nullable().optional(),\n }),\n ),\n viewer: z.object({\n userId: z.string().uuid().nullable(),\n name: z.string().nullable(),\n email: z.string().nullable(),\n }),\n})\n\nconst companyDetailErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Fetch company detail',\n methods: {\n GET: {\n summary: 'Fetch company with related data',\n description: 'Returns a company customer record with optional related resources such as addresses, comments, activities, interactions, deals, todos, and linked people.',\n query: companyDetailQuerySchema,\n responses: [\n { status: 200, description: 'Company detail payload', schema: companyDetailResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid identifier', schema: companyDetailErrorSchema },\n { status: 401, description: 'Unauthorized', schema: companyDetailErrorSchema },\n { status: 403, description: 'Forbidden for tenant/organization scope', schema: companyDetailErrorSchema },\n { status: 404, description: 'Company not found', schema: companyDetailErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerAddress,\n CustomerComment,\n CustomerActivity,\n CustomerTagAssignment,\n CustomerTag,\n CustomerLabelAssignment,\n CustomerLabel,\n CustomerDealCompanyLink,\n CustomerDeal,\n CustomerTodoLink,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n CustomerInteraction,\n} from '../../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n resolveCompanyCustomFieldRouting,\n mergeCompanyCustomFieldValues,\n} from '../../../lib/customFieldRouting'\nimport { isOpenInteractionStatus, TERMINAL_INTERACTION_STATUS_LIST } from '../../../lib/interactionStatus'\nimport {\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n EXAMPLE_TODO_SOURCE,\n CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n mapInteractionRecordToActivitySummary,\n mapInteractionRecordToTodoSummary,\n} from '../../../lib/interactionCompatibility'\nimport { resolveCustomerInteractionFeatureFlags } from '../../../lib/interactionFeatureFlags'\nimport { hydrateCanonicalInteractions } from '../../../lib/interactionReadModel'\nimport { buildEmailVisibilityMikroFilter } from '../../../lib/visibilityFilter'\nimport { resolveCustomerDetailTenantScope } from '../../../lib/detailTenantScope'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../lib/personCompanyLinkTable'\nimport { normalizeCustomerDetailCustomFields } from '../../detailCustomFields'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport { runWithCacheTenant } from '@open-mercato/cache'\nimport {\n buildCollectionTags,\n canonicalizeResourceTag,\n isCrudCacheEnabled,\n resolveCrudCache,\n} from '@open-mercato/shared/lib/crud/cache'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst COMPANY_DETAIL_CACHE_TTL_MS = 60_000\n\n// The customers write commands already invalidate these resource collections via\n// invalidateCrudCache using these exact resourceKind strings. Reusing them as\n// cache tags means the cached detail is flushed by those existing commands with\n// no new wiring (#3664, mirroring #3143). Canonicalize each kind the same way\n// invalidateCrudCache does (camelCase split + lowercase) so the tag shapes match.\nconst COMPANY_DETAIL_CACHE_RESOURCE_KINDS = [\n 'customers.company',\n 'customers.address',\n 'customers.tagAssignment',\n 'customers.labelAssignment',\n 'customers.personCompanyLink',\n 'customers.interaction',\n 'customers.activity',\n] as const\n\nfunction buildCompanyDetailCacheTags(tenantId: string | null, organizationId: string | null): string[] {\n const tags = new Set<string>()\n for (const resourceKind of COMPANY_DETAIL_CACHE_RESOURCE_KINDS) {\n const resource = canonicalizeResourceTag(resourceKind) ?? resourceKind\n for (const tag of buildCollectionTags(resource, tenantId, [organizationId])) {\n tags.add(tag)\n }\n }\n return Array.from(tags)\n}\n\nfunction buildCompanyDetailCacheKey(parts: {\n tenantId: string | null\n organizationId: string | null\n companyId: string\n selectedOrganizationId: string | null\n filterIds: string[] | null\n allowedIds: string[] | null\n isSuperAdmin: boolean\n viewerUserId: string | null\n interactionMode: string\n includeTokens: string[]\n}): string {\n const sortKeys = (values: string[]): string[] =>\n [...values].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))\n const filterIds = parts.filterIds ? sortKeys(parts.filterIds).join(',') : 'all'\n const allowedIds = parts.allowedIds ? sortKeys(parts.allowedIds).join(',') : 'all'\n const includeTokens = sortKeys(parts.includeTokens).join(',')\n return [\n 'customers:companies:detail',\n `tenant:${parts.tenantId ?? 'null'}`,\n `org:${parts.organizationId ?? 'null'}`,\n `company:${parts.companyId}`,\n `selected:${parts.selectedOrganizationId ?? 'null'}`,\n `filter:${filterIds}`,\n `allowed:${allowedIds}`,\n `super:${parts.isSuperAdmin ? '1' : '0'}`,\n `viewer:${parts.viewerUserId ?? 'null'}`,\n `mode:${parts.interactionMode}`,\n `include:${includeTokens}`,\n ].join('|')\n}\n\nfunction parseIncludeParams(request: Request): Set<string> {\n const url = new URL(request.url)\n const raw = url.searchParams.getAll('include')\n const tokens = new Set<string>()\n raw.forEach((entry) => {\n if (!entry) return\n entry\n .split(',')\n .map((part) => part.trim().toLowerCase())\n .filter((part) => part.length > 0)\n .forEach((part) => tokens.add(part))\n })\n return tokens\n}\n\nfunction forbidden(message: string) {\n return NextResponse.json({ error: message }, { status: 403 })\n}\n\nfunction notFound(message: string) {\n return NextResponse.json({ error: message }, { status: 404 })\n}\n\nfunction serializeTags(assignments: CustomerTagAssignment[]): Array<{ id: string; label: string; color: string | null }> {\n return assignments\n .map((assignment) => {\n const tag = assignment.tag as CustomerTag | string | null\n if (!tag || typeof tag === 'string') return null\n return {\n id: tag.id,\n label: tag.label,\n color: tag.color ?? null,\n }\n })\n .filter((tag): tag is { id: string; label: string; color: string | null } => tag !== null)\n}\n\ntype TodoDetail = {\n title: string | null\n isDone: boolean | null\n priority: number | null\n severity: string | null\n description: string | null\n dueAt: string | null\n organizationId: string | null\n customValues: Record<string, unknown> | null\n}\n\nfunction extractTodoTitle(record: Record<string, unknown>): string | null {\n const candidates = ['title', 'subject', 'name', 'summary', 'text', 'description']\n for (const key of candidates) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length > 0) {\n return value.trim()\n }\n }\n return null\n}\n\nfunction parseNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = Number(trimmed)\n if (!Number.isNaN(parsed)) return parsed\n }\n return null\n}\n\nfunction parseDateValue(value: unknown): string | null {\n if (value instanceof Date) {\n const ts = value.getTime()\n return Number.isNaN(ts) ? null : value.toISOString()\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const candidate = new Date(trimmed)\n if (!Number.isNaN(candidate.getTime())) return candidate.toISOString()\n }\n return null\n}\n\nfunction readCustomField(record: Record<string, unknown>, key: string): unknown {\n const custom = record.custom ?? record.customFields ?? record.cf\n if (custom && typeof custom === 'object') {\n const bucket = custom as Record<string, unknown>\n if (key in bucket) return bucket[key]\n }\n return undefined\n}\n\ntype CompanyDetailKpiSummary = {\n activeDealsCount: number\n activeDealsValue: number | null\n dealCurrency: string | null\n activityCount: number\n activityTrend: { value: number; direction: 'up' | 'down' | 'unchanged' } | null\n ltvValue: number | null\n completedDealsCount: number\n clientTenureYears: number | null\n}\n\nfunction parseDealAmount(value: string | number | null | undefined): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = Number(trimmed)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nfunction computeActivityTrend(\n timestamps: string[],\n): { value: number; direction: 'up' | 'down' | 'unchanged' } | null {\n if (!timestamps.length) return null\n const now = Date.now()\n const weekMs = 7 * 86_400_000\n let thisWeek = 0\n let lastWeek = 0\n timestamps.forEach((value) => {\n const time = new Date(value).getTime()\n if (Number.isNaN(time)) return\n const diff = now - time\n if (diff < 0 || diff >= weekMs * 2) return\n if (diff < weekMs) {\n thisWeek += 1\n return\n }\n lastWeek += 1\n })\n if (lastWeek === 0 && thisWeek === 0) return null\n if (lastWeek === 0) return { value: 100, direction: 'up' }\n const pct = ((thisWeek - lastWeek) / lastWeek) * 100\n if (Math.abs(pct) < 0.5) return { value: 0, direction: 'unchanged' }\n return { value: Math.round(Math.abs(pct) * 100) / 100, direction: pct > 0 ? 'up' : 'down' }\n}\n\nasync function resolveTodoDetails(\n queryEngine: QueryEngine,\n links: CustomerTodoLink[],\n tenantId: string | null,\n organizationIds: Array<string | null>,\n): Promise<Map<string, TodoDetail>> {\n const details = new Map<string, TodoDetail>()\n if (!links.length || !tenantId) return details\n\n const scopedOrgIds = organizationIds\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n\n const idsBySource = new Map<string, Set<string>>()\n for (const link of links) {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const id = typeof link.todoId === 'string' && link.todoId.trim().length > 0 ? link.todoId : String(link.todoId ?? '')\n if (!id) continue\n if (!idsBySource.has(source)) idsBySource.set(source, new Set<string>())\n idsBySource.get(source)!.add(id)\n }\n\n for (const [source, idSet] of idsBySource.entries()) {\n const ids = Array.from(idSet)\n if (!ids.length) continue\n try {\n const result = await queryEngine.query<Record<string, unknown>>(source as EntityId, {\n tenantId,\n organizationIds: scopedOrgIds.length > 0 ? scopedOrgIds : undefined,\n filters: { id: { $in: ids } },\n includeCustomFields: ['priority', 'due_at', 'severity', 'description'],\n page: { page: 1, pageSize: Math.max(ids.length, 1) },\n })\n for (const item of result.items ?? []) {\n if (!item || typeof item !== 'object') continue\n const record = item as Record<string, unknown>\n const rawId = typeof record.id === 'string' && record.id.trim().length > 0 ? record.id : String(record.id ?? '')\n if (!rawId) continue\n const title = extractTodoTitle(record)\n const isDone = (() => {\n const direct = parseBooleanFromUnknown(record.is_done)\n if (direct !== null) return direct\n const custom = parseBooleanFromUnknown(readCustomField(record, 'is_done'))\n if (custom !== null) return custom\n const generic = parseBooleanFromUnknown(record.isDone)\n if (generic !== null) return generic\n return parseBooleanFromUnknown(readCustomField(record, 'isDone'))\n })()\n const priority = (() => {\n const candidates = [\n record['cf:priority'],\n record['cf_priority'],\n record.priority,\n readCustomField(record, 'priority'),\n ]\n for (const candidate of candidates) {\n const parsed = parseNumber(candidate)\n if (parsed !== null) return parsed\n }\n return null\n })()\n const severity = (() => {\n const candidates = [\n record['cf:severity'],\n record['cf_severity'],\n record.severity,\n readCustomField(record, 'severity'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const dueAt = (() => {\n const candidates = [\n record['cf:due_at'],\n record['cf_due_at'],\n record.due_at,\n readCustomField(record, 'due_at'),\n record.dueAt,\n readCustomField(record, 'dueAt'),\n ]\n for (const candidate of candidates) {\n const parsed = parseDateValue(candidate)\n if (parsed) return parsed\n }\n return null\n })()\n const organizationId = (() => {\n const candidates = [\n record.organization_id,\n record['cf:organization_id'],\n record['cf_organization_id'],\n record.organizationId,\n readCustomField(record, 'organization_id'),\n readCustomField(record, 'organizationId'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const descriptionValue = (() => {\n const direct = typeof record.description === 'string' ? record.description : null\n if (direct) return direct\n const customDescription = readCustomField(record, 'description')\n if (typeof customDescription === 'string' && customDescription.trim().length > 0) {\n return customDescription.trim()\n }\n return null\n })()\n\n const customValues: Record<string, unknown> = {}\n const assignCustomValue = (key: string, value: unknown) => {\n const trimmedKey = key.trim()\n if (!trimmedKey.length) return\n customValues[trimmedKey] = value === undefined ? null : value\n }\n for (const [rawKey, rawValue] of Object.entries(record)) {\n if (rawKey.startsWith('cf:')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n } else if (rawKey.startsWith('cf_')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n }\n }\n const nestedCustom = record.custom ?? record.customFields ?? record.cf\n if (nestedCustom && typeof nestedCustom === 'object') {\n for (const [nestedKey, nestedValue] of Object.entries(nestedCustom as Record<string, unknown>)) {\n assignCustomValue(nestedKey, nestedValue)\n }\n }\n\n details.set(`${source}:${rawId}`, {\n title,\n isDone,\n priority,\n severity,\n description: descriptionValue,\n dueAt,\n organizationId,\n customValues: Object.keys(customValues).length ? customValues : null,\n })\n }\n } catch (err) {\n logger.warn('customers.companies.detail: failed to resolve todos', { source, err })\n }\n }\n\n return details\n}\n\nexport async function GET(_req: Request, ctx: { params?: { id?: string } }) {\n const auth = await getAuthFromRequest(_req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const parse = paramsSchema.safeParse({ id: ctx.params?.id })\n if (!parse.success) return NextResponse.json({ error: 'Invalid company id' }, { status: 400 })\n\n const includeTokens = parseIncludeParams(_req)\n const includeActivities = includeTokens.has('activities')\n const includeAddresses = includeTokens.has('addresses')\n const includeComments = includeTokens.has('comments') || includeTokens.has('notes')\n const includeDeals = includeTokens.has('deals')\n const includeInteractions = includeTokens.has('interactions')\n const includeTodos = includeTokens.has('todos') || includeTokens.has('tasks')\n const includePeople = includeTokens.has('people')\n const plannedPreviewLimit = 5\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: _req })\n const em = (container.resolve('em') as EntityManager)\n const interactionFlags = await resolveCustomerInteractionFeatureFlags(container, scope?.tenantId ?? auth.tenantId)\n const interactionMode = interactionFlags.unified ? 'canonical' : 'legacy'\n\n const tenantScope = resolveCustomerDetailTenantScope(parse.data.id, 'company', auth)\n if (!tenantScope.allowed) return notFound('Company not found')\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n tenantScope.where,\n { populate: ['companyProfile'] },\n {\n tenantId: auth.tenantId ?? null,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n },\n )\n if (!company) return notFound('Company not found')\n\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: company.organizationId })) {\n return forbidden('Access denied')\n }\n\n const companyScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n\n // Per-user email privacy (CRM email integration): exclude private email\n // interactions owned by other users from every read path that returns\n // customer_interactions. Non-email rows, shared emails, and legacy\n // null-visibility rows pass through. v1 is strict owner-only: there is NO\n // admin bypass \u2014 the filter ignores caller features, and\n // `customers.email.view_private` is reserved (inert) for v2 oversight.\n // Mirrors the people detail route. API-key callers resolve to null\n // (no author match \u2014 shared/non-email rows only).\n const viewerUserId = auth.isApiKey ? null : (auth.sub ?? null)\n const emailVisibilityFilter = buildEmailVisibilityMikroFilter({\n currentUserId: viewerUserId,\n userFeatures: undefined,\n })\n\n // Opt-in cache (#3664): the company existence + org read-access checks above\n // always run, so authorization is never served from cache. Only the expensive\n // detail sweeps below are cached. Key on tenant/org/company + the RBAC scope,\n // viewer (email privacy), interaction mode, and the requested include set.\n const cacheTenantId = companyScope.tenantId\n const cache = isCrudCacheEnabled() ? resolveCrudCache(container) : null\n const cacheKey = cache\n ? buildCompanyDetailCacheKey({\n tenantId: cacheTenantId,\n organizationId: companyScope.organizationId,\n companyId: company.id,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n filterIds: scope?.filterIds ?? null,\n allowedIds: scope?.allowedIds ?? null,\n isSuperAdmin: auth.isSuperAdmin === true,\n viewerUserId,\n interactionMode,\n includeTokens: Array.from(includeTokens),\n })\n : null\n if (cache && cacheKey) {\n const cached = await runWithCacheTenant(cacheTenantId, () => cache.get(cacheKey))\n if (cached) return NextResponse.json(cached)\n }\n\n const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos\n\n // These reads only depend on the resolved company + scope + email visibility\n // filter, so dispatch them together to avoid a server-side request waterfall\n // before the detail surface can render (issue #3203).\n const [profile, addresses, tagAssignments, labelAssignments, comments, canonicalInteractionRows] = await Promise.all([\n company.companyProfile\n ? findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n id: company.companyProfile.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n )\n : findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n entity: company,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n ),\n includeAddresses\n ? findWithDecryption(\n em,\n CustomerAddress,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { isPrimary: 'desc', createdAt: 'desc' } },\n companyScope,\n )\n : Promise.resolve<CustomerAddress[]>([]),\n findWithDecryption(\n em,\n CustomerTagAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['tag'] },\n companyScope,\n ),\n findWithDecryption(\n em,\n CustomerLabelAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['label'] },\n companyScope,\n ),\n includeComments\n ? findWithDecryption(\n em,\n CustomerComment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : Promise.resolve<CustomerComment[]>([]),\n shouldLoadCanonicalInteractions\n ? findWithDecryption(\n em,\n CustomerInteraction,\n interactionFlags.unified\n ? {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }\n : {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'asc', createdAt: 'desc' }, limit: 100 },\n companyScope,\n )\n : Promise.resolve<CustomerInteraction[]>([]),\n ])\n const canonicalActiveInteractions = canonicalInteractionRows.filter((interaction) => !interaction.deletedAt)\n const canonicalInteractions = shouldLoadCanonicalInteractions\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: canonicalActiveInteractions,\n enrich: includeInteractions,\n })\n : []\n\n const plannedPreviewRows =\n canonicalActiveInteractions.length > 0\n ? canonicalActiveInteractions\n .filter((interaction) => isOpenInteractionStatus(interaction.status) && interaction.interactionType !== 'task')\n .sort((left, right) => {\n const leftTime = new Date(left.scheduledAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.scheduledAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return left.id.localeCompare(right.id)\n return leftTime - rightTime\n })\n .slice(0, plannedPreviewLimit)\n : await findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n status: { $nin: [...TERMINAL_INTERACTION_STATUS_LIST] },\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'ASC', createdAt: 'ASC' }, limit: plannedPreviewLimit },\n companyScope,\n )\n const plannedActivitiesPreview = plannedPreviewRows.length\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: plannedPreviewRows,\n enrich: true,\n })\n : []\n\n const activities = includeActivities && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerActivity,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { occurredAt: 'desc', createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n const todoLinks = includeTodos && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerTodoLink,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n\n let todoDetails = new Map<string, TodoDetail>()\n if (includeTodos && !interactionFlags.unified && todoLinks.length) {\n const queryEngine = (container.resolve('queryEngine') as QueryEngine)\n try {\n todoDetails = await resolveTodoDetails(\n queryEngine,\n todoLinks,\n company.tenantId ?? auth.tenantId ?? null,\n [company.organizationId ?? null, ...(scope?.filterIds ?? [])],\n )\n } catch (err) {\n logger.warn('customers.companies.detail: failed to enrich todo links', { err })\n }\n }\n\n const canonicalActivityBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n const canonicalTodoBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n\n const canonicalActivityItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType !== 'task')\n .map((interaction) => mapInteractionRecordToActivitySummary(interaction))\n const canonicalTodoItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType === 'task')\n .map((interaction) => mapInteractionRecordToTodoSummary(interaction))\n\n const authorIds = new Set<string>()\n if (includeActivities) {\n for (const activity of activities) {\n if (activity.authorUserId) authorIds.add(activity.authorUserId)\n }\n }\n if (includeComments) {\n for (const comment of comments) {\n if (comment.authorUserId) authorIds.add(comment.authorUserId)\n }\n }\n if (viewerUserId) authorIds.add(viewerUserId)\n\n let userMap = new Map<string, { name: string | null; email: string | null }>()\n if (authorIds.size) {\n const authorIdList = Array.from(authorIds)\n const users = await findWithDecryption(\n em,\n User,\n {\n id: { $in: authorIdList },\n tenantId: company.tenantId,\n },\n {},\n companyScope,\n )\n userMap = new Map(\n users.map((user) => [\n user.id,\n {\n name: user.name ?? null,\n email: user.email ?? null,\n },\n ])\n )\n }\n\n let deals: CustomerDeal[] = []\n if (includeDeals) {\n const dealLinks = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n deals = dealLinks\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n }\n\n const dealLinksForMetrics = includeDeals\n ? deals\n : (\n await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n )\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n\n let relatedPeople: Array<{\n entity: CustomerEntity\n profile: CustomerPersonProfile | null\n linkedAt: string | null\n }> = []\n if (includePeople) {\n const peopleDecryptionScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n const relatedPeopleById = new Map<\n string,\n { entity: CustomerEntity; profile: CustomerPersonProfile | null; linkedAt: string | null }\n >()\n const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n const companyLinks = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyLinkWhere,\n {\n populate: ['person', 'person.personProfile'],\n orderBy: { isPrimary: 'desc', createdAt: 'asc' },\n },\n peopleDecryptionScope,\n ),\n )\n companyLinks.forEach((link) => {\n const entity = typeof link.person === 'string' ? null : link.person\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n const personProfile =\n entity.personProfile && typeof entity.personProfile !== 'string'\n ? entity.personProfile\n : null\n relatedPeopleById.set(entity.id, {\n entity,\n profile: personProfile,\n linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null,\n })\n })\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n entity: { deletedAt: null },\n },\n { populate: ['entity'] },\n peopleDecryptionScope,\n )\n profiles.forEach((entry) => {\n const entity = entry.entity as CustomerEntity | null\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n if (!relatedPeopleById.has(entity.id)) {\n relatedPeopleById.set(entity.id, {\n entity,\n profile: entry ?? null,\n linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null,\n })\n }\n })\n relatedPeople = Array.from(relatedPeopleById.values())\n }\n\n // Entity custom fields, profile custom fields, and the routing lookup do not\n // depend on each other (profileId is already resolved above), so load them in\n // parallel instead of three sequential awaits (issue #3203).\n const profileId = profile?.id ?? null\n const [entityCustomFieldValues, profileCustomFieldValues, routing] = await Promise.all([\n loadCustomFieldValues({\n em,\n entityId: E.customers.customer_entity,\n recordIds: [company.id],\n tenantIdByRecord: { [company.id]: company.tenantId ?? null },\n organizationIdByRecord: { [company.id]: company.organizationId ?? null },\n tenantFallbacks: [\n company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n }),\n profileId\n ? loadCustomFieldValues({\n em,\n entityId: E.customers.customer_company_profile,\n recordIds: [profileId],\n tenantIdByRecord: { [profileId]: profile?.tenantId ?? null },\n organizationIdByRecord: { [profileId]: profile?.organizationId ?? null },\n tenantFallbacks: [\n profile?.tenantId ?? company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n })\n : Promise.resolve<Record<string, Record<string, unknown>>>({}),\n resolveCompanyCustomFieldRouting(em, company.tenantId ?? null, company.organizationId ?? null),\n ])\n const customFields = normalizeCustomerDetailCustomFields(\n mergeCompanyCustomFieldValues(\n routing,\n entityCustomFieldValues?.[company.id] ?? {},\n profileId ? profileCustomFieldValues?.[profileId] ?? {} : {},\n ),\n )\n\n // The count queries, related-people fallback, and KPI interaction fallback are\n // all independent of each other; dispatch them together rather than awaiting\n // each inline so the response counts/KPIs are assembled in one parallel round\n // instead of a waterfall (issue #3203).\n const peopleCountQuery = includePeople\n ? Promise.resolve(relatedPeople.length)\n : (async () => {\n const peopleLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n return filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n peopleLinkWhere,\n {},\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ).length\n })()\n const [\n activityCount,\n interactionCount,\n todoCount,\n commentsCount,\n addressesCount,\n peopleCount,\n kpiInteractionRows,\n ] = await Promise.all([\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n }),\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }),\n interactionFlags.unified\n ? em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: 'task',\n })\n : em.count(CustomerTodoLink, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeComments\n ? Promise.resolve(comments.length)\n : em.count(CustomerComment, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeAddresses\n ? Promise.resolve(addresses.length)\n : em.count(CustomerAddress, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n peopleCountQuery,\n canonicalActiveInteractions.length\n ? Promise.resolve(canonicalActiveInteractions)\n : findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n },\n {\n fields: ['id', 'occurredAt', 'scheduledAt', 'createdAt'],\n orderBy: { createdAt: 'DESC' },\n },\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ])\n const activityTrend = computeActivityTrend(\n kpiInteractionRows\n .map((interaction) => interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt)\n .map((value) => (value instanceof Date ? value.toISOString() : typeof value === 'string' ? value : ''))\n .filter((value) => value.length > 0),\n )\n const activeDeals = dealLinksForMetrics.filter(\n (deal) => deal.status !== 'won' && deal.status !== 'lost' && deal.status !== 'closed',\n )\n const wonDeals = dealLinksForMetrics.filter((deal) => deal.status === 'won')\n const activeDealsValue = activeDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n const ltvValue = wonDeals.length\n ? wonDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n : null\n const earliestInteractionTime = kpiInteractionRows.reduce<number | null>((earliest, interaction) => {\n const candidate = interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt\n const time = candidate instanceof Date ? candidate.getTime() : new Date(candidate).getTime()\n if (Number.isNaN(time)) return earliest\n if (earliest === null) return time\n return Math.min(earliest, time)\n }, null)\n const companyKpis: CompanyDetailKpiSummary = {\n activeDealsCount: activeDeals.length,\n activeDealsValue: activeDeals.length ? activeDealsValue : null,\n dealCurrency:\n activeDeals[0]?.valueCurrency ??\n dealLinksForMetrics[0]?.valueCurrency ??\n null,\n activityCount,\n activityTrend,\n ltvValue,\n completedDealsCount: wonDeals.length,\n clientTenureYears:\n earliestInteractionTime === null\n ? null\n : Math.floor((Date.now() - earliestInteractionTime) / (365.25 * 86_400_000)),\n }\n const counts = {\n tags: tagAssignments.length + labelAssignments.length,\n comments: commentsCount,\n activities: activityCount,\n interactions: interactionCount,\n todos: todoCount,\n deals: includeDeals ? deals.length : dealLinksForMetrics.length,\n people: peopleCount,\n addresses: addressesCount,\n }\n\n const payload = {\n interactionMode,\n company: {\n id: company.id,\n displayName: company.displayName,\n description: company.description,\n ownerUserId: company.ownerUserId,\n primaryEmail: company.primaryEmail,\n primaryPhone: company.primaryPhone,\n status: company.status,\n lifecycleStage: company.lifecycleStage,\n source: company.source,\n nextInteractionAt: company.nextInteractionAt ? company.nextInteractionAt.toISOString() : null,\n nextInteractionName: company.nextInteractionName,\n nextInteractionRefId: company.nextInteractionRefId,\n nextInteractionIcon: company.nextInteractionIcon,\n nextInteractionColor: company.nextInteractionColor,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n isActive: company.isActive,\n temperature: company.temperature ?? null,\n renewalQuarter: company.renewalQuarter ?? null,\n createdAt: company.createdAt.toISOString(),\n updatedAt: company.updatedAt.toISOString(),\n },\n profile: profile\n ? {\n id: profile.id,\n legalName: profile.legalName,\n brandName: profile.brandName,\n domain: profile.domain,\n websiteUrl: profile.websiteUrl,\n industry: profile.industry,\n sizeBucket: profile.sizeBucket,\n annualRevenue: profile.annualRevenue,\n }\n : null,\n customFields,\n tags: [\n ...serializeTags(tagAssignments),\n ...labelAssignments\n .map((assignment) => {\n const label = assignment.label as CustomerLabel | string | null\n if (!label || typeof label === 'string') return null\n return { id: label.id, label: label.label, color: null }\n })\n .filter((tag): tag is { id: string; label: string; color: null } => tag !== null),\n ],\n addresses: includeAddresses\n ? addresses.map((address) => ({\n id: address.id,\n name: address.name,\n purpose: address.purpose,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2,\n buildingNumber: address.buildingNumber,\n flatNumber: address.flatNumber,\n city: address.city,\n region: address.region,\n postalCode: address.postalCode,\n country: address.country,\n latitude: address.latitude,\n longitude: address.longitude,\n isPrimary: address.isPrimary,\n createdAt: address.createdAt.toISOString(),\n }))\n : [],\n comments: includeComments\n ? comments.map((comment) => {\n const authorInfo = comment.authorUserId ? userMap.get(comment.authorUserId) : null\n return {\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId,\n authorName: comment.authorUserId ? authorInfo?.name ?? null : null,\n authorEmail: comment.authorUserId ? authorInfo?.email ?? null : null,\n dealId: comment.deal ? (typeof comment.deal === 'string' ? comment.deal : comment.deal.id) : null,\n createdAt: comment.createdAt.toISOString(),\n appearanceIcon: comment.appearanceIcon ?? null,\n appearanceColor: comment.appearanceColor ?? null,\n }\n })\n : [],\n activities: includeActivities\n ? (\n interactionFlags.unified\n ? canonicalActivityItems\n : [\n ...activities\n .filter((activity) => !canonicalActivityBridgeIds.has(activity.id))\n .map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject,\n body: activity.body,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n authorUserId: activity.authorUserId,\n authorName: activity.authorUserId ? userMap.get(activity.authorUserId)?.name ?? null : null,\n authorEmail: activity.authorUserId ? userMap.get(activity.authorUserId)?.email ?? null : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n })),\n ...canonicalActivityItems.filter(\n (activity) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === activity.id &&\n interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.occurredAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.occurredAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n interactions: includeInteractions\n ? canonicalInteractions\n : [],\n deals: includeDeals\n ? deals.map((deal) => ({\n id: deal.id,\n title: deal.title,\n status: deal.status,\n pipelineStage: deal.pipelineStage,\n pipelineId: deal.pipelineId ?? null,\n pipelineStageId: deal.pipelineStageId ?? null,\n valueAmount: deal.valueAmount,\n valueCurrency: deal.valueCurrency,\n probability: deal.probability,\n expectedCloseAt: deal.expectedCloseAt ? deal.expectedCloseAt.toISOString() : null,\n ownerUserId: deal.ownerUserId,\n source: deal.source,\n createdAt: deal.createdAt.toISOString(),\n updatedAt: deal.updatedAt.toISOString(),\n }))\n : [],\n todos: includeTodos\n ? (\n interactionFlags.unified\n ? canonicalTodoItems\n : [\n ...todoLinks\n .filter((link) => !canonicalTodoBridgeIds.has(link.todoId))\n .map((link) => {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const key = `${source}:${link.todoId}`\n const detail = todoDetails.get(key)\n return {\n id: link.id,\n todoId: link.todoId,\n todoSource: source,\n createdAt: link.createdAt.toISOString(),\n createdByUserId: link.createdByUserId,\n title: detail?.title ?? null,\n isDone: detail?.isDone ?? null,\n priority: detail?.priority ?? null,\n severity: detail?.severity ?? null,\n description: detail?.description ?? null,\n dueAt: detail?.dueAt ?? null,\n todoOrganizationId: detail?.organizationId ?? null,\n customValues: detail?.customValues ?? null,\n }\n }),\n ...canonicalTodoItems.filter(\n (todo) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === todo.todoId &&\n interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.createdAt).getTime()\n const rightTime = new Date(right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n people: includePeople\n ? relatedPeople.map(({ entity, profile: personProfile, linkedAt }) => ({\n id: entity.id,\n displayName: entity.displayName,\n primaryEmail: entity.primaryEmail ?? null,\n primaryPhone: entity.primaryPhone ?? null,\n status: entity.status ?? null,\n lifecycleStage: entity.lifecycleStage ?? null,\n jobTitle: personProfile?.jobTitle ?? null,\n department: personProfile?.department ?? null,\n createdAt: entity.createdAt.toISOString(),\n organizationId: entity.organizationId,\n source: entity.source ?? null,\n temperature: entity.temperature ?? null,\n linkedAt,\n }))\n : [],\n plannedActivitiesPreview,\n counts,\n kpis: companyKpis,\n viewer: {\n userId: viewerUserId,\n name: viewerUserId ? userMap.get(viewerUserId)?.name ?? null : null,\n email: viewerUserId ? userMap.get(viewerUserId)?.email ?? auth.email ?? null : auth.email ?? null,\n },\n }\n\n if (cache && cacheKey) {\n try {\n await runWithCacheTenant(cacheTenantId, () =>\n cache.set(cacheKey, payload, {\n ttl: COMPANY_DETAIL_CACHE_TTL_MS,\n tags: buildCompanyDetailCacheTags(cacheTenantId, companyScope.organizationId),\n }),\n )\n } catch (err) {\n logger.warn('Failed to set company detail cache', { component: 'companies', err })\n }\n }\n\n return NextResponse.json(payload)\n}\n\nconst companyDetailQuerySchema = z.object({\n include: z\n .string()\n .optional()\n .describe('Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people).'),\n}).passthrough()\n\nconst companyDetailResponseSchema = z.object({\n interactionMode: z.enum(['canonical', 'legacy']),\n company: z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n nextInteractionAt: z.string().nullable().optional(),\n nextInteractionName: z.string().nullable().optional(),\n nextInteractionRefId: z.string().nullable().optional(),\n nextInteractionIcon: z.string().nullable().optional(),\n nextInteractionColor: z.string().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n isActive: z.boolean().optional(),\n temperature: z.string().nullable().optional(),\n renewalQuarter: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n profile: z\n .object({\n id: z.string().uuid(),\n legalName: z.string().nullable().optional(),\n brandName: z.string().nullable().optional(),\n domain: z.string().nullable().optional(),\n websiteUrl: z.string().nullable().optional(),\n industry: z.string().nullable().optional(),\n sizeBucket: z.string().nullable().optional(),\n annualRevenue: z.number().nullable().optional(),\n })\n .nullable(),\n customFields: z.record(z.string(), z.unknown()),\n tags: z.array(\n z.object({\n id: z.string().uuid(),\n label: z.string(),\n color: z.string().nullable().optional(),\n }),\n ),\n addresses: z.array(\n z.object({\n id: z.string().uuid(),\n name: z.string().nullable().optional(),\n purpose: z.string().nullable().optional(),\n addressLine1: z.string().nullable().optional(),\n addressLine2: z.string().nullable().optional(),\n buildingNumber: z.string().nullable().optional(),\n flatNumber: z.string().nullable().optional(),\n city: z.string().nullable().optional(),\n region: z.string().nullable().optional(),\n postalCode: z.string().nullable().optional(),\n country: z.string().nullable().optional(),\n latitude: z.number().nullable().optional(),\n longitude: z.number().nullable().optional(),\n isPrimary: z.boolean().nullable().optional(),\n createdAt: z.string(),\n }),\n ),\n comments: z.array(\n z.object({\n id: z.string().uuid(),\n body: z.string().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n activities: z.array(\n z.object({\n id: z.string().uuid(),\n activityType: z.string(),\n subject: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n interactions: z.array(\n z.object({\n id: z.string().uuid(),\n entityId: z.string().uuid().nullable().optional(),\n interactionType: z.string(),\n title: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n status: z.string(),\n scheduledAt: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n priority: z.number().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n deals: z.array(\n z.object({\n id: z.string().uuid(),\n title: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n pipelineStage: z.string().nullable().optional(),\n valueAmount: z.number().nullable().optional(),\n valueCurrency: z.string().nullable().optional(),\n probability: z.number().nullable().optional(),\n expectedCloseAt: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n todos: z.array(\n z.object({\n id: z.string().uuid(),\n todoId: z.string().uuid(),\n todoSource: z.string(),\n createdAt: z.string(),\n createdByUserId: z.string().uuid().nullable().optional(),\n title: z.string().nullable().optional(),\n isDone: z.boolean().nullable().optional(),\n priority: z.number().nullable().optional(),\n severity: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n dueAt: z.string().nullable().optional(),\n todoOrganizationId: z.string().uuid().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n }),\n ),\n people: z.array(\n z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n jobTitle: z.string().nullable().optional(),\n department: z.string().nullable().optional(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n temperature: z.string().nullable().optional(),\n linkedAt: z.string().nullable().optional(),\n }),\n ),\n viewer: z.object({\n userId: z.string().uuid().nullable(),\n name: z.string().nullable(),\n email: z.string().nullable(),\n }),\n})\n\nconst companyDetailErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Fetch company detail',\n methods: {\n GET: {\n summary: 'Fetch company with related data',\n description: 'Returns a company customer record with optional related resources such as addresses, comments, activities, interactions, deals, todos, and linked people.',\n query: companyDetailQuerySchema,\n responses: [\n { status: 200, description: 'Company detail payload', schema: companyDetailResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid identifier', schema: companyDetailErrorSchema },\n { status: 401, description: 'Unauthorized', schema: companyDetailErrorSchema },\n { status: 403, description: 'Forbidden for tenant/organization scope', schema: companyDetailErrorSchema },\n { status: 404, description: 'Company not found', schema: companyDetailErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -19,7 +19,8 @@ const BUILTIN_DICTIONARY_ROUTE_KINDS = [
19
19
  "industries",
20
20
  "temperature",
21
21
  "renewal-quarters",
22
- "person-company-roles"
22
+ "person-company-roles",
23
+ "interaction-statuses"
23
24
  ];
24
25
  const dictionaryCustomKindSchema = z.string().trim().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Invalid dictionary kind");
25
26
  const dictionaryKindSchema = z.union([
@@ -38,7 +39,8 @@ const KIND_MAP = {
38
39
  industries: "industry",
39
40
  temperature: "temperature",
40
41
  "renewal-quarters": "renewal_quarter",
41
- "person-company-roles": "person_company_role"
42
+ "person-company-roles": "person_company_role",
43
+ "interaction-statuses": "interaction_status"
42
44
  };
43
45
  const paramsSchema = z.object({
44
46
  kind: dictionaryKindSchema
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/api/dictionaries/context.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer, type AppContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport const BUILTIN_DICTIONARY_ROUTE_KINDS = [\n 'statuses',\n 'sources',\n 'lifecycle-stages',\n 'address-types',\n 'activity-types',\n 'deal-statuses',\n 'pipeline-stages',\n 'job-titles',\n 'industries',\n 'temperature',\n 'renewal-quarters',\n 'person-company-roles',\n] as const\n\ntype BuiltinDictionaryRouteKind = (typeof BUILTIN_DICTIONARY_ROUTE_KINDS)[number]\n\nconst dictionaryCustomKindSchema = z\n .string()\n .trim()\n .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'Invalid dictionary kind')\n\nexport const dictionaryKindSchema = z.union([\n z.enum(BUILTIN_DICTIONARY_ROUTE_KINDS),\n dictionaryCustomKindSchema,\n])\n\nexport type DictionaryRouteParam = z.infer<typeof dictionaryKindSchema>\nexport type DictionaryEntityKind = string\n\nconst KIND_MAP: Record<BuiltinDictionaryRouteKind, DictionaryEntityKind> = {\n statuses: 'status',\n sources: 'source',\n 'lifecycle-stages': 'lifecycle_stage',\n 'address-types': 'address_type',\n 'activity-types': 'activity_type',\n 'deal-statuses': 'deal_status',\n 'pipeline-stages': 'pipeline_stage',\n 'job-titles': 'job_title',\n industries: 'industry',\n temperature: 'temperature',\n 'renewal-quarters': 'renewal_quarter',\n 'person-company-roles': 'person_company_role',\n}\n\nexport const paramsSchema = z.object({\n kind: dictionaryKindSchema,\n})\n\nexport type DictionaryRouteContext = {\n auth: Awaited<ReturnType<typeof getAuthFromRequest>>\n translate: (key: string, fallback?: string) => string\n em: EntityManager\n organizationId: string | null\n tenantId: string\n readableOrganizationIds: string[]\n cache?: CacheStrategy\n container: AppContainer\n ctx: CommandRuntimeContext\n}\n\nexport function resolveDictionaryActorId(\n auth: Awaited<ReturnType<typeof getAuthFromRequest>>,\n): string {\n if (auth && typeof auth.sub === 'string' && auth.sub.trim().length > 0) return auth.sub\n if (auth && typeof auth.userId === 'string' && auth.userId.trim().length > 0) return auth.userId\n if (auth && typeof auth.keyId === 'string' && auth.keyId.trim().length > 0) return auth.keyId\n return 'system'\n}\n\nexport function mapDictionaryKind(kind: string | undefined) {\n const parsed = paramsSchema.parse({ kind })\n const mappedKind = Object.prototype.hasOwnProperty.call(KIND_MAP, parsed.kind)\n ? KIND_MAP[parsed.kind as BuiltinDictionaryRouteKind]\n : parsed.kind\n return {\n kind: parsed.kind,\n mappedKind,\n }\n}\n\nexport async function resolveDictionaryRouteContext(\n req: Request,\n options?: { selectedId?: string | null },\n): Promise<DictionaryRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n\n const scope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request: req,\n selectedId: options?.selectedId,\n })\n const em = (container.resolve('em') as EntityManager)\n const tenantId = scope?.tenantId ?? auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n\n const normalizeId = (value: unknown): string | null => {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n }\n\n const candidateIds = new Set<string>()\n const pushCandidate = (value: unknown) => {\n const normalized = normalizeId(value)\n if (normalized) candidateIds.add(normalized)\n }\n\n pushCandidate(organizationId)\n pushCandidate(auth.orgId ?? null)\n if (Array.isArray(scope?.filterIds)) {\n for (const id of scope.filterIds) pushCandidate(id)\n }\n if (Array.isArray(scope?.allowedIds)) {\n for (const id of scope.allowedIds) pushCandidate(id)\n }\n\n let cache: CacheStrategy | undefined\n try {\n cache = (container.resolve('cache') as CacheStrategy)\n } catch {}\n\n const readableOrganizationIds = new Set<string>()\n try {\n const shouldLoadAll = candidateIds.size === 0\n const organizations = await em.find(\n Organization,\n {\n tenant: tenantId as any,\n deletedAt: null,\n ...(shouldLoadAll ? {} : { id: { $in: Array.from(candidateIds) } }),\n } as any,\n { fields: ['id', 'ancestorIds'] },\n )\n for (const organization of organizations) {\n const id = normalizeId(organization.id)\n if (id) readableOrganizationIds.add(id)\n if (Array.isArray(organization.ancestorIds)) {\n for (const ancestorId of organization.ancestorIds) {\n const normalized = normalizeId(ancestorId)\n if (normalized) readableOrganizationIds.add(normalized)\n }\n }\n }\n if (!shouldLoadAll && readableOrganizationIds.size === 0) {\n for (const id of candidateIds) readableOrganizationIds.add(id)\n }\n } catch (err) {\n logger.warn('Failed to resolve ancestor organizations', { component: 'dictionaries.context', err })\n for (const id of candidateIds) readableOrganizationIds.add(id)\n }\n\n const commandContext: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n return {\n auth,\n translate,\n em,\n organizationId,\n tenantId,\n readableOrganizationIds: Array.from(readableOrganizationIds),\n cache,\n container,\n ctx: commandContext,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer, type AppContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nexport const BUILTIN_DICTIONARY_ROUTE_KINDS = [\n 'statuses',\n 'sources',\n 'lifecycle-stages',\n 'address-types',\n 'activity-types',\n 'deal-statuses',\n 'pipeline-stages',\n 'job-titles',\n 'industries',\n 'temperature',\n 'renewal-quarters',\n 'person-company-roles',\n 'interaction-statuses',\n] as const\n\ntype BuiltinDictionaryRouteKind = (typeof BUILTIN_DICTIONARY_ROUTE_KINDS)[number]\n\nconst dictionaryCustomKindSchema = z\n .string()\n .trim()\n .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'Invalid dictionary kind')\n\nexport const dictionaryKindSchema = z.union([\n z.enum(BUILTIN_DICTIONARY_ROUTE_KINDS),\n dictionaryCustomKindSchema,\n])\n\nexport type DictionaryRouteParam = z.infer<typeof dictionaryKindSchema>\nexport type DictionaryEntityKind = string\n\nconst KIND_MAP: Record<BuiltinDictionaryRouteKind, DictionaryEntityKind> = {\n statuses: 'status',\n sources: 'source',\n 'lifecycle-stages': 'lifecycle_stage',\n 'address-types': 'address_type',\n 'activity-types': 'activity_type',\n 'deal-statuses': 'deal_status',\n 'pipeline-stages': 'pipeline_stage',\n 'job-titles': 'job_title',\n industries: 'industry',\n temperature: 'temperature',\n 'renewal-quarters': 'renewal_quarter',\n 'person-company-roles': 'person_company_role',\n 'interaction-statuses': 'interaction_status',\n}\n\nexport const paramsSchema = z.object({\n kind: dictionaryKindSchema,\n})\n\nexport type DictionaryRouteContext = {\n auth: Awaited<ReturnType<typeof getAuthFromRequest>>\n translate: (key: string, fallback?: string) => string\n em: EntityManager\n organizationId: string | null\n tenantId: string\n readableOrganizationIds: string[]\n cache?: CacheStrategy\n container: AppContainer\n ctx: CommandRuntimeContext\n}\n\nexport function resolveDictionaryActorId(\n auth: Awaited<ReturnType<typeof getAuthFromRequest>>,\n): string {\n if (auth && typeof auth.sub === 'string' && auth.sub.trim().length > 0) return auth.sub\n if (auth && typeof auth.userId === 'string' && auth.userId.trim().length > 0) return auth.userId\n if (auth && typeof auth.keyId === 'string' && auth.keyId.trim().length > 0) return auth.keyId\n return 'system'\n}\n\nexport function mapDictionaryKind(kind: string | undefined) {\n const parsed = paramsSchema.parse({ kind })\n const mappedKind = Object.prototype.hasOwnProperty.call(KIND_MAP, parsed.kind)\n ? KIND_MAP[parsed.kind as BuiltinDictionaryRouteKind]\n : parsed.kind\n return {\n kind: parsed.kind,\n mappedKind,\n }\n}\n\nexport async function resolveDictionaryRouteContext(\n req: Request,\n options?: { selectedId?: string | null },\n): Promise<DictionaryRouteContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('customers.errors.unauthorized', 'Unauthorized') })\n }\n\n const scope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request: req,\n selectedId: options?.selectedId,\n })\n const em = (container.resolve('em') as EntityManager)\n const tenantId = scope?.tenantId ?? auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n\n const normalizeId = (value: unknown): string | null => {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n }\n\n const candidateIds = new Set<string>()\n const pushCandidate = (value: unknown) => {\n const normalized = normalizeId(value)\n if (normalized) candidateIds.add(normalized)\n }\n\n pushCandidate(organizationId)\n pushCandidate(auth.orgId ?? null)\n if (Array.isArray(scope?.filterIds)) {\n for (const id of scope.filterIds) pushCandidate(id)\n }\n if (Array.isArray(scope?.allowedIds)) {\n for (const id of scope.allowedIds) pushCandidate(id)\n }\n\n let cache: CacheStrategy | undefined\n try {\n cache = (container.resolve('cache') as CacheStrategy)\n } catch {}\n\n const readableOrganizationIds = new Set<string>()\n try {\n const shouldLoadAll = candidateIds.size === 0\n const organizations = await em.find(\n Organization,\n {\n tenant: tenantId as any,\n deletedAt: null,\n ...(shouldLoadAll ? {} : { id: { $in: Array.from(candidateIds) } }),\n } as any,\n { fields: ['id', 'ancestorIds'] },\n )\n for (const organization of organizations) {\n const id = normalizeId(organization.id)\n if (id) readableOrganizationIds.add(id)\n if (Array.isArray(organization.ancestorIds)) {\n for (const ancestorId of organization.ancestorIds) {\n const normalized = normalizeId(ancestorId)\n if (normalized) readableOrganizationIds.add(normalized)\n }\n }\n }\n if (!shouldLoadAll && readableOrganizationIds.size === 0) {\n for (const id of candidateIds) readableOrganizationIds.add(id)\n }\n } catch (err) {\n logger.warn('Failed to resolve ancestor organizations', { component: 'dictionaries.context', err })\n for (const id of candidateIds) readableOrganizationIds.add(id)\n }\n\n const commandContext: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n return {\n auth,\n translate,\n em,\n organizationId,\n tenantId,\n readableOrganizationIds: Array.from(readableOrganizationIds),\n cache,\n container,\n ctx: commandContext,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -8,6 +8,7 @@ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/d
8
8
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
9
9
  import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
10
10
  import { CustomerInteraction } from "../../../data/entities.js";
11
+ import { TERMINAL_INTERACTION_STATUS_LIST } from "../../../lib/interactionStatus.js";
11
12
  import { createLogger } from "@open-mercato/shared/lib/logger";
12
13
  const logger = createLogger("customers");
13
14
  const querySchema = z.object({
@@ -80,7 +81,7 @@ async function GET(req) {
80
81
  const checkUserId = query.userId ?? auth.userId;
81
82
  const em = container.resolve("em").fork();
82
83
  const kysely = em.getKysely();
83
- let baseQuery = kysely.selectFrom("customer_interactions").select(["id", "scheduled_at", "duration_minutes", "interaction_type"]).where("tenant_id", "=", auth.tenantId).where("status", "=", "planned").where("scheduled_at", "is not", null).where("deleted_at", "is", null);
84
+ let baseQuery = kysely.selectFrom("customer_interactions").select(["id", "scheduled_at", "duration_minutes", "interaction_type"]).where("tenant_id", "=", auth.tenantId).where("status", "not in", [...TERMINAL_INTERACTION_STATUS_LIST]).where("scheduled_at", "is not", null).where("deleted_at", "is", null);
84
85
  if (organizationIds.length === 1) {
85
86
  baseQuery = baseQuery.where("organization_id", "=", organizationIds[0]);
86
87
  } else if (organizationIds.length > 1) {