@open-mercato/core 0.4.6-develop-2ba4e02ffb → 0.4.6-develop-15c18897fc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/catalog/migrations/Migration20251116191744.js +4 -4
- package/dist/modules/catalog/migrations/Migration20251116191744.js.map +1 -1
- package/dist/modules/customers/api/people/[id]/route.js +4 -2
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/cli.js +1 -1
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/people.js +15 -0
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +1 -1
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/catalog/migrations/Migration20251116191744.ts +4 -4
- package/src/modules/customers/api/people/[id]/route.ts +2 -0
- package/src/modules/customers/cli.ts +2 -1
- package/src/modules/customers/commands/people.ts +9 -0
- package/src/modules/query_index/lib/coverage.ts +2 -1
|
@@ -493,6 +493,21 @@ const updatePersonCommand = {
|
|
|
493
493
|
if (parsed.companyEntityId !== void 0) {
|
|
494
494
|
profile.company = await resolveCompanyReference(em, parsed.companyEntityId, record.organizationId, record.tenantId);
|
|
495
495
|
}
|
|
496
|
+
const profileFieldsUpdated = [
|
|
497
|
+
parsed.firstName,
|
|
498
|
+
parsed.lastName,
|
|
499
|
+
parsed.preferredName,
|
|
500
|
+
parsed.jobTitle,
|
|
501
|
+
parsed.department,
|
|
502
|
+
parsed.seniority,
|
|
503
|
+
parsed.timezone,
|
|
504
|
+
parsed.linkedInUrl,
|
|
505
|
+
parsed.twitterUrl,
|
|
506
|
+
parsed.companyEntityId
|
|
507
|
+
].some((v) => v !== void 0);
|
|
508
|
+
if (profileFieldsUpdated) {
|
|
509
|
+
record.updatedAt = /* @__PURE__ */ new Date();
|
|
510
|
+
}
|
|
496
511
|
if (parsed.displayName !== void 0) {
|
|
497
512
|
const nextDisplayName = parsed.displayName.trim();
|
|
498
513
|
if (!nextDisplayName) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/commands/people.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerAddress,\n CustomerComment,\n CustomerActivity,\n CustomerDeal,\n CustomerDealPersonLink,\n CustomerTodoLink,\n CustomerEntity,\n CustomerPersonProfile,\n CustomerTagAssignment,\n} from '../data/entities'\nimport { resolvePersonCustomFieldRouting, CUSTOMER_ENTITY_ID, PERSON_ENTITY_ID } from '../lib/customFieldRouting'\nimport {\n personCreateSchema,\n personUpdateSchema,\n type PersonCreateInput,\n type PersonUpdateInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n assertFound,\n syncEntityTags,\n loadEntityTagIds,\n ensureDictionaryEntry,\n emitQueryIndexDeleteEvents,\n emitQueryIndexUpsertEvents,\n type QueryIndexEventEntry,\n} from './shared'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\ntype PersonAddressSnapshot = {\n id: string\n name: string | null\n purpose: string | null\n addressLine1: string\n addressLine2: string | null\n city: string | null\n region: string | null\n postalCode: string | null\n country: string | null\n latitude: number | null\n longitude: number | null\n isPrimary: boolean\n}\n\ntype PersonCommentSnapshot = {\n id: string\n body: string\n authorUserId: string | null\n dealId: string | null\n createdAt: Date\n updatedAt: Date\n deletedAt: Date | null\n appearanceIcon: string | null\n appearanceColor: string | null\n}\n\ntype PersonActivitySnapshot = {\n id: string\n activityType: string\n subject: string | null\n body: string | null\n occurredAt: Date | null\n authorUserId: string | null\n appearanceIcon: string | null\n appearanceColor: string | null\n dealId: string | null\n createdAt: Date\n updatedAt: Date\n}\n\ntype PersonTodoSnapshot = {\n id: string\n todoId: string\n todoSource: string\n createdAt: Date\n createdByUserId: string | null\n}\n\ntype PersonSnapshot = {\n entity: {\n id: string\n organizationId: string\n tenantId: string\n displayName: string\n description: string | null\n ownerUserId: string | null\n primaryEmail: string | null\n primaryPhone: string | null\n status: string | null\n lifecycleStage: string | null\n source: string | null\n nextInteractionAt: Date | null\n nextInteractionName: string | null\n nextInteractionRefId: string | null\n nextInteractionIcon: string | null\n nextInteractionColor: string | null\n isActive: boolean\n }\n profile: {\n id: string\n firstName: string | null\n lastName: string | null\n preferredName: string | null\n jobTitle: string | null\n department: string | null\n seniority: string | null\n timezone: string | null\n linkedInUrl: string | null\n twitterUrl: string | null\n companyEntityId: string | null\n }\n tagIds: string[]\n addresses: PersonAddressSnapshot[]\n comments: PersonCommentSnapshot[]\n custom?: Record<string, unknown>\n deals: Array<{\n id: string\n dealId: string\n participantRole: string | null\n createdAt: Date\n }>\n activities: PersonActivitySnapshot[]\n todos: PersonTodoSnapshot[]\n}\n\ntype PersonUndoPayload = {\n before?: PersonSnapshot | null\n after?: PersonSnapshot | null\n}\n\nconst personCrudIndexer: CrudIndexerConfig<CustomerEntity> = {\n entityType: E.customers.customer_person_profile,\n}\n\nconst personCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'person',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nfunction normalizeOptionalString(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nfunction normalizeHexColor(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim().toLowerCase()\n return /^#([0-9a-f]{6})$/.test(trimmed) ? trimmed : null\n}\n\nfunction normalizeEmail(value: string | null | undefined): string | null {\n const normalized = normalizeOptionalString(value)\n return normalized ? normalized.toLowerCase() : null\n}\n\nfunction serializePersonSnapshot(\n entity: CustomerEntity,\n profile: CustomerPersonProfile,\n tagIds: string[],\n addresses: CustomerAddress[],\n comments: CustomerComment[],\n deals: CustomerDealPersonLink[],\n activities: CustomerActivity[],\n todoLinks: CustomerTodoLink[],\n custom?: Record<string, unknown>\n): PersonSnapshot {\n return {\n entity: {\n id: entity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n displayName: entity.displayName,\n description: entity.description ?? null,\n ownerUserId: entity.ownerUserId ?? null,\n primaryEmail: entity.primaryEmail ?? null,\n primaryPhone: entity.primaryPhone ?? null,\n status: entity.status ?? null,\n lifecycleStage: entity.lifecycleStage ?? null,\n source: entity.source ?? null,\n nextInteractionAt: entity.nextInteractionAt ?? null,\n nextInteractionName: entity.nextInteractionName ?? null,\n nextInteractionRefId: entity.nextInteractionRefId ?? null,\n nextInteractionIcon: entity.nextInteractionIcon ?? null,\n nextInteractionColor: entity.nextInteractionColor ?? null,\n isActive: entity.isActive,\n },\n profile: {\n id: profile.id,\n firstName: profile.firstName ?? null,\n lastName: profile.lastName ?? null,\n preferredName: profile.preferredName ?? null,\n jobTitle: profile.jobTitle ?? null,\n department: profile.department ?? null,\n seniority: profile.seniority ?? null,\n timezone: profile.timezone ?? null,\n linkedInUrl: profile.linkedInUrl ?? null,\n twitterUrl: profile.twitterUrl ?? null,\n companyEntityId: profile.company\n ? typeof profile.company === 'string'\n ? profile.company\n : profile.company.id\n : null,\n },\n tagIds,\n addresses: addresses.map((address) => ({\n id: address.id,\n name: address.name ?? null,\n purpose: address.purpose ?? null,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2 ?? null,\n city: address.city ?? null,\n region: address.region ?? null,\n postalCode: address.postalCode ?? null,\n country: address.country ?? null,\n latitude: address.latitude ?? null,\n longitude: address.longitude ?? null,\n isPrimary: address.isPrimary,\n })),\n comments: comments.map((comment) => ({\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId ?? null,\n dealId: comment.deal\n ? typeof comment.deal === 'string'\n ? comment.deal\n : comment.deal.id\n : null,\n createdAt: comment.createdAt,\n updatedAt: comment.updatedAt,\n deletedAt: comment.deletedAt ?? null,\n appearanceIcon: comment.appearanceIcon ?? null,\n appearanceColor: comment.appearanceColor ?? null,\n })),\n deals: deals\n .filter((link) => link.deal)\n .map((link) => ({\n id: link.id,\n dealId: link.deal.id,\n participantRole: link.participantRole ?? null,\n createdAt: link.createdAt,\n })),\n activities: activities.map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: activity.occurredAt ?? null,\n authorUserId: activity.authorUserId ?? null,\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n dealId: activity.deal\n ? typeof activity.deal === 'string'\n ? activity.deal\n : activity.deal.id\n : null,\n createdAt: activity.createdAt,\n updatedAt: activity.updatedAt,\n })),\n todos: todoLinks.map((todo) => ({\n id: todo.id,\n todoId: todo.todoId,\n todoSource: todo.todoSource,\n createdAt: todo.createdAt,\n createdByUserId: todo.createdByUserId ?? null,\n })),\n custom,\n }\n}\n\nasync function loadPersonSnapshot(em: EntityManager, entityId: string): Promise<PersonSnapshot | null> {\n const entity = await em.findOne(CustomerEntity, { id: entityId, deletedAt: null })\n if (!entity || entity.kind !== 'person') return null\n const profile = await findOneWithDecryption(\n em,\n CustomerPersonProfile,\n { entity: entity },\n { populate: ['company'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n if (!profile) return null\n const tagIds = await loadEntityTagIds(em, entity)\n const addresses = await em.find(CustomerAddress, { entity }, { orderBy: { createdAt: 'asc' } })\n const comments = await findWithDecryption(\n em,\n CustomerComment,\n { entity },\n { orderBy: { createdAt: 'asc' }, populate: ['deal'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n const deals = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n { person: entity },\n { orderBy: { createdAt: 'asc' }, populate: ['deal'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n const activities = await findWithDecryption(\n em,\n CustomerActivity,\n { entity },\n { orderBy: { createdAt: 'asc' }, populate: ['deal'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n const todoLinks = await em.find(CustomerTodoLink, { entity }, { orderBy: { createdAt: 'asc' } })\n const entityCustom = await loadCustomFieldSnapshot(em, {\n entityId: CUSTOMER_ENTITY_ID,\n recordId: entity.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n const profileCustom = await loadCustomFieldSnapshot(em, {\n entityId: PERSON_ENTITY_ID,\n recordId: profile.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n const routing = await resolvePersonCustomFieldRouting(em, entity.tenantId, entity.organizationId)\n const custom: Record<string, unknown> = { ...entityCustom }\n for (const [key, value] of Object.entries(profileCustom)) {\n const target = routing.get(key)\n if (target === CUSTOMER_ENTITY_ID && Object.prototype.hasOwnProperty.call(custom, key)) continue\n custom[key] = value\n }\n return serializePersonSnapshot(entity, profile, tagIds, addresses, comments, deals, activities, todoLinks, custom)\n}\n\nasync function resolveCompanyReference(\n em: EntityManager,\n companyId: string | null | undefined,\n organizationId: string,\n tenantId: string\n): Promise<CustomerEntity | null> {\n if (!companyId) return null\n const company = await em.findOne(CustomerEntity, { id: companyId, kind: 'company', deletedAt: null })\n if (!company) {\n throw new CrudHttpError(400, { error: 'Company not found' })\n }\n if (company.organizationId !== organizationId || company.tenantId !== tenantId) {\n throw new CrudHttpError(403, { error: 'Cannot link person to company outside current scope' })\n }\n return company\n}\n\nasync function setCustomFieldsForPerson(\n ctx: CommandRuntimeContext,\n entityId: string,\n profileId: string,\n organizationId: string,\n tenantId: string,\n values: Record<string, unknown>\n): Promise<void> {\n if (!values || !Object.keys(values).length) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const routing = await resolvePersonCustomFieldRouting(em, tenantId, organizationId)\n const entityScoped: Record<string, unknown> = {}\n const profileScoped: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(values)) {\n const target = routing.get(key) ?? PERSON_ENTITY_ID\n if (target === CUSTOMER_ENTITY_ID) entityScoped[key] = value\n else profileScoped[key] = value\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n if (Object.keys(entityScoped).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: CUSTOMER_ENTITY_ID,\n recordId: entityId,\n organizationId,\n tenantId,\n values: entityScoped,\n notify: true,\n })\n }\n if (Object.keys(profileScoped).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: PERSON_ENTITY_ID,\n recordId: profileId,\n organizationId,\n tenantId,\n values: profileScoped,\n notify: true,\n })\n }\n}\n\nconst createPersonCommand: CommandHandler<PersonCreateInput, { entityId: string; personId: string }> = {\n id: 'customers.people.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(personCreateSchema, rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const firstName = parsed.firstName?.trim() ?? ''\n const lastName = parsed.lastName?.trim() ?? ''\n const description = normalizeOptionalString(parsed.description)\n const primaryEmail = normalizeEmail(parsed.primaryEmail)\n const primaryPhone = normalizeOptionalString(parsed.primaryPhone)\n const status = normalizeOptionalString(parsed.status)\n const lifecycleStage = normalizeOptionalString(parsed.lifecycleStage)\n const source = normalizeOptionalString(parsed.source)\n const preferredName = normalizeOptionalString(parsed.preferredName)\n const jobTitle = normalizeOptionalString(parsed.jobTitle)\n const department = normalizeOptionalString(parsed.department)\n const seniority = normalizeOptionalString(parsed.seniority)\n const timezone = normalizeOptionalString(parsed.timezone)\n const linkedInUrl = normalizeOptionalString(parsed.linkedInUrl)\n const twitterUrl = normalizeOptionalString(parsed.twitterUrl)\n const displayName = parsed.displayName?.trim() ?? ''\n const nextInteractionName = parsed.nextInteraction?.name ? parsed.nextInteraction.name.trim() : null\n const nextInteractionRefId = normalizeOptionalString(parsed.nextInteraction?.refId)\n const nextInteractionIcon = normalizeOptionalString(parsed.nextInteraction?.icon)\n const nextInteractionColor = normalizeHexColor(parsed.nextInteraction?.color)\n if (!firstName || !lastName) {\n throw new CrudHttpError(400, { error: 'First and last name are required' })\n }\n if (!displayName) {\n throw new CrudHttpError(400, { error: 'Display name is required' })\n }\n\n const entity = em.create(CustomerEntity, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n kind: 'person',\n displayName,\n description,\n ownerUserId: parsed.ownerUserId ?? null,\n primaryEmail,\n primaryPhone,\n status,\n lifecycleStage,\n source,\n nextInteractionAt: parsed.nextInteraction?.at ?? null,\n nextInteractionName,\n nextInteractionRefId,\n nextInteractionIcon,\n nextInteractionColor,\n isActive: parsed.isActive ?? true,\n })\n\n const company = await resolveCompanyReference(em, parsed.companyEntityId ?? null, parsed.organizationId, parsed.tenantId)\n\n const profile = em.create(CustomerPersonProfile, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n entity,\n firstName,\n lastName,\n preferredName,\n jobTitle,\n department,\n seniority,\n timezone,\n linkedInUrl,\n twitterUrl,\n company,\n })\n\n em.persist(entity)\n em.persist(profile)\n if (status) {\n await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'status',\n value: status,\n })\n }\n if (jobTitle) {\n await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'job_title',\n value: jobTitle,\n })\n }\n if (source) {\n await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'source',\n value: source,\n })\n }\n await em.flush()\n\n const tenantId = entity.tenantId\n const organizationId = entity.organizationId\n await syncEntityTags(em, entity, parsed.tags)\n await em.flush()\n await setCustomFieldsForPerson(ctx, entity.id, profile.id, organizationId, tenantId, custom)\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity,\n identifiers: {\n id: profile.id ?? entity.id,\n tenantId,\n organizationId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n return { entityId: entity.id, personId: profile.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadPersonSnapshot(em, result.entityId)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const snapshot = snapshots.after as PersonSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.people.create', 'Create person'),\n resourceKind: 'customers.person',\n resourceId: result.entityId,\n tenantId: snapshot?.entity.tenantId ?? null,\n organizationId: snapshot?.entity.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot,\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PersonUndoPayload>(logEntry) ?? null\n const entityId = logEntry?.resourceId ?? payload?.after?.entity.id ?? null\n if (!entityId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entity = await em.findOne(CustomerEntity, { id: entityId })\n if (!entity) return\n const profile = await em.findOne(CustomerPersonProfile, { entity })\n await em.nativeDelete(CustomerTagAssignment, { entity })\n if (profile) {\n await em.remove(profile).flush()\n }\n await em.remove(entity).flush()\n },\n}\n\nconst updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string }> = {\n id: 'customers.people.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(personUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPersonSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(personUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entity = await em.findOne(CustomerEntity, { id: parsed.id, deletedAt: null })\n const record = assertFound(entity, 'Person not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const profile = await em.findOne(CustomerPersonProfile, { entity: record })\n if (!profile) throw new CrudHttpError(404, { error: 'Person profile not found' })\n\n if (parsed.description !== undefined) record.description = normalizeOptionalString(parsed.description)\n if (parsed.ownerUserId !== undefined) record.ownerUserId = parsed.ownerUserId ?? null\n if (parsed.primaryEmail !== undefined) record.primaryEmail = normalizeEmail(parsed.primaryEmail)\n if (parsed.primaryPhone !== undefined) record.primaryPhone = normalizeOptionalString(parsed.primaryPhone)\n if (parsed.status !== undefined) {\n const normalizedStatus = normalizeOptionalString(parsed.status)\n record.status = normalizedStatus\n if (normalizedStatus) {\n await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'status',\n value: normalizedStatus,\n })\n }\n }\n if (parsed.lifecycleStage !== undefined) record.lifecycleStage = normalizeOptionalString(parsed.lifecycleStage)\n if (parsed.source !== undefined) {\n const normalizedSource = normalizeOptionalString(parsed.source)\n record.source = normalizedSource\n if (normalizedSource) {\n await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'source',\n value: normalizedSource,\n })\n }\n }\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive\n if (parsed.nextInteraction) {\n record.nextInteractionAt = parsed.nextInteraction.at\n record.nextInteractionName = parsed.nextInteraction.name.trim()\n record.nextInteractionRefId = normalizeOptionalString(parsed.nextInteraction.refId) ?? null\n record.nextInteractionIcon = normalizeOptionalString(parsed.nextInteraction.icon)\n record.nextInteractionColor = normalizeHexColor(parsed.nextInteraction.color)\n } else if (parsed.nextInteraction === null) {\n record.nextInteractionAt = null\n record.nextInteractionName = null\n record.nextInteractionRefId = null\n record.nextInteractionIcon = null\n record.nextInteractionColor = null\n }\n\n if (parsed.firstName !== undefined) profile.firstName = normalizeOptionalString(parsed.firstName)\n if (parsed.lastName !== undefined) profile.lastName = normalizeOptionalString(parsed.lastName)\n if (parsed.preferredName !== undefined) profile.preferredName = normalizeOptionalString(parsed.preferredName)\n if (parsed.jobTitle !== undefined) {\n const normalizedJobTitle = normalizeOptionalString(parsed.jobTitle)\n profile.jobTitle = normalizedJobTitle\n if (normalizedJobTitle) {\n await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'job_title',\n value: normalizedJobTitle,\n })\n }\n }\n if (parsed.department !== undefined) profile.department = normalizeOptionalString(parsed.department)\n if (parsed.seniority !== undefined) profile.seniority = normalizeOptionalString(parsed.seniority)\n if (parsed.timezone !== undefined) profile.timezone = normalizeOptionalString(parsed.timezone)\n if (parsed.linkedInUrl !== undefined) profile.linkedInUrl = normalizeOptionalString(parsed.linkedInUrl)\n if (parsed.twitterUrl !== undefined) profile.twitterUrl = normalizeOptionalString(parsed.twitterUrl)\n\n if (parsed.companyEntityId !== undefined) {\n profile.company = await resolveCompanyReference(em, parsed.companyEntityId, record.organizationId, record.tenantId)\n }\n\n if (parsed.displayName !== undefined) {\n const nextDisplayName = parsed.displayName.trim()\n if (!nextDisplayName) {\n throw new CrudHttpError(400, { error: 'Display name is required' })\n }\n record.displayName = nextDisplayName\n }\n\n await em.flush()\n await syncEntityTags(em, record, parsed.tags)\n await em.flush()\n\n await setCustomFieldsForPerson(ctx, record.id, profile.id, record.organizationId, record.tenantId, custom)\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: profile.id ?? record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n return { entityId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadPersonSnapshot(em, result.entityId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as PersonSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as PersonSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.people.update', 'Update person'),\n resourceKind: 'customers.person',\n resourceId: before.entity.id,\n tenantId: before.entity.tenantId,\n organizationId: before.entity.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies PersonUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PersonUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entity = await em.findOne(CustomerEntity, { id: before.entity.id })\n if (!entity) {\n const newEntity = em.create(CustomerEntity, {\n id: before.entity.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n kind: 'person',\n displayName: before.entity.displayName,\n description: before.entity.description,\n ownerUserId: before.entity.ownerUserId,\n primaryEmail: before.entity.primaryEmail,\n primaryPhone: before.entity.primaryPhone,\n status: before.entity.status,\n lifecycleStage: before.entity.lifecycleStage,\n source: before.entity.source,\n nextInteractionAt: before.entity.nextInteractionAt,\n nextInteractionName: before.entity.nextInteractionName,\n nextInteractionRefId: before.entity.nextInteractionRefId,\n nextInteractionIcon: before.entity.nextInteractionIcon,\n nextInteractionColor: before.entity.nextInteractionColor,\n isActive: before.entity.isActive,\n })\n em.persist(newEntity)\n const profile = em.create(CustomerPersonProfile, {\n id: before.profile.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n entity: newEntity,\n firstName: before.profile.firstName,\n lastName: before.profile.lastName,\n preferredName: before.profile.preferredName,\n jobTitle: before.profile.jobTitle,\n department: before.profile.department,\n seniority: before.profile.seniority,\n timezone: before.profile.timezone,\n linkedInUrl: before.profile.linkedInUrl,\n twitterUrl: before.profile.twitterUrl,\n })\n em.persist(profile)\n if (before.profile.companyEntityId) {\n profile.company = await resolveCompanyReference(\n em,\n before.profile.companyEntityId,\n before.entity.organizationId,\n before.entity.tenantId\n )\n }\n await em.flush()\n await syncEntityTags(em, newEntity, before.tagIds)\n await em.flush()\n } else {\n entity.displayName = before.entity.displayName\n entity.description = before.entity.description\n entity.ownerUserId = before.entity.ownerUserId\n entity.primaryEmail = before.entity.primaryEmail\n entity.primaryPhone = before.entity.primaryPhone\n entity.status = before.entity.status\n entity.lifecycleStage = before.entity.lifecycleStage\n entity.source = before.entity.source\n entity.nextInteractionAt = before.entity.nextInteractionAt\n entity.nextInteractionName = before.entity.nextInteractionName\n entity.nextInteractionRefId = before.entity.nextInteractionRefId\n entity.nextInteractionIcon = before.entity.nextInteractionIcon\n entity.nextInteractionColor = before.entity.nextInteractionColor\n entity.isActive = before.entity.isActive\n await em.flush()\n const profile = await em.findOne(CustomerPersonProfile, { entity })\n if (profile) {\n profile.firstName = before.profile.firstName\n profile.lastName = before.profile.lastName\n profile.preferredName = before.profile.preferredName\n profile.jobTitle = before.profile.jobTitle\n profile.department = before.profile.department\n profile.seniority = before.profile.seniority\n profile.timezone = before.profile.timezone\n profile.linkedInUrl = before.profile.linkedInUrl\n profile.twitterUrl = before.profile.twitterUrl\n profile.company = before.profile.companyEntityId\n ? await resolveCompanyReference(\n em,\n before.profile.companyEntityId,\n before.entity.organizationId,\n before.entity.tenantId\n )\n : null\n }\n await syncEntityTags(em, entity, before.tagIds)\n await em.flush()\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: await em.findOne(CustomerEntity, { id: before.entity.id }),\n identifiers: {\n id: before.profile.id ?? before.entity.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsForPerson(ctx, before.entity.id, before.profile.id, before.entity.organizationId, before.entity.tenantId, resetValues)\n }\n },\n}\n\nconst deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { entityId: string }> =\n {\n id: 'customers.people.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Person id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPersonSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Person id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadPersonSnapshot(em, id)\n const entity = await em.findOne(CustomerEntity, { id, deletedAt: null })\n const record = assertFound(entity, 'Person not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const profile = await em.findOne(CustomerPersonProfile, { entity: record })\n if (profile) em.remove(profile)\n await em.nativeDelete(CustomerAddress, { entity: record })\n await em.nativeDelete(CustomerComment, { entity: record })\n await em.nativeDelete(CustomerActivity, { entity: record })\n await em.nativeDelete(CustomerTodoLink, { entity: record })\n await em.nativeDelete(CustomerTagAssignment, { entity: record })\n await em.nativeDelete(CustomerDealPersonLink, { person: record })\n em.remove(record)\n await em.flush()\n\n const indexDeletes: QueryIndexEventEntry[] = []\n const dealUpserts: QueryIndexEventEntry[] = []\n if (snapshot) {\n for (const activity of snapshot.activities ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_activity,\n recordId: activity.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const comment of snapshot.comments ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_comment,\n recordId: comment.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const address of snapshot.addresses ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_address,\n recordId: address.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const todo of snapshot.todos ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_todo_link,\n recordId: todo.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const deal of snapshot.deals ?? []) {\n if (deal.dealId) {\n dealUpserts.push({\n entityType: E.customers.customer_deal,\n recordId: deal.dealId,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n }\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: profile?.id ?? record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n await emitQueryIndexDeleteEvents(ctx, indexDeletes)\n await emitQueryIndexUpsertEvents(ctx, dealUpserts)\n return { entityId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as PersonSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.people.delete', 'Delete person'),\n resourceKind: 'customers.person',\n resourceId: before.entity.id,\n tenantId: before.entity.tenantId,\n organizationId: before.entity.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies PersonUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PersonUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let entity = await em.findOne(CustomerEntity, { id: before.entity.id })\n if (!entity) {\n entity = em.create(CustomerEntity, {\n id: before.entity.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n kind: 'person',\n displayName: before.entity.displayName,\n description: before.entity.description,\n ownerUserId: before.entity.ownerUserId,\n primaryEmail: before.entity.primaryEmail,\n primaryPhone: before.entity.primaryPhone,\n status: before.entity.status,\n lifecycleStage: before.entity.lifecycleStage,\n source: before.entity.source,\n nextInteractionAt: before.entity.nextInteractionAt,\n nextInteractionName: before.entity.nextInteractionName,\n nextInteractionRefId: before.entity.nextInteractionRefId,\n nextInteractionIcon: before.entity.nextInteractionIcon,\n nextInteractionColor: before.entity.nextInteractionColor,\n isActive: before.entity.isActive,\n })\n em.persist(entity)\n }\n\n entity.displayName = before.entity.displayName\n entity.description = before.entity.description\n entity.ownerUserId = before.entity.ownerUserId\n entity.primaryEmail = before.entity.primaryEmail\n entity.primaryPhone = before.entity.primaryPhone\n entity.status = before.entity.status\n entity.lifecycleStage = before.entity.lifecycleStage\n entity.source = before.entity.source\n entity.nextInteractionAt = before.entity.nextInteractionAt\n entity.nextInteractionName = before.entity.nextInteractionName\n entity.nextInteractionRefId = before.entity.nextInteractionRefId\n entity.nextInteractionIcon = before.entity.nextInteractionIcon\n entity.nextInteractionColor = before.entity.nextInteractionColor\n entity.isActive = before.entity.isActive\n\n let profile = await em.findOne(CustomerPersonProfile, { entity })\n if (!profile) {\n profile = em.create(CustomerPersonProfile, {\n id: before.profile.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n entity,\n firstName: before.profile.firstName,\n lastName: before.profile.lastName,\n preferredName: before.profile.preferredName,\n jobTitle: before.profile.jobTitle,\n department: before.profile.department,\n seniority: before.profile.seniority,\n timezone: before.profile.timezone,\n linkedInUrl: before.profile.linkedInUrl,\n twitterUrl: before.profile.twitterUrl,\n })\n } else {\n profile.firstName = before.profile.firstName\n profile.lastName = before.profile.lastName\n profile.preferredName = before.profile.preferredName\n profile.jobTitle = before.profile.jobTitle\n profile.department = before.profile.department\n profile.seniority = before.profile.seniority\n profile.timezone = before.profile.timezone\n profile.linkedInUrl = before.profile.linkedInUrl\n profile.twitterUrl = before.profile.twitterUrl\n }\n\n if (before.profile.companyEntityId) {\n profile.company = await resolveCompanyReference(\n em,\n before.profile.companyEntityId,\n before.entity.organizationId,\n before.entity.tenantId\n )\n } else {\n profile.company = null\n }\n\n await em.flush()\n await syncEntityTags(em, entity, before.tagIds)\n await em.flush()\n\n const beforeActivities = (before as { activities?: PersonActivitySnapshot[] }).activities ?? []\n const beforeTodos = (before as { todos?: PersonTodoSnapshot[] }).todos ?? []\n\n const relatedDealIds = new Set<string>()\n for (const link of before.deals) relatedDealIds.add(link.dealId)\n for (const activity of beforeActivities) {\n if (activity.dealId) relatedDealIds.add(activity.dealId)\n }\n for (const comment of before.comments) {\n if (comment.dealId) relatedDealIds.add(comment.dealId)\n }\n let dealMap = new Map<string, CustomerDeal>()\n if (relatedDealIds.size) {\n const deals = await em.find(CustomerDeal, {\n id: { $in: Array.from(relatedDealIds) },\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n })\n dealMap = new Map(deals.map((deal) => [deal.id, deal]))\n }\n\n await em.nativeDelete(CustomerDealPersonLink, { person: entity })\n for (const link of before.deals) {\n const deal = dealMap.get(link.dealId)\n if (!deal) continue\n const restoredLink = em.create(CustomerDealPersonLink, {\n id: link.id,\n deal,\n person: entity,\n participantRole: link.participantRole,\n createdAt: link.createdAt,\n })\n em.persist(restoredLink)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerActivity, { entity })\n for (const activity of beforeActivities) {\n const restoredActivity = em.create(CustomerActivity, {\n id: activity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n activityType: activity.activityType,\n subject: activity.subject,\n body: activity.body,\n occurredAt: activity.occurredAt,\n authorUserId: activity.authorUserId,\n appearanceIcon: activity.appearanceIcon,\n appearanceColor: activity.appearanceColor,\n deal: activity.dealId ? dealMap.get(activity.dealId) ?? null : null,\n createdAt: activity.createdAt,\n updatedAt: activity.updatedAt,\n })\n em.persist(restoredActivity)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerComment, { entity })\n for (const comment of before.comments) {\n const restoredComment = em.create(CustomerComment, {\n id: comment.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n body: comment.body,\n authorUserId: comment.authorUserId,\n appearanceIcon: comment.appearanceIcon,\n appearanceColor: comment.appearanceColor,\n deal: comment.dealId ? dealMap.get(comment.dealId) ?? null : null,\n createdAt: comment.createdAt,\n updatedAt: comment.updatedAt,\n deletedAt: comment.deletedAt,\n })\n em.persist(restoredComment)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerAddress, { entity })\n for (const address of before.addresses) {\n const restoredAddress = em.create(CustomerAddress, {\n id: address.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n name: address.name,\n purpose: address.purpose,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2,\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 })\n em.persist(restoredAddress)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerTodoLink, { entity })\n for (const todo of beforeTodos) {\n const restoredTodo = em.create(CustomerTodoLink, {\n id: todo.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n todoId: todo.todoId,\n todoSource: todo.todoSource,\n createdAt: todo.createdAt,\n createdByUserId: todo.createdByUserId,\n })\n em.persist(restoredTodo)\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity,\n identifiers: {\n id: profile.id ?? entity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n const upsertEntries: QueryIndexEventEntry[] = []\n for (const activity of before.activities ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_activity,\n recordId: activity.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n for (const comment of before.comments ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_comment,\n recordId: comment.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n for (const address of before.addresses ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_address,\n recordId: address.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n for (const todo of beforeTodos ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_todo_link,\n recordId: todo.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n const dealUpserts: QueryIndexEventEntry[] = []\n for (const deal of before.deals ?? []) {\n if (deal.dealId) {\n dealUpserts.push({\n entityType: E.customers.customer_deal,\n recordId: deal.dealId,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n }\n const resetValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsForPerson(ctx, entity.id, profile.id, entity.organizationId, entity.tenantId, resetValues)\n }\n await emitQueryIndexUpsertEvents(ctx, upsertEntries)\n await emitQueryIndexUpsertEvents(ctx, dealUpserts)\n },\n }\n\nregisterCommand(createPersonCommand)\nregisterCommand(updatePersonCommand)\nregisterCommand(deletePersonCommand)\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerAddress,\n CustomerComment,\n CustomerActivity,\n CustomerDeal,\n CustomerDealPersonLink,\n CustomerTodoLink,\n CustomerEntity,\n CustomerPersonProfile,\n CustomerTagAssignment,\n} from '../data/entities'\nimport { resolvePersonCustomFieldRouting, CUSTOMER_ENTITY_ID, PERSON_ENTITY_ID } from '../lib/customFieldRouting'\nimport {\n personCreateSchema,\n personUpdateSchema,\n type PersonCreateInput,\n type PersonUpdateInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n assertFound,\n syncEntityTags,\n loadEntityTagIds,\n ensureDictionaryEntry,\n emitQueryIndexDeleteEvents,\n emitQueryIndexUpsertEvents,\n type QueryIndexEventEntry,\n} from './shared'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\n\ntype PersonAddressSnapshot = {\n id: string\n name: string | null\n purpose: string | null\n addressLine1: string\n addressLine2: string | null\n city: string | null\n region: string | null\n postalCode: string | null\n country: string | null\n latitude: number | null\n longitude: number | null\n isPrimary: boolean\n}\n\ntype PersonCommentSnapshot = {\n id: string\n body: string\n authorUserId: string | null\n dealId: string | null\n createdAt: Date\n updatedAt: Date\n deletedAt: Date | null\n appearanceIcon: string | null\n appearanceColor: string | null\n}\n\ntype PersonActivitySnapshot = {\n id: string\n activityType: string\n subject: string | null\n body: string | null\n occurredAt: Date | null\n authorUserId: string | null\n appearanceIcon: string | null\n appearanceColor: string | null\n dealId: string | null\n createdAt: Date\n updatedAt: Date\n}\n\ntype PersonTodoSnapshot = {\n id: string\n todoId: string\n todoSource: string\n createdAt: Date\n createdByUserId: string | null\n}\n\ntype PersonSnapshot = {\n entity: {\n id: string\n organizationId: string\n tenantId: string\n displayName: string\n description: string | null\n ownerUserId: string | null\n primaryEmail: string | null\n primaryPhone: string | null\n status: string | null\n lifecycleStage: string | null\n source: string | null\n nextInteractionAt: Date | null\n nextInteractionName: string | null\n nextInteractionRefId: string | null\n nextInteractionIcon: string | null\n nextInteractionColor: string | null\n isActive: boolean\n }\n profile: {\n id: string\n firstName: string | null\n lastName: string | null\n preferredName: string | null\n jobTitle: string | null\n department: string | null\n seniority: string | null\n timezone: string | null\n linkedInUrl: string | null\n twitterUrl: string | null\n companyEntityId: string | null\n }\n tagIds: string[]\n addresses: PersonAddressSnapshot[]\n comments: PersonCommentSnapshot[]\n custom?: Record<string, unknown>\n deals: Array<{\n id: string\n dealId: string\n participantRole: string | null\n createdAt: Date\n }>\n activities: PersonActivitySnapshot[]\n todos: PersonTodoSnapshot[]\n}\n\ntype PersonUndoPayload = {\n before?: PersonSnapshot | null\n after?: PersonSnapshot | null\n}\n\nconst personCrudIndexer: CrudIndexerConfig<CustomerEntity> = {\n entityType: E.customers.customer_person_profile,\n}\n\nconst personCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'person',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\nfunction normalizeOptionalString(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nfunction normalizeHexColor(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim().toLowerCase()\n return /^#([0-9a-f]{6})$/.test(trimmed) ? trimmed : null\n}\n\nfunction normalizeEmail(value: string | null | undefined): string | null {\n const normalized = normalizeOptionalString(value)\n return normalized ? normalized.toLowerCase() : null\n}\n\nfunction serializePersonSnapshot(\n entity: CustomerEntity,\n profile: CustomerPersonProfile,\n tagIds: string[],\n addresses: CustomerAddress[],\n comments: CustomerComment[],\n deals: CustomerDealPersonLink[],\n activities: CustomerActivity[],\n todoLinks: CustomerTodoLink[],\n custom?: Record<string, unknown>\n): PersonSnapshot {\n return {\n entity: {\n id: entity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n displayName: entity.displayName,\n description: entity.description ?? null,\n ownerUserId: entity.ownerUserId ?? null,\n primaryEmail: entity.primaryEmail ?? null,\n primaryPhone: entity.primaryPhone ?? null,\n status: entity.status ?? null,\n lifecycleStage: entity.lifecycleStage ?? null,\n source: entity.source ?? null,\n nextInteractionAt: entity.nextInteractionAt ?? null,\n nextInteractionName: entity.nextInteractionName ?? null,\n nextInteractionRefId: entity.nextInteractionRefId ?? null,\n nextInteractionIcon: entity.nextInteractionIcon ?? null,\n nextInteractionColor: entity.nextInteractionColor ?? null,\n isActive: entity.isActive,\n },\n profile: {\n id: profile.id,\n firstName: profile.firstName ?? null,\n lastName: profile.lastName ?? null,\n preferredName: profile.preferredName ?? null,\n jobTitle: profile.jobTitle ?? null,\n department: profile.department ?? null,\n seniority: profile.seniority ?? null,\n timezone: profile.timezone ?? null,\n linkedInUrl: profile.linkedInUrl ?? null,\n twitterUrl: profile.twitterUrl ?? null,\n companyEntityId: profile.company\n ? typeof profile.company === 'string'\n ? profile.company\n : profile.company.id\n : null,\n },\n tagIds,\n addresses: addresses.map((address) => ({\n id: address.id,\n name: address.name ?? null,\n purpose: address.purpose ?? null,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2 ?? null,\n city: address.city ?? null,\n region: address.region ?? null,\n postalCode: address.postalCode ?? null,\n country: address.country ?? null,\n latitude: address.latitude ?? null,\n longitude: address.longitude ?? null,\n isPrimary: address.isPrimary,\n })),\n comments: comments.map((comment) => ({\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId ?? null,\n dealId: comment.deal\n ? typeof comment.deal === 'string'\n ? comment.deal\n : comment.deal.id\n : null,\n createdAt: comment.createdAt,\n updatedAt: comment.updatedAt,\n deletedAt: comment.deletedAt ?? null,\n appearanceIcon: comment.appearanceIcon ?? null,\n appearanceColor: comment.appearanceColor ?? null,\n })),\n deals: deals\n .filter((link) => link.deal)\n .map((link) => ({\n id: link.id,\n dealId: link.deal.id,\n participantRole: link.participantRole ?? null,\n createdAt: link.createdAt,\n })),\n activities: activities.map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: activity.occurredAt ?? null,\n authorUserId: activity.authorUserId ?? null,\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n dealId: activity.deal\n ? typeof activity.deal === 'string'\n ? activity.deal\n : activity.deal.id\n : null,\n createdAt: activity.createdAt,\n updatedAt: activity.updatedAt,\n })),\n todos: todoLinks.map((todo) => ({\n id: todo.id,\n todoId: todo.todoId,\n todoSource: todo.todoSource,\n createdAt: todo.createdAt,\n createdByUserId: todo.createdByUserId ?? null,\n })),\n custom,\n }\n}\n\nasync function loadPersonSnapshot(em: EntityManager, entityId: string): Promise<PersonSnapshot | null> {\n const entity = await em.findOne(CustomerEntity, { id: entityId, deletedAt: null })\n if (!entity || entity.kind !== 'person') return null\n const profile = await findOneWithDecryption(\n em,\n CustomerPersonProfile,\n { entity: entity },\n { populate: ['company'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n if (!profile) return null\n const tagIds = await loadEntityTagIds(em, entity)\n const addresses = await em.find(CustomerAddress, { entity }, { orderBy: { createdAt: 'asc' } })\n const comments = await findWithDecryption(\n em,\n CustomerComment,\n { entity },\n { orderBy: { createdAt: 'asc' }, populate: ['deal'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n const deals = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n { person: entity },\n { orderBy: { createdAt: 'asc' }, populate: ['deal'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n const activities = await findWithDecryption(\n em,\n CustomerActivity,\n { entity },\n { orderBy: { createdAt: 'asc' }, populate: ['deal'] },\n { tenantId: entity.tenantId, organizationId: entity.organizationId },\n )\n const todoLinks = await em.find(CustomerTodoLink, { entity }, { orderBy: { createdAt: 'asc' } })\n const entityCustom = await loadCustomFieldSnapshot(em, {\n entityId: CUSTOMER_ENTITY_ID,\n recordId: entity.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n const profileCustom = await loadCustomFieldSnapshot(em, {\n entityId: PERSON_ENTITY_ID,\n recordId: profile.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n const routing = await resolvePersonCustomFieldRouting(em, entity.tenantId, entity.organizationId)\n const custom: Record<string, unknown> = { ...entityCustom }\n for (const [key, value] of Object.entries(profileCustom)) {\n const target = routing.get(key)\n if (target === CUSTOMER_ENTITY_ID && Object.prototype.hasOwnProperty.call(custom, key)) continue\n custom[key] = value\n }\n return serializePersonSnapshot(entity, profile, tagIds, addresses, comments, deals, activities, todoLinks, custom)\n}\n\nasync function resolveCompanyReference(\n em: EntityManager,\n companyId: string | null | undefined,\n organizationId: string,\n tenantId: string\n): Promise<CustomerEntity | null> {\n if (!companyId) return null\n const company = await em.findOne(CustomerEntity, { id: companyId, kind: 'company', deletedAt: null })\n if (!company) {\n throw new CrudHttpError(400, { error: 'Company not found' })\n }\n if (company.organizationId !== organizationId || company.tenantId !== tenantId) {\n throw new CrudHttpError(403, { error: 'Cannot link person to company outside current scope' })\n }\n return company\n}\n\nasync function setCustomFieldsForPerson(\n ctx: CommandRuntimeContext,\n entityId: string,\n profileId: string,\n organizationId: string,\n tenantId: string,\n values: Record<string, unknown>\n): Promise<void> {\n if (!values || !Object.keys(values).length) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const routing = await resolvePersonCustomFieldRouting(em, tenantId, organizationId)\n const entityScoped: Record<string, unknown> = {}\n const profileScoped: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(values)) {\n const target = routing.get(key) ?? PERSON_ENTITY_ID\n if (target === CUSTOMER_ENTITY_ID) entityScoped[key] = value\n else profileScoped[key] = value\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n if (Object.keys(entityScoped).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: CUSTOMER_ENTITY_ID,\n recordId: entityId,\n organizationId,\n tenantId,\n values: entityScoped,\n notify: true,\n })\n }\n if (Object.keys(profileScoped).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: PERSON_ENTITY_ID,\n recordId: profileId,\n organizationId,\n tenantId,\n values: profileScoped,\n notify: true,\n })\n }\n}\n\nconst createPersonCommand: CommandHandler<PersonCreateInput, { entityId: string; personId: string }> = {\n id: 'customers.people.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(personCreateSchema, rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const firstName = parsed.firstName?.trim() ?? ''\n const lastName = parsed.lastName?.trim() ?? ''\n const description = normalizeOptionalString(parsed.description)\n const primaryEmail = normalizeEmail(parsed.primaryEmail)\n const primaryPhone = normalizeOptionalString(parsed.primaryPhone)\n const status = normalizeOptionalString(parsed.status)\n const lifecycleStage = normalizeOptionalString(parsed.lifecycleStage)\n const source = normalizeOptionalString(parsed.source)\n const preferredName = normalizeOptionalString(parsed.preferredName)\n const jobTitle = normalizeOptionalString(parsed.jobTitle)\n const department = normalizeOptionalString(parsed.department)\n const seniority = normalizeOptionalString(parsed.seniority)\n const timezone = normalizeOptionalString(parsed.timezone)\n const linkedInUrl = normalizeOptionalString(parsed.linkedInUrl)\n const twitterUrl = normalizeOptionalString(parsed.twitterUrl)\n const displayName = parsed.displayName?.trim() ?? ''\n const nextInteractionName = parsed.nextInteraction?.name ? parsed.nextInteraction.name.trim() : null\n const nextInteractionRefId = normalizeOptionalString(parsed.nextInteraction?.refId)\n const nextInteractionIcon = normalizeOptionalString(parsed.nextInteraction?.icon)\n const nextInteractionColor = normalizeHexColor(parsed.nextInteraction?.color)\n if (!firstName || !lastName) {\n throw new CrudHttpError(400, { error: 'First and last name are required' })\n }\n if (!displayName) {\n throw new CrudHttpError(400, { error: 'Display name is required' })\n }\n\n const entity = em.create(CustomerEntity, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n kind: 'person',\n displayName,\n description,\n ownerUserId: parsed.ownerUserId ?? null,\n primaryEmail,\n primaryPhone,\n status,\n lifecycleStage,\n source,\n nextInteractionAt: parsed.nextInteraction?.at ?? null,\n nextInteractionName,\n nextInteractionRefId,\n nextInteractionIcon,\n nextInteractionColor,\n isActive: parsed.isActive ?? true,\n })\n\n const company = await resolveCompanyReference(em, parsed.companyEntityId ?? null, parsed.organizationId, parsed.tenantId)\n\n const profile = em.create(CustomerPersonProfile, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n entity,\n firstName,\n lastName,\n preferredName,\n jobTitle,\n department,\n seniority,\n timezone,\n linkedInUrl,\n twitterUrl,\n company,\n })\n\n em.persist(entity)\n em.persist(profile)\n if (status) {\n await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'status',\n value: status,\n })\n }\n if (jobTitle) {\n await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'job_title',\n value: jobTitle,\n })\n }\n if (source) {\n await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'source',\n value: source,\n })\n }\n await em.flush()\n\n const tenantId = entity.tenantId\n const organizationId = entity.organizationId\n await syncEntityTags(em, entity, parsed.tags)\n await em.flush()\n await setCustomFieldsForPerson(ctx, entity.id, profile.id, organizationId, tenantId, custom)\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity,\n identifiers: {\n id: profile.id ?? entity.id,\n tenantId,\n organizationId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n return { entityId: entity.id, personId: profile.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadPersonSnapshot(em, result.entityId)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const snapshot = snapshots.after as PersonSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.people.create', 'Create person'),\n resourceKind: 'customers.person',\n resourceId: result.entityId,\n tenantId: snapshot?.entity.tenantId ?? null,\n organizationId: snapshot?.entity.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot,\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PersonUndoPayload>(logEntry) ?? null\n const entityId = logEntry?.resourceId ?? payload?.after?.entity.id ?? null\n if (!entityId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entity = await em.findOne(CustomerEntity, { id: entityId })\n if (!entity) return\n const profile = await em.findOne(CustomerPersonProfile, { entity })\n await em.nativeDelete(CustomerTagAssignment, { entity })\n if (profile) {\n await em.remove(profile).flush()\n }\n await em.remove(entity).flush()\n },\n}\n\nconst updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string }> = {\n id: 'customers.people.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(personUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPersonSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(personUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entity = await em.findOne(CustomerEntity, { id: parsed.id, deletedAt: null })\n const record = assertFound(entity, 'Person not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const profile = await em.findOne(CustomerPersonProfile, { entity: record })\n if (!profile) throw new CrudHttpError(404, { error: 'Person profile not found' })\n\n if (parsed.description !== undefined) record.description = normalizeOptionalString(parsed.description)\n if (parsed.ownerUserId !== undefined) record.ownerUserId = parsed.ownerUserId ?? null\n if (parsed.primaryEmail !== undefined) record.primaryEmail = normalizeEmail(parsed.primaryEmail)\n if (parsed.primaryPhone !== undefined) record.primaryPhone = normalizeOptionalString(parsed.primaryPhone)\n if (parsed.status !== undefined) {\n const normalizedStatus = normalizeOptionalString(parsed.status)\n record.status = normalizedStatus\n if (normalizedStatus) {\n await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'status',\n value: normalizedStatus,\n })\n }\n }\n if (parsed.lifecycleStage !== undefined) record.lifecycleStage = normalizeOptionalString(parsed.lifecycleStage)\n if (parsed.source !== undefined) {\n const normalizedSource = normalizeOptionalString(parsed.source)\n record.source = normalizedSource\n if (normalizedSource) {\n await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'source',\n value: normalizedSource,\n })\n }\n }\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive\n if (parsed.nextInteraction) {\n record.nextInteractionAt = parsed.nextInteraction.at\n record.nextInteractionName = parsed.nextInteraction.name.trim()\n record.nextInteractionRefId = normalizeOptionalString(parsed.nextInteraction.refId) ?? null\n record.nextInteractionIcon = normalizeOptionalString(parsed.nextInteraction.icon)\n record.nextInteractionColor = normalizeHexColor(parsed.nextInteraction.color)\n } else if (parsed.nextInteraction === null) {\n record.nextInteractionAt = null\n record.nextInteractionName = null\n record.nextInteractionRefId = null\n record.nextInteractionIcon = null\n record.nextInteractionColor = null\n }\n\n if (parsed.firstName !== undefined) profile.firstName = normalizeOptionalString(parsed.firstName)\n if (parsed.lastName !== undefined) profile.lastName = normalizeOptionalString(parsed.lastName)\n if (parsed.preferredName !== undefined) profile.preferredName = normalizeOptionalString(parsed.preferredName)\n if (parsed.jobTitle !== undefined) {\n const normalizedJobTitle = normalizeOptionalString(parsed.jobTitle)\n profile.jobTitle = normalizedJobTitle\n if (normalizedJobTitle) {\n await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'job_title',\n value: normalizedJobTitle,\n })\n }\n }\n if (parsed.department !== undefined) profile.department = normalizeOptionalString(parsed.department)\n if (parsed.seniority !== undefined) profile.seniority = normalizeOptionalString(parsed.seniority)\n if (parsed.timezone !== undefined) profile.timezone = normalizeOptionalString(parsed.timezone)\n if (parsed.linkedInUrl !== undefined) profile.linkedInUrl = normalizeOptionalString(parsed.linkedInUrl)\n if (parsed.twitterUrl !== undefined) profile.twitterUrl = normalizeOptionalString(parsed.twitterUrl)\n\n if (parsed.companyEntityId !== undefined) {\n profile.company = await resolveCompanyReference(em, parsed.companyEntityId, record.organizationId, record.tenantId)\n }\n\n const profileFieldsUpdated = [\n parsed.firstName, parsed.lastName, parsed.preferredName, parsed.jobTitle,\n parsed.department, parsed.seniority, parsed.timezone, parsed.linkedInUrl,\n parsed.twitterUrl, parsed.companyEntityId,\n ].some((v) => v !== undefined)\n if (profileFieldsUpdated) {\n record.updatedAt = new Date()\n }\n\n if (parsed.displayName !== undefined) {\n const nextDisplayName = parsed.displayName.trim()\n if (!nextDisplayName) {\n throw new CrudHttpError(400, { error: 'Display name is required' })\n }\n record.displayName = nextDisplayName\n }\n\n await em.flush()\n await syncEntityTags(em, record, parsed.tags)\n await em.flush()\n\n await setCustomFieldsForPerson(ctx, record.id, profile.id, record.organizationId, record.tenantId, custom)\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: profile.id ?? record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n return { entityId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadPersonSnapshot(em, result.entityId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as PersonSnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as PersonSnapshot | undefined\n return {\n actionLabel: translate('customers.audit.people.update', 'Update person'),\n resourceKind: 'customers.person',\n resourceId: before.entity.id,\n tenantId: before.entity.tenantId,\n organizationId: before.entity.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies PersonUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PersonUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entity = await em.findOne(CustomerEntity, { id: before.entity.id })\n if (!entity) {\n const newEntity = em.create(CustomerEntity, {\n id: before.entity.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n kind: 'person',\n displayName: before.entity.displayName,\n description: before.entity.description,\n ownerUserId: before.entity.ownerUserId,\n primaryEmail: before.entity.primaryEmail,\n primaryPhone: before.entity.primaryPhone,\n status: before.entity.status,\n lifecycleStage: before.entity.lifecycleStage,\n source: before.entity.source,\n nextInteractionAt: before.entity.nextInteractionAt,\n nextInteractionName: before.entity.nextInteractionName,\n nextInteractionRefId: before.entity.nextInteractionRefId,\n nextInteractionIcon: before.entity.nextInteractionIcon,\n nextInteractionColor: before.entity.nextInteractionColor,\n isActive: before.entity.isActive,\n })\n em.persist(newEntity)\n const profile = em.create(CustomerPersonProfile, {\n id: before.profile.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n entity: newEntity,\n firstName: before.profile.firstName,\n lastName: before.profile.lastName,\n preferredName: before.profile.preferredName,\n jobTitle: before.profile.jobTitle,\n department: before.profile.department,\n seniority: before.profile.seniority,\n timezone: before.profile.timezone,\n linkedInUrl: before.profile.linkedInUrl,\n twitterUrl: before.profile.twitterUrl,\n })\n em.persist(profile)\n if (before.profile.companyEntityId) {\n profile.company = await resolveCompanyReference(\n em,\n before.profile.companyEntityId,\n before.entity.organizationId,\n before.entity.tenantId\n )\n }\n await em.flush()\n await syncEntityTags(em, newEntity, before.tagIds)\n await em.flush()\n } else {\n entity.displayName = before.entity.displayName\n entity.description = before.entity.description\n entity.ownerUserId = before.entity.ownerUserId\n entity.primaryEmail = before.entity.primaryEmail\n entity.primaryPhone = before.entity.primaryPhone\n entity.status = before.entity.status\n entity.lifecycleStage = before.entity.lifecycleStage\n entity.source = before.entity.source\n entity.nextInteractionAt = before.entity.nextInteractionAt\n entity.nextInteractionName = before.entity.nextInteractionName\n entity.nextInteractionRefId = before.entity.nextInteractionRefId\n entity.nextInteractionIcon = before.entity.nextInteractionIcon\n entity.nextInteractionColor = before.entity.nextInteractionColor\n entity.isActive = before.entity.isActive\n await em.flush()\n const profile = await em.findOne(CustomerPersonProfile, { entity })\n if (profile) {\n profile.firstName = before.profile.firstName\n profile.lastName = before.profile.lastName\n profile.preferredName = before.profile.preferredName\n profile.jobTitle = before.profile.jobTitle\n profile.department = before.profile.department\n profile.seniority = before.profile.seniority\n profile.timezone = before.profile.timezone\n profile.linkedInUrl = before.profile.linkedInUrl\n profile.twitterUrl = before.profile.twitterUrl\n profile.company = before.profile.companyEntityId\n ? await resolveCompanyReference(\n em,\n before.profile.companyEntityId,\n before.entity.organizationId,\n before.entity.tenantId\n )\n : null\n }\n await syncEntityTags(em, entity, before.tagIds)\n await em.flush()\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: await em.findOne(CustomerEntity, { id: before.entity.id }),\n identifiers: {\n id: before.profile.id ?? before.entity.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsForPerson(ctx, before.entity.id, before.profile.id, before.entity.organizationId, before.entity.tenantId, resetValues)\n }\n },\n}\n\nconst deletePersonCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { entityId: string }> =\n {\n id: 'customers.people.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Person id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPersonSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Person id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadPersonSnapshot(em, id)\n const entity = await em.findOne(CustomerEntity, { id, deletedAt: null })\n const record = assertFound(entity, 'Person not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const profile = await em.findOne(CustomerPersonProfile, { entity: record })\n if (profile) em.remove(profile)\n await em.nativeDelete(CustomerAddress, { entity: record })\n await em.nativeDelete(CustomerComment, { entity: record })\n await em.nativeDelete(CustomerActivity, { entity: record })\n await em.nativeDelete(CustomerTodoLink, { entity: record })\n await em.nativeDelete(CustomerTagAssignment, { entity: record })\n await em.nativeDelete(CustomerDealPersonLink, { person: record })\n em.remove(record)\n await em.flush()\n\n const indexDeletes: QueryIndexEventEntry[] = []\n const dealUpserts: QueryIndexEventEntry[] = []\n if (snapshot) {\n for (const activity of snapshot.activities ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_activity,\n recordId: activity.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const comment of snapshot.comments ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_comment,\n recordId: comment.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const address of snapshot.addresses ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_address,\n recordId: address.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const todo of snapshot.todos ?? []) {\n indexDeletes.push({\n entityType: E.customers.customer_todo_link,\n recordId: todo.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n for (const deal of snapshot.deals ?? []) {\n if (deal.dealId) {\n dealUpserts.push({\n entityType: E.customers.customer_deal,\n recordId: deal.dealId,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n }\n }\n }\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: profile?.id ?? record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n await emitQueryIndexDeleteEvents(ctx, indexDeletes)\n await emitQueryIndexUpsertEvents(ctx, dealUpserts)\n return { entityId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as PersonSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.people.delete', 'Delete person'),\n resourceKind: 'customers.person',\n resourceId: before.entity.id,\n tenantId: before.entity.tenantId,\n organizationId: before.entity.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies PersonUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PersonUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let entity = await em.findOne(CustomerEntity, { id: before.entity.id })\n if (!entity) {\n entity = em.create(CustomerEntity, {\n id: before.entity.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n kind: 'person',\n displayName: before.entity.displayName,\n description: before.entity.description,\n ownerUserId: before.entity.ownerUserId,\n primaryEmail: before.entity.primaryEmail,\n primaryPhone: before.entity.primaryPhone,\n status: before.entity.status,\n lifecycleStage: before.entity.lifecycleStage,\n source: before.entity.source,\n nextInteractionAt: before.entity.nextInteractionAt,\n nextInteractionName: before.entity.nextInteractionName,\n nextInteractionRefId: before.entity.nextInteractionRefId,\n nextInteractionIcon: before.entity.nextInteractionIcon,\n nextInteractionColor: before.entity.nextInteractionColor,\n isActive: before.entity.isActive,\n })\n em.persist(entity)\n }\n\n entity.displayName = before.entity.displayName\n entity.description = before.entity.description\n entity.ownerUserId = before.entity.ownerUserId\n entity.primaryEmail = before.entity.primaryEmail\n entity.primaryPhone = before.entity.primaryPhone\n entity.status = before.entity.status\n entity.lifecycleStage = before.entity.lifecycleStage\n entity.source = before.entity.source\n entity.nextInteractionAt = before.entity.nextInteractionAt\n entity.nextInteractionName = before.entity.nextInteractionName\n entity.nextInteractionRefId = before.entity.nextInteractionRefId\n entity.nextInteractionIcon = before.entity.nextInteractionIcon\n entity.nextInteractionColor = before.entity.nextInteractionColor\n entity.isActive = before.entity.isActive\n\n let profile = await em.findOne(CustomerPersonProfile, { entity })\n if (!profile) {\n profile = em.create(CustomerPersonProfile, {\n id: before.profile.id,\n organizationId: before.entity.organizationId,\n tenantId: before.entity.tenantId,\n entity,\n firstName: before.profile.firstName,\n lastName: before.profile.lastName,\n preferredName: before.profile.preferredName,\n jobTitle: before.profile.jobTitle,\n department: before.profile.department,\n seniority: before.profile.seniority,\n timezone: before.profile.timezone,\n linkedInUrl: before.profile.linkedInUrl,\n twitterUrl: before.profile.twitterUrl,\n })\n } else {\n profile.firstName = before.profile.firstName\n profile.lastName = before.profile.lastName\n profile.preferredName = before.profile.preferredName\n profile.jobTitle = before.profile.jobTitle\n profile.department = before.profile.department\n profile.seniority = before.profile.seniority\n profile.timezone = before.profile.timezone\n profile.linkedInUrl = before.profile.linkedInUrl\n profile.twitterUrl = before.profile.twitterUrl\n }\n\n if (before.profile.companyEntityId) {\n profile.company = await resolveCompanyReference(\n em,\n before.profile.companyEntityId,\n before.entity.organizationId,\n before.entity.tenantId\n )\n } else {\n profile.company = null\n }\n\n await em.flush()\n await syncEntityTags(em, entity, before.tagIds)\n await em.flush()\n\n const beforeActivities = (before as { activities?: PersonActivitySnapshot[] }).activities ?? []\n const beforeTodos = (before as { todos?: PersonTodoSnapshot[] }).todos ?? []\n\n const relatedDealIds = new Set<string>()\n for (const link of before.deals) relatedDealIds.add(link.dealId)\n for (const activity of beforeActivities) {\n if (activity.dealId) relatedDealIds.add(activity.dealId)\n }\n for (const comment of before.comments) {\n if (comment.dealId) relatedDealIds.add(comment.dealId)\n }\n let dealMap = new Map<string, CustomerDeal>()\n if (relatedDealIds.size) {\n const deals = await em.find(CustomerDeal, {\n id: { $in: Array.from(relatedDealIds) },\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n })\n dealMap = new Map(deals.map((deal) => [deal.id, deal]))\n }\n\n await em.nativeDelete(CustomerDealPersonLink, { person: entity })\n for (const link of before.deals) {\n const deal = dealMap.get(link.dealId)\n if (!deal) continue\n const restoredLink = em.create(CustomerDealPersonLink, {\n id: link.id,\n deal,\n person: entity,\n participantRole: link.participantRole,\n createdAt: link.createdAt,\n })\n em.persist(restoredLink)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerActivity, { entity })\n for (const activity of beforeActivities) {\n const restoredActivity = em.create(CustomerActivity, {\n id: activity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n activityType: activity.activityType,\n subject: activity.subject,\n body: activity.body,\n occurredAt: activity.occurredAt,\n authorUserId: activity.authorUserId,\n appearanceIcon: activity.appearanceIcon,\n appearanceColor: activity.appearanceColor,\n deal: activity.dealId ? dealMap.get(activity.dealId) ?? null : null,\n createdAt: activity.createdAt,\n updatedAt: activity.updatedAt,\n })\n em.persist(restoredActivity)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerComment, { entity })\n for (const comment of before.comments) {\n const restoredComment = em.create(CustomerComment, {\n id: comment.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n body: comment.body,\n authorUserId: comment.authorUserId,\n appearanceIcon: comment.appearanceIcon,\n appearanceColor: comment.appearanceColor,\n deal: comment.dealId ? dealMap.get(comment.dealId) ?? null : null,\n createdAt: comment.createdAt,\n updatedAt: comment.updatedAt,\n deletedAt: comment.deletedAt,\n })\n em.persist(restoredComment)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerAddress, { entity })\n for (const address of before.addresses) {\n const restoredAddress = em.create(CustomerAddress, {\n id: address.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n name: address.name,\n purpose: address.purpose,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2,\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 })\n em.persist(restoredAddress)\n }\n await em.flush()\n\n await em.nativeDelete(CustomerTodoLink, { entity })\n for (const todo of beforeTodos) {\n const restoredTodo = em.create(CustomerTodoLink, {\n id: todo.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n entity,\n todoId: todo.todoId,\n todoSource: todo.todoSource,\n createdAt: todo.createdAt,\n createdByUserId: todo.createdByUserId,\n })\n em.persist(restoredTodo)\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity,\n identifiers: {\n id: profile.id ?? entity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n },\n indexer: personCrudIndexer,\n events: personCrudEvents,\n })\n\n const upsertEntries: QueryIndexEventEntry[] = []\n for (const activity of before.activities ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_activity,\n recordId: activity.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n for (const comment of before.comments ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_comment,\n recordId: comment.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n for (const address of before.addresses ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_address,\n recordId: address.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n for (const todo of beforeTodos ?? []) {\n upsertEntries.push({\n entityType: E.customers.customer_todo_link,\n recordId: todo.id,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n const dealUpserts: QueryIndexEventEntry[] = []\n for (const deal of before.deals ?? []) {\n if (deal.dealId) {\n dealUpserts.push({\n entityType: E.customers.customer_deal,\n recordId: deal.dealId,\n tenantId: entity.tenantId,\n organizationId: entity.organizationId,\n })\n }\n }\n const resetValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsForPerson(ctx, entity.id, profile.id, entity.organizationId, entity.tenantId, resetValues)\n }\n await emitQueryIndexUpsertEvents(ctx, upsertEntries)\n await emitQueryIndexUpsertEvents(ctx, dealUpserts)\n },\n }\n\nregisterCommand(createPersonCommand)\nregisterCommand(updatePersonCommand)\nregisterCommand(deletePersonCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -111,7 +111,7 @@ async function deleteCoverageForEntity(knex, entityType) {
|
|
|
111
111
|
async function tableHasColumn(knex, table, column) {
|
|
112
112
|
const key = `${table}.${column}`;
|
|
113
113
|
if (COLUMN_CACHE.has(key)) return COLUMN_CACHE.get(key);
|
|
114
|
-
const exists = await knex("information_schema.columns").
|
|
114
|
+
const exists = await knex("information_schema.columns").whereRaw("table_schema = current_schema()").where({ table_name: table, column_name: column }).first();
|
|
115
115
|
const present = !!exists;
|
|
116
116
|
COLUMN_CACHE.set(key, present);
|
|
117
117
|
return present;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/lib/coverage.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { Knex } from 'knex'\nimport { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\n\nexport type CoverageScope = {\n entityType: string\n tenantId?: string | null\n organizationId?: string | null\n withDeleted?: boolean\n}\n\ntype CoverageRow = {\n base_count: unknown\n indexed_count: unknown\n vector_indexed_count: unknown\n refreshed_at: Date | string | null\n}\n\nexport type CoverageAdjustment = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n deltaBase: number\n deltaIndex: number\n deltaVector?: number\n}\n\nexport type CoverageDeltaInput = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n baseDelta: number\n indexDelta: number\n vectorDelta?: number\n}\n\nconst COLUMN_CACHE = new Map<string, boolean>()\nconst GLOBAL_ORGANIZATION_PLACEHOLDER = '00000000-0000-0000-0000-000000000000'\nexport const COVERAGE_ORG_PLACEHOLDER = GLOBAL_ORGANIZATION_PLACEHOLDER\n\nfunction toCount(value: unknown): number {\n if (typeof value === 'number') return Number.isFinite(value) ? value : 0\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n }\n if (value != null && typeof (value as { valueOf: () => number }).valueOf === 'function') {\n const parsed = Number((value as { valueOf: () => number }).valueOf())\n return Number.isFinite(parsed) ? parsed : 0\n }\n return 0\n}\n\nfunction normalizeOrganizationForStore(orgId: string | null | undefined): string {\n return orgId ?? GLOBAL_ORGANIZATION_PLACEHOLDER\n}\n\nfunction applyOrganizationCondition(\n qb: Knex.QueryBuilder<any, any>,\n column: string,\n organizationId: string | null | undefined\n) {\n const stored = normalizeOrganizationForStore(organizationId ?? null)\n if (stored === GLOBAL_ORGANIZATION_PLACEHOLDER) {\n qb.andWhere((sub) => {\n sub.whereNull(column).orWhere(column, GLOBAL_ORGANIZATION_PLACEHOLDER)\n })\n } else {\n qb.andWhere(column, stored)\n }\n}\n\nasync function fetchCoverageRow(\n knex: Knex,\n scope: CoverageScope\n): Promise<(CoverageRow & { organization_id: string | null }) | null> {\n const { entityType, tenantId, organizationId, withDeleted } = scope\n const row = await knex('entity_index_coverage')\n .select(['base_count', 'indexed_count', 'vector_indexed_count', 'refreshed_at', 'organization_id'])\n .where('entity_type', entityType)\n .where('tenant_id', tenantId ?? null)\n .where('with_deleted', withDeleted === true)\n .modify((qb) => applyOrganizationCondition(qb, 'organization_id', organizationId ?? null))\n .orderBy('refreshed_at', 'desc')\n .first<CoverageRow & { organization_id: string | null }>()\n return row ?? null\n}\n\nasync function pruneDuplicateCoverageRows(\n knex: Knex,\n scope: CoverageScope,\n keepId: string | null\n) {\n const query = knex('entity_index_coverage')\n .where('entity_type', scope.entityType)\n .where('tenant_id', scope.tenantId ?? null)\n .where('with_deleted', scope.withDeleted === true)\n .modify((qb) => applyOrganizationCondition(qb, 'organization_id', scope.organizationId ?? null))\n if (keepId) {\n await query.andWhereNot('id', keepId).del()\n } else {\n await query.del()\n }\n}\n\nasync function upsertCoverageRow(\n knex: Knex,\n scope: CoverageScope,\n counts: { baseCount: number; indexedCount: number; vectorIndexedCount: number }\n) {\n const storedOrgId = normalizeOrganizationForStore(scope.organizationId ?? null)\n if (scope.organizationId == null) {\n await knex('entity_index_coverage')\n .where('entity_type', scope.entityType)\n .where('tenant_id', scope.tenantId ?? null)\n .where('with_deleted', scope.withDeleted === true)\n .whereNull('organization_id')\n .del()\n }\n\n const rows = await knex('entity_index_coverage')\n .insert({\n entity_type: scope.entityType,\n tenant_id: scope.tenantId ?? null,\n organization_id: storedOrgId,\n with_deleted: scope.withDeleted === true,\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: knex.fn.now(),\n })\n .onConflict(['entity_type', 'tenant_id', 'organization_id', 'with_deleted'])\n .merge({\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: knex.fn.now(),\n })\n .returning<{ id: string }[]>('id')\n\n const keepId = rows?.[0]?.id ?? null\n await pruneDuplicateCoverageRows(knex, scope, keepId)\n}\n\nexport async function readCoverageSnapshot(\n knex: Knex,\n scope: CoverageScope\n): Promise<(CoverageRow & { baseCount: number; indexedCount: number; vectorIndexedCount: number }) | null> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return null\n const row = await fetchCoverageRow(knex, {\n entityType,\n tenantId: scope.tenantId ?? null,\n organizationId: scope.organizationId ?? null,\n withDeleted: scope.withDeleted === true,\n })\n if (!row) return null\n const refreshedAt = row.refreshed_at instanceof Date ? row.refreshed_at : (row.refreshed_at ? new Date(row.refreshed_at) : null)\n return {\n base_count: row.base_count,\n indexed_count: row.indexed_count,\n vector_indexed_count: row.vector_indexed_count,\n refreshed_at: refreshedAt ?? null,\n baseCount: toCount(row.base_count),\n indexedCount: toCount(row.indexed_count),\n vectorIndexedCount: toCount(row.vector_indexed_count),\n }\n}\n\nexport async function applyCoverageAdjustments(\n em: EntityManager,\n adjustments: CoverageAdjustment[]\n): Promise<void> {\n if (!adjustments.length) return\n const knex = (em as any).getConnection().getKnex() as Knex\n const aggregated = aggregateAdjustments(adjustments)\n for (const entry of aggregated) {\n const scope = entry.scope\n const existing = await fetchCoverageRow(knex, scope)\n const currentBase = existing ? toCount(existing.base_count) : 0\n const currentIndex = existing ? toCount(existing.indexed_count) : 0\n const currentVector = existing ? toCount(existing.vector_indexed_count) : 0\n const nextBase = Math.max(currentBase + entry.deltaBase, 0)\n const nextIndex = Math.max(currentIndex + entry.deltaIndex, 0)\n const nextVector = Math.max(currentVector + entry.deltaVector, 0)\n\n await upsertCoverageRow(knex, scope, {\n baseCount: nextBase,\n indexedCount: nextIndex,\n vectorIndexedCount: nextVector,\n })\n }\n}\n\nexport async function deleteCoverageForEntity(knex: Knex, entityType: string): Promise<void> {\n if (!entityType) return\n await knex('entity_index_coverage').where({ entity_type: entityType }).del()\n}\n\nasync function tableHasColumn(knex: Knex, table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (COLUMN_CACHE.has(key)) return COLUMN_CACHE.get(key)!\n const exists = await knex('information_schema.columns')\n .where({ table_schema: 'public', table_name: table, column_name: column })\n .first()\n const present = !!exists\n COLUMN_CACHE.set(key, present)\n return present\n}\n\nexport async function refreshCoverageSnapshot(\n em: EntityManager,\n scope: CoverageScope,\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n\n const knex = (em as any).getConnection().getKnex() as Knex\n const baseTable = resolveEntityTableName(em, entityType)\n\n const hasOrg = await tableHasColumn(knex, baseTable, 'organization_id')\n const hasTenant = await tableHasColumn(knex, baseTable, 'tenant_id')\n const hasDeleted = await tableHasColumn(knex, baseTable, 'deleted_at')\n\n if (organizationId !== null && !hasOrg) return\n if (tenantId !== null && !hasTenant) return\n\n let baseQuery = knex({ b: baseTable }).count({ count: '*' })\n if (organizationId !== null && hasOrg) baseQuery = baseQuery.where('b.organization_id', organizationId)\n if (tenantId !== null && hasTenant) baseQuery = baseQuery.where('b.tenant_id', tenantId)\n if (!withDeleted && hasDeleted) baseQuery = baseQuery.whereNull('b.deleted_at')\n\n const baseRow = await baseQuery.first()\n const baseCount = toCount(baseRow?.count)\n\n let indexQuery = knex({ ei: 'entity_indexes' })\n .count({ count: '*' })\n .where('ei.entity_type', entityType)\n if (organizationId !== null) indexQuery = indexQuery.where('ei.organization_id', organizationId)\n if (tenantId !== null) indexQuery = indexQuery.where('ei.tenant_id', tenantId)\n if (!withDeleted) indexQuery = indexQuery.whereNull('ei.deleted_at')\n\n const indexRow = await indexQuery.first()\n const indexCount = toCount(indexRow?.count)\n\n // Count vector entries directly from database\n let vectorCount: number | undefined\n const hasVectorTable = await tableHasColumn(knex, 'vector_search', 'entity_id')\n if (hasVectorTable && typeof tenantId === 'string' && tenantId.length > 0) {\n try {\n let vectorQuery = knex('vector_search')\n .count({ count: 1 })\n .where('entity_id', entityType)\n .where('tenant_id', tenantId)\n if (organizationId !== null) {\n vectorQuery = vectorQuery.where('organization_id', organizationId)\n }\n const vectorRow = await vectorQuery.first()\n vectorCount = toCount(vectorRow?.count)\n } catch (err) {\n console.warn('[query_index] Failed to resolve vector count for coverage snapshot', {\n entityType,\n tenantId,\n organizationId,\n error: err instanceof Error ? err.message : err,\n })\n vectorCount = undefined\n }\n }\n\n await writeCoverageCounts(em, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorCount,\n })\n}\n\nexport async function writeCoverageCounts(\n em: EntityManager,\n scope: CoverageScope,\n counts: { baseCount?: number; indexedCount?: number; vectorCount?: number }\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const knex = (em as any).getConnection().getKnex() as Knex\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n const existing = await fetchCoverageRow(knex, {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n })\n const baseCount = counts.baseCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.baseCount)))\n : Math.max(0, Math.trunc(toCount(existing?.base_count)))\n const indexCount = counts.indexedCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.indexedCount)))\n : Math.max(0, Math.trunc(toCount(existing?.indexed_count)))\n const vectorCount = counts.vectorCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.vectorCount)))\n : Math.max(0, Math.trunc(toCount(existing?.vector_indexed_count)))\n await upsertCoverageRow(knex, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorIndexedCount: vectorCount,\n })\n}\n\ntype AggregatedAdjustment = {\n scope: CoverageScope\n deltaBase: number\n deltaIndex: number\n deltaVector: number\n}\n\nfunction aggregateAdjustments(adjustments: CoverageAdjustment[]): AggregatedAdjustment[] {\n const map = new Map<string, AggregatedAdjustment>()\n for (const adj of adjustments) {\n if (!adj?.entityType) continue\n const deltaBase = Number.isFinite(adj.deltaBase) ? adj.deltaBase : 0\n const deltaIndex = Number.isFinite(adj.deltaIndex) ? adj.deltaIndex : 0\n const deltaVector = Number.isFinite(adj.deltaVector) ? adj.deltaVector! : 0\n if (deltaBase === 0 && deltaIndex === 0 && deltaVector === 0) continue\n const scope: CoverageScope = {\n entityType: adj.entityType,\n tenantId: adj.tenantId ?? null,\n organizationId: adj.organizationId ?? null,\n withDeleted: adj.withDeleted === true,\n }\n const key = scopeKey(scope)\n const existing = map.get(key)\n if (existing) {\n existing.deltaBase += deltaBase\n existing.deltaIndex += deltaIndex\n existing.deltaVector += deltaVector\n } else {\n map.set(key, { scope, deltaBase, deltaIndex, deltaVector })\n }\n }\n return Array.from(map.values())\n}\n\nfunction scopeKey(scope: CoverageScope): string {\n const tenant = scope.tenantId ?? '__tenant_null__'\n const org = normalizeOrganizationForStore(scope.organizationId ?? null)\n const deleted = scope.withDeleted === true ? '1' : '0'\n return `${scope.entityType}|${tenant}|${org}|${deleted}`\n}\n\nexport function createCoverageAdjustments(input: CoverageDeltaInput): CoverageAdjustment[] {\n const entityType = String(input.entityType || '')\n if (!entityType) return []\n const baseDelta = Number.isFinite(input.baseDelta) ? input.baseDelta : 0\n const indexDelta = Number.isFinite(input.indexDelta) ? input.indexDelta : 0\n const vectorDelta = Number.isFinite(input.vectorDelta) ? input.vectorDelta! : 0\n if (baseDelta === 0 && indexDelta === 0 && vectorDelta === 0) return []\n const withDeleted = input.withDeleted === true\n const tenantId = input.tenantId ?? null\n const organizationId = input.organizationId ?? null\n return [\n {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n deltaBase: baseDelta,\n deltaIndex: indexDelta,\n deltaVector: vectorDelta,\n },\n ]\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { Knex } from 'knex'\nimport { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\n\nexport type CoverageScope = {\n entityType: string\n tenantId?: string | null\n organizationId?: string | null\n withDeleted?: boolean\n}\n\ntype CoverageRow = {\n base_count: unknown\n indexed_count: unknown\n vector_indexed_count: unknown\n refreshed_at: Date | string | null\n}\n\nexport type CoverageAdjustment = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n deltaBase: number\n deltaIndex: number\n deltaVector?: number\n}\n\nexport type CoverageDeltaInput = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n baseDelta: number\n indexDelta: number\n vectorDelta?: number\n}\n\nconst COLUMN_CACHE = new Map<string, boolean>()\nconst GLOBAL_ORGANIZATION_PLACEHOLDER = '00000000-0000-0000-0000-000000000000'\nexport const COVERAGE_ORG_PLACEHOLDER = GLOBAL_ORGANIZATION_PLACEHOLDER\n\nfunction toCount(value: unknown): number {\n if (typeof value === 'number') return Number.isFinite(value) ? value : 0\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n }\n if (value != null && typeof (value as { valueOf: () => number }).valueOf === 'function') {\n const parsed = Number((value as { valueOf: () => number }).valueOf())\n return Number.isFinite(parsed) ? parsed : 0\n }\n return 0\n}\n\nfunction normalizeOrganizationForStore(orgId: string | null | undefined): string {\n return orgId ?? GLOBAL_ORGANIZATION_PLACEHOLDER\n}\n\nfunction applyOrganizationCondition(\n qb: Knex.QueryBuilder<any, any>,\n column: string,\n organizationId: string | null | undefined\n) {\n const stored = normalizeOrganizationForStore(organizationId ?? null)\n if (stored === GLOBAL_ORGANIZATION_PLACEHOLDER) {\n qb.andWhere((sub) => {\n sub.whereNull(column).orWhere(column, GLOBAL_ORGANIZATION_PLACEHOLDER)\n })\n } else {\n qb.andWhere(column, stored)\n }\n}\n\nasync function fetchCoverageRow(\n knex: Knex,\n scope: CoverageScope\n): Promise<(CoverageRow & { organization_id: string | null }) | null> {\n const { entityType, tenantId, organizationId, withDeleted } = scope\n const row = await knex('entity_index_coverage')\n .select(['base_count', 'indexed_count', 'vector_indexed_count', 'refreshed_at', 'organization_id'])\n .where('entity_type', entityType)\n .where('tenant_id', tenantId ?? null)\n .where('with_deleted', withDeleted === true)\n .modify((qb) => applyOrganizationCondition(qb, 'organization_id', organizationId ?? null))\n .orderBy('refreshed_at', 'desc')\n .first<CoverageRow & { organization_id: string | null }>()\n return row ?? null\n}\n\nasync function pruneDuplicateCoverageRows(\n knex: Knex,\n scope: CoverageScope,\n keepId: string | null\n) {\n const query = knex('entity_index_coverage')\n .where('entity_type', scope.entityType)\n .where('tenant_id', scope.tenantId ?? null)\n .where('with_deleted', scope.withDeleted === true)\n .modify((qb) => applyOrganizationCondition(qb, 'organization_id', scope.organizationId ?? null))\n if (keepId) {\n await query.andWhereNot('id', keepId).del()\n } else {\n await query.del()\n }\n}\n\nasync function upsertCoverageRow(\n knex: Knex,\n scope: CoverageScope,\n counts: { baseCount: number; indexedCount: number; vectorIndexedCount: number }\n) {\n const storedOrgId = normalizeOrganizationForStore(scope.organizationId ?? null)\n if (scope.organizationId == null) {\n await knex('entity_index_coverage')\n .where('entity_type', scope.entityType)\n .where('tenant_id', scope.tenantId ?? null)\n .where('with_deleted', scope.withDeleted === true)\n .whereNull('organization_id')\n .del()\n }\n\n const rows = await knex('entity_index_coverage')\n .insert({\n entity_type: scope.entityType,\n tenant_id: scope.tenantId ?? null,\n organization_id: storedOrgId,\n with_deleted: scope.withDeleted === true,\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: knex.fn.now(),\n })\n .onConflict(['entity_type', 'tenant_id', 'organization_id', 'with_deleted'])\n .merge({\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: knex.fn.now(),\n })\n .returning<{ id: string }[]>('id')\n\n const keepId = rows?.[0]?.id ?? null\n await pruneDuplicateCoverageRows(knex, scope, keepId)\n}\n\nexport async function readCoverageSnapshot(\n knex: Knex,\n scope: CoverageScope\n): Promise<(CoverageRow & { baseCount: number; indexedCount: number; vectorIndexedCount: number }) | null> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return null\n const row = await fetchCoverageRow(knex, {\n entityType,\n tenantId: scope.tenantId ?? null,\n organizationId: scope.organizationId ?? null,\n withDeleted: scope.withDeleted === true,\n })\n if (!row) return null\n const refreshedAt = row.refreshed_at instanceof Date ? row.refreshed_at : (row.refreshed_at ? new Date(row.refreshed_at) : null)\n return {\n base_count: row.base_count,\n indexed_count: row.indexed_count,\n vector_indexed_count: row.vector_indexed_count,\n refreshed_at: refreshedAt ?? null,\n baseCount: toCount(row.base_count),\n indexedCount: toCount(row.indexed_count),\n vectorIndexedCount: toCount(row.vector_indexed_count),\n }\n}\n\nexport async function applyCoverageAdjustments(\n em: EntityManager,\n adjustments: CoverageAdjustment[]\n): Promise<void> {\n if (!adjustments.length) return\n const knex = (em as any).getConnection().getKnex() as Knex\n const aggregated = aggregateAdjustments(adjustments)\n for (const entry of aggregated) {\n const scope = entry.scope\n const existing = await fetchCoverageRow(knex, scope)\n const currentBase = existing ? toCount(existing.base_count) : 0\n const currentIndex = existing ? toCount(existing.indexed_count) : 0\n const currentVector = existing ? toCount(existing.vector_indexed_count) : 0\n const nextBase = Math.max(currentBase + entry.deltaBase, 0)\n const nextIndex = Math.max(currentIndex + entry.deltaIndex, 0)\n const nextVector = Math.max(currentVector + entry.deltaVector, 0)\n\n await upsertCoverageRow(knex, scope, {\n baseCount: nextBase,\n indexedCount: nextIndex,\n vectorIndexedCount: nextVector,\n })\n }\n}\n\nexport async function deleteCoverageForEntity(knex: Knex, entityType: string): Promise<void> {\n if (!entityType) return\n await knex('entity_index_coverage').where({ entity_type: entityType }).del()\n}\n\nasync function tableHasColumn(knex: Knex, table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (COLUMN_CACHE.has(key)) return COLUMN_CACHE.get(key)!\n const exists = await knex('information_schema.columns')\n .whereRaw('table_schema = current_schema()')\n .where({ table_name: table, column_name: column })\n .first()\n const present = !!exists\n COLUMN_CACHE.set(key, present)\n return present\n}\n\nexport async function refreshCoverageSnapshot(\n em: EntityManager,\n scope: CoverageScope,\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n\n const knex = (em as any).getConnection().getKnex() as Knex\n const baseTable = resolveEntityTableName(em, entityType)\n\n const hasOrg = await tableHasColumn(knex, baseTable, 'organization_id')\n const hasTenant = await tableHasColumn(knex, baseTable, 'tenant_id')\n const hasDeleted = await tableHasColumn(knex, baseTable, 'deleted_at')\n\n if (organizationId !== null && !hasOrg) return\n if (tenantId !== null && !hasTenant) return\n\n let baseQuery = knex({ b: baseTable }).count({ count: '*' })\n if (organizationId !== null && hasOrg) baseQuery = baseQuery.where('b.organization_id', organizationId)\n if (tenantId !== null && hasTenant) baseQuery = baseQuery.where('b.tenant_id', tenantId)\n if (!withDeleted && hasDeleted) baseQuery = baseQuery.whereNull('b.deleted_at')\n\n const baseRow = await baseQuery.first()\n const baseCount = toCount(baseRow?.count)\n\n let indexQuery = knex({ ei: 'entity_indexes' })\n .count({ count: '*' })\n .where('ei.entity_type', entityType)\n if (organizationId !== null) indexQuery = indexQuery.where('ei.organization_id', organizationId)\n if (tenantId !== null) indexQuery = indexQuery.where('ei.tenant_id', tenantId)\n if (!withDeleted) indexQuery = indexQuery.whereNull('ei.deleted_at')\n\n const indexRow = await indexQuery.first()\n const indexCount = toCount(indexRow?.count)\n\n // Count vector entries directly from database\n let vectorCount: number | undefined\n const hasVectorTable = await tableHasColumn(knex, 'vector_search', 'entity_id')\n if (hasVectorTable && typeof tenantId === 'string' && tenantId.length > 0) {\n try {\n let vectorQuery = knex('vector_search')\n .count({ count: 1 })\n .where('entity_id', entityType)\n .where('tenant_id', tenantId)\n if (organizationId !== null) {\n vectorQuery = vectorQuery.where('organization_id', organizationId)\n }\n const vectorRow = await vectorQuery.first()\n vectorCount = toCount(vectorRow?.count)\n } catch (err) {\n console.warn('[query_index] Failed to resolve vector count for coverage snapshot', {\n entityType,\n tenantId,\n organizationId,\n error: err instanceof Error ? err.message : err,\n })\n vectorCount = undefined\n }\n }\n\n await writeCoverageCounts(em, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorCount,\n })\n}\n\nexport async function writeCoverageCounts(\n em: EntityManager,\n scope: CoverageScope,\n counts: { baseCount?: number; indexedCount?: number; vectorCount?: number }\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const knex = (em as any).getConnection().getKnex() as Knex\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n const existing = await fetchCoverageRow(knex, {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n })\n const baseCount = counts.baseCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.baseCount)))\n : Math.max(0, Math.trunc(toCount(existing?.base_count)))\n const indexCount = counts.indexedCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.indexedCount)))\n : Math.max(0, Math.trunc(toCount(existing?.indexed_count)))\n const vectorCount = counts.vectorCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.vectorCount)))\n : Math.max(0, Math.trunc(toCount(existing?.vector_indexed_count)))\n await upsertCoverageRow(knex, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorIndexedCount: vectorCount,\n })\n}\n\ntype AggregatedAdjustment = {\n scope: CoverageScope\n deltaBase: number\n deltaIndex: number\n deltaVector: number\n}\n\nfunction aggregateAdjustments(adjustments: CoverageAdjustment[]): AggregatedAdjustment[] {\n const map = new Map<string, AggregatedAdjustment>()\n for (const adj of adjustments) {\n if (!adj?.entityType) continue\n const deltaBase = Number.isFinite(adj.deltaBase) ? adj.deltaBase : 0\n const deltaIndex = Number.isFinite(adj.deltaIndex) ? adj.deltaIndex : 0\n const deltaVector = Number.isFinite(adj.deltaVector) ? adj.deltaVector! : 0\n if (deltaBase === 0 && deltaIndex === 0 && deltaVector === 0) continue\n const scope: CoverageScope = {\n entityType: adj.entityType,\n tenantId: adj.tenantId ?? null,\n organizationId: adj.organizationId ?? null,\n withDeleted: adj.withDeleted === true,\n }\n const key = scopeKey(scope)\n const existing = map.get(key)\n if (existing) {\n existing.deltaBase += deltaBase\n existing.deltaIndex += deltaIndex\n existing.deltaVector += deltaVector\n } else {\n map.set(key, { scope, deltaBase, deltaIndex, deltaVector })\n }\n }\n return Array.from(map.values())\n}\n\nfunction scopeKey(scope: CoverageScope): string {\n const tenant = scope.tenantId ?? '__tenant_null__'\n const org = normalizeOrganizationForStore(scope.organizationId ?? null)\n const deleted = scope.withDeleted === true ? '1' : '0'\n return `${scope.entityType}|${tenant}|${org}|${deleted}`\n}\n\nexport function createCoverageAdjustments(input: CoverageDeltaInput): CoverageAdjustment[] {\n const entityType = String(input.entityType || '')\n if (!entityType) return []\n const baseDelta = Number.isFinite(input.baseDelta) ? input.baseDelta : 0\n const indexDelta = Number.isFinite(input.indexDelta) ? input.indexDelta : 0\n const vectorDelta = Number.isFinite(input.vectorDelta) ? input.vectorDelta! : 0\n if (baseDelta === 0 && indexDelta === 0 && vectorDelta === 0) return []\n const withDeleted = input.withDeleted === true\n const tenantId = input.tenantId ?? null\n const organizationId = input.organizationId ?? null\n return [\n {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n deltaBase: baseDelta,\n deltaIndex: indexDelta,\n deltaVector: vectorDelta,\n },\n ]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.4.6-develop-
|
|
3
|
+
"version": "0.4.6-develop-15c18897fc",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
}
|
|
208
208
|
},
|
|
209
209
|
"dependencies": {
|
|
210
|
-
"@open-mercato/shared": "0.4.6-develop-
|
|
210
|
+
"@open-mercato/shared": "0.4.6-develop-15c18897fc",
|
|
211
211
|
"@types/html-to-text": "^9.0.4",
|
|
212
212
|
"@types/semver": "^7.5.8",
|
|
213
213
|
"@xyflow/react": "^12.6.0",
|
|
@@ -22,7 +22,7 @@ export class Migration20251116191744 extends Migration {
|
|
|
22
22
|
if not exists (
|
|
23
23
|
select 1
|
|
24
24
|
from information_schema.columns
|
|
25
|
-
where table_schema =
|
|
25
|
+
where table_schema = current_schema()
|
|
26
26
|
and table_name = 'catalog_product_variant_relations'
|
|
27
27
|
and column_name = 'child_product_id'
|
|
28
28
|
) then
|
|
@@ -32,7 +32,7 @@ export class Migration20251116191744 extends Migration {
|
|
|
32
32
|
if exists (
|
|
33
33
|
select 1
|
|
34
34
|
from information_schema.columns
|
|
35
|
-
where table_schema =
|
|
35
|
+
where table_schema = current_schema()
|
|
36
36
|
and table_name = 'catalog_product_variant_relations'
|
|
37
37
|
and column_name = 'child_variant_id'
|
|
38
38
|
) then
|
|
@@ -88,7 +88,7 @@ export class Migration20251116191744 extends Migration {
|
|
|
88
88
|
if exists (
|
|
89
89
|
select 1
|
|
90
90
|
from information_schema.columns
|
|
91
|
-
where table_schema =
|
|
91
|
+
where table_schema = current_schema()
|
|
92
92
|
and table_name = 'catalog_product_variant_relations'
|
|
93
93
|
and column_name = 'child_product_id'
|
|
94
94
|
) then
|
|
@@ -98,7 +98,7 @@ export class Migration20251116191744 extends Migration {
|
|
|
98
98
|
if exists (
|
|
99
99
|
select 1
|
|
100
100
|
from information_schema.columns
|
|
101
|
-
where table_schema =
|
|
101
|
+
where table_schema = current_schema()
|
|
102
102
|
and table_name = 'catalog_product_variant_relations'
|
|
103
103
|
and column_name = 'child_variant_id'
|
|
104
104
|
) then
|
|
@@ -613,6 +613,7 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
|
|
|
613
613
|
linkedInUrl: profile.linkedInUrl,
|
|
614
614
|
twitterUrl: profile.twitterUrl,
|
|
615
615
|
companyEntityId: profile.company ? (typeof profile.company === 'string' ? profile.company : profile.company.id) : null,
|
|
616
|
+
updatedAt: profile.updatedAt.toISOString(),
|
|
616
617
|
}
|
|
617
618
|
: null,
|
|
618
619
|
customFields,
|
|
@@ -777,6 +778,7 @@ const personDetailResponseSchema = z.object({
|
|
|
777
778
|
linkedInUrl: z.string().nullable().optional(),
|
|
778
779
|
twitterUrl: z.string().nullable().optional(),
|
|
779
780
|
companyEntityId: z.string().uuid().nullable().optional(),
|
|
781
|
+
updatedAt: z.string(),
|
|
780
782
|
})
|
|
781
783
|
.nullable(),
|
|
782
784
|
customFields: z.record(z.string(), z.unknown()),
|
|
@@ -2644,7 +2644,8 @@ async function warnIfStressTestSchemaChanged(knex: any) {
|
|
|
2644
2644
|
for (const [table, requiredColumns] of Object.entries(STRESS_TEST_REQUIRED_COLUMNS)) {
|
|
2645
2645
|
const rows = await knex('information_schema.columns')
|
|
2646
2646
|
.select('column_name')
|
|
2647
|
-
.
|
|
2647
|
+
.whereRaw('table_schema = current_schema()')
|
|
2648
|
+
.where({ table_name: table })
|
|
2648
2649
|
const existing = new Set(rows.map((row: { column_name: string }) => row.column_name))
|
|
2649
2650
|
const missing = requiredColumns.filter((column) => !existing.has(column))
|
|
2650
2651
|
if (missing.length) warnings.push(`${table}: missing ${missing.join(', ')}`)
|
|
@@ -662,6 +662,15 @@ const updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string
|
|
|
662
662
|
profile.company = await resolveCompanyReference(em, parsed.companyEntityId, record.organizationId, record.tenantId)
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
const profileFieldsUpdated = [
|
|
666
|
+
parsed.firstName, parsed.lastName, parsed.preferredName, parsed.jobTitle,
|
|
667
|
+
parsed.department, parsed.seniority, parsed.timezone, parsed.linkedInUrl,
|
|
668
|
+
parsed.twitterUrl, parsed.companyEntityId,
|
|
669
|
+
].some((v) => v !== undefined)
|
|
670
|
+
if (profileFieldsUpdated) {
|
|
671
|
+
record.updatedAt = new Date()
|
|
672
|
+
}
|
|
673
|
+
|
|
665
674
|
if (parsed.displayName !== undefined) {
|
|
666
675
|
const nextDisplayName = parsed.displayName.trim()
|
|
667
676
|
if (!nextDisplayName) {
|
|
@@ -203,7 +203,8 @@ async function tableHasColumn(knex: Knex, table: string, column: string): Promis
|
|
|
203
203
|
const key = `${table}.${column}`
|
|
204
204
|
if (COLUMN_CACHE.has(key)) return COLUMN_CACHE.get(key)!
|
|
205
205
|
const exists = await knex('information_schema.columns')
|
|
206
|
-
.
|
|
206
|
+
.whereRaw('table_schema = current_schema()')
|
|
207
|
+
.where({ table_name: table, column_name: column })
|
|
207
208
|
.first()
|
|
208
209
|
const present = !!exists
|
|
209
210
|
COLUMN_CACHE.set(key, present)
|