@open-mercato/core 0.6.6-develop.6296.1.5e8bdfee17 → 0.6.6-develop.6300.1.08ff40c897
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/AGENTS.md +8 -0
- package/dist/generated/entities/module_config/index.js +4 -0
- package/dist/generated/entities/module_config/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +1 -1
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/configs/data/entities.js +15 -1
- package/dist/modules/configs/data/entities.js.map +2 -2
- package/dist/modules/configs/lib/module-config-service.js +52 -19
- package/dist/modules/configs/lib/module-config-service.js.map +3 -3
- package/dist/modules/configs/migrations/Migration20260617150000.js +21 -0
- package/dist/modules/configs/migrations/Migration20260617150000.js.map +7 -0
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -22
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +8 -7
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +6 -5
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/generated/entities/module_config/index.ts +2 -0
- package/generated/entity-fields-registry.ts +2 -0
- package/package.json +7 -7
- package/src/modules/auth/lib/setup-app.ts +1 -1
- package/src/modules/configs/data/entities.ts +17 -1
- package/src/modules/configs/lib/module-config-service.ts +83 -24
- package/src/modules/configs/migrations/.snapshot-open-mercato.json +41 -4
- package/src/modules/configs/migrations/.snapshot-openmercato.json +41 -4
- package/src/modules/configs/migrations/Migration20260617150000.ts +21 -0
- package/src/modules/customers/api/activities/route.ts +6 -0
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +29 -22
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +8 -7
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +6 -5
- package/dist/modules/customers/components/detail/CompanyDashboardTab.js +0 -133
- package/dist/modules/customers/components/detail/CompanyDashboardTab.js.map +0 -7
- package/src/modules/customers/components/detail/CompanyDashboardTab.tsx +0 -161
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/api/activities/route.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @deprecated Use /api/customers/interactions instead. This route is maintained\n * as a compatibility bridge per SPEC-046b and delegates writes to canonical\n * interaction commands.\n */\nimport { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerActivity, CustomerDeal, CustomerInteraction } from '../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { activityCreateSchema, activityUpdateSchema } from '../../data/validators'\nimport { createCustomersCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from '../openapi'\nimport {\n mapInteractionRecordToActivitySummary,\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n} from '../../lib/interactionCompatibility'\nimport { withOperationMetadata } from '../../lib/operationMetadata'\nimport { resolveCustomerInteractionFeatureFlags } from '../../lib/interactionFeatureFlags'\nimport { resolveCustomersRequestContext } from '../../lib/interactionRequestContext'\nimport { hydrateCanonicalInteractions } from '../../lib/interactionReadModel'\nimport { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'\nimport { buildEmailVisibilityMikroFilter } from '../../lib/visibilityFilter'\n\nconst listSchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n entityId: z.string().uuid().optional(),\n dealId: z.string().uuid().optional(),\n activityType: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.activities.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst activityCreateBodySchema = activityCreateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityUpdateBodySchema = activityUpdateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityDeleteBodySchema = z.object({\n id: z.string().uuid(),\n})\n\nconst ADAPTER_HEADERS = {\n Deprecation: 'true',\n Sunset: 'Tue, 30 Jun 2026 00:00:00 GMT',\n Link: '</api/customers/interactions>; rel=\"successor-version\"',\n}\n\n// Caps the per-source fetch window used by the deprecated merged (legacy +\n// canonical bridge) read path. Keeps memory bounded on tenants with large\n// activity history; deep-pagination beyond this window is not supported here \u2014\n// use /api/customers/interactions instead.\nconst MERGED_ACTIVITY_FETCH_CAP = 2000\n\ntype ActivityItem = {\n id: string\n activityType: string\n subject?: string | null\n body?: string | null\n occurredAt?: string | null\n createdAt: string\n appearanceIcon?: string | null\n appearanceColor?: string | null\n entityId?: string | null\n authorUserId?: string | null\n authorName?: string | null\n authorEmail?: string | null\n dealId?: string | null\n dealTitle?: string | null\n customValues?: Record<string, unknown> | null\n activityTypeLabel?: string | null\n}\n\ntype CanonicalActivityListResult = {\n items: ActivityItem[]\n total: number\n bridgeIds: Set<string>\n}\n\nfunction resolveGuardUserId(auth: {\n sub?: string | null\n userId?: string | null\n keyId?: string | null\n}): string {\n if (typeof auth.sub === 'string' && auth.sub.trim().length > 0) return auth.sub\n if (typeof auth.userId === 'string' && auth.userId.trim().length > 0) return auth.userId\n if (typeof auth.keyId === 'string' && auth.keyId.trim().length > 0) return auth.keyId\n return 'system'\n}\n\nfunction withAdapterHeaders(response: Response): Response {\n const headers = new Headers(response.headers)\n Object.entries(ADAPTER_HEADERS).forEach(([key, value]) => headers.set(key, value))\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n}\n\nasync function legacyAdaptersDisabledResponse(): Promise<Response> {\n const { translate } = await resolveTranslations()\n return withAdapterHeaders(NextResponse.json(\n {\n error: translate(\n 'customers.interactions.legacyAdapters.disabled',\n 'This legacy adapter has been disabled. Use /api/customers/interactions instead.',\n ),\n },\n { status: 410 },\n ))\n}\n\nfunction buildLegacyOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction buildCanonicalOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction resolveActivitySortValue(item: ActivityItem, sortField: string | undefined): number {\n const raw =\n sortField === 'createdAt'\n ? item.createdAt\n : item.occurredAt ?? item.createdAt\n const timestamp = raw ? new Date(raw).getTime() : Number.NaN\n return Number.isNaN(timestamp) ? 0 : timestamp\n}\n\nfunction sortActivityItems(\n items: ActivityItem[],\n sortField: string | undefined,\n sortDir: 'asc' | 'desc',\n): ActivityItem[] {\n return [...items].sort((left, right) => {\n const leftValue = resolveActivitySortValue(left, sortField)\n const rightValue = resolveActivitySortValue(right, sortField)\n if (leftValue === rightValue) {\n return sortDir === 'asc'\n ? left.id.localeCompare(right.id)\n : right.id.localeCompare(left.id)\n }\n return sortDir === 'asc' ? leftValue - rightValue : rightValue - leftValue\n })\n}\n\nfunction paginateActivityItems(\n items: ActivityItem[],\n page: number,\n pageSize: number,\n): { items: ActivityItem[]; total: number } {\n const start = (page - 1) * pageSize\n return {\n items: items.slice(start, start + pageSize),\n total: items.length,\n }\n}\n\nexport async function decorateActivityItems(\n em: EntityManager,\n items: ActivityItem[],\n decryptionScope?: { tenantId: string; organizationId: string },\n): Promise<ActivityItem[]> {\n if (items.length === 0) return items\n\n const authorIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.authorUserId === 'string' ? item.authorUserId : null))\n .filter((value): value is string => !!value),\n ),\n )\n const dealIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.dealId === 'string' ? item.dealId : null))\n .filter((value): value is string => !!value),\n ),\n )\n\n if (dealIds.length > 0 && (!decryptionScope?.tenantId || !decryptionScope?.organizationId)) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(400, {\n error: translate('customers.errors.tenant_required', 'Tenant context is required'),\n })\n }\n\n const [users, deals] = await Promise.all([\n authorIds.length > 0 ? em.find(User, { id: { $in: authorIds } }) : Promise.resolve([]),\n dealIds.length > 0 && decryptionScope\n ? findWithDecryption(\n em,\n CustomerDeal,\n { id: { $in: dealIds }, tenantId: decryptionScope.tenantId, organizationId: decryptionScope.organizationId },\n undefined,\n decryptionScope,\n )\n : Promise.resolve([]),\n ])\n\n const userMap = new Map(\n users.map((user) => [\n user.id,\n {\n name: user.name ?? null,\n email: user.email ?? null,\n },\n ]),\n )\n const dealMap = new Map(deals.map((deal) => [deal.id, deal.title]))\n\n return items.map((item) => ({\n ...item,\n activityTypeLabel: item.activityType,\n authorName: item.authorUserId ? userMap.get(item.authorUserId)?.name ?? null : null,\n authorEmail: item.authorUserId ? userMap.get(item.authorUserId)?.email ?? null : null,\n dealTitle: item.dealId ? dealMap.get(item.dealId) ?? null : null,\n }))\n}\n\nfunction mapLegacyActivity(activity: CustomerActivity): ActivityItem {\n return {\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n entityId: typeof activity.entity === 'string' ? activity.entity : activity.entity.id,\n authorUserId: activity.authorUserId ?? null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n customValues: null,\n }\n}\n\nasync function listCanonicalActivities(\n em: EntityManager,\n container: { resolve: (name: string) => unknown },\n auth: { tenantId: string | null; orgId: string | null; sub?: string | null; userId?: string | null; keyId?: string | null },\n selectedOrganizationId: string | null,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { includeDeleted?: boolean; source?: string | string[] | null; paginate?: boolean },\n): Promise<CanonicalActivityListResult> {\n const where: Record<string, unknown> = {\n tenantId,\n interactionType: { $ne: 'task' },\n }\n if (!options?.includeDeleted) {\n where.deletedAt = null\n }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.dealId = query.dealId\n if (query.activityType) where.interactionType = query.activityType\n if (options?.source) {\n where.source = Array.isArray(options.source) ? { $in: options.source } : options.source\n }\n\n // Per-user email privacy: exclude other users' private email interactions from\n // the deprecated /activities surface (mirrors the /interactions Layer-1 filter).\n // v1 strict owner-only \u2014 no admin bypass (the filter ignores caller features).\n const activitiesViewerUserId = auth.keyId ? null : (auth.sub ?? auth.userId ?? null)\n Object.assign(\n where,\n buildEmailVisibilityMikroFilter({\n currentUserId: activitiesViewerUserId,\n userFeatures: undefined,\n }),\n )\n\n const findOptions = {\n orderBy: buildCanonicalOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerInteraction, where, findOptions)\n : (await em.findAndCount(CustomerInteraction, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.filter((row) => !row.deletedAt).length\n : await em.count(CustomerInteraction, where)\n\n const activeRows = rows.filter((row) => !row.deletedAt)\n const hydrated = await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId,\n interactions: activeRows,\n })\n const items = hydrated.map((row) => ({\n ...mapInteractionRecordToActivitySummary(row),\n customValues: row.customValues ?? null,\n activityTypeLabel: row.interactionType,\n }))\n\n return {\n items,\n total,\n bridgeIds: new Set(rows.map((row) => row.id)),\n }\n}\n\nasync function listLegacyActivities(\n em: EntityManager,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { paginate?: boolean },\n selectedOrganizationId?: string | null,\n): Promise<{ items: ActivityItem[]; total: number }> {\n const where: Record<string, unknown> = { tenantId }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.deal = query.dealId\n if (query.activityType) where.activityType = query.activityType\n\n const findOptions = {\n populate: ['entity', 'deal'] as const,\n orderBy: buildLegacyOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerActivity, where, findOptions)\n : (await em.findAndCount(CustomerActivity, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.length\n : await em.count(CustomerActivity, where)\n\n return {\n items: await decorateActivityItems(\n em,\n rows.map(mapLegacyActivity),\n selectedOrganizationId ? { tenantId, organizationId: selectedOrganizationId } : undefined,\n ),\n total,\n }\n}\n\nexport async function GET(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url)\n const query = listSchema.parse(Object.fromEntries(url.searchParams))\n const {\n auth,\n em,\n organizationIds,\n container,\n selectedOrganizationId,\n } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n\n const sortDir = query.sortDir ?? 'desc'\n\n const result = flags.unified\n ? await listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n query,\n )\n : await (async () => {\n const windowSize = Math.min(\n MERGED_ACTIVITY_FETCH_CAP,\n Math.max(query.pageSize, query.page * query.pageSize + query.pageSize),\n )\n const windowedQuery = { ...query, page: 1, pageSize: windowSize }\n const [legacy, canonical] = await Promise.all([\n listLegacyActivities(\n em,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n { paginate: true },\n selectedOrganizationId,\n ),\n listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n {\n includeDeleted: true,\n paginate: true,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n },\n ),\n ])\n const merged = sortActivityItems(\n [\n ...legacy.items.filter((item) => !canonical.bridgeIds.has(item.id)),\n ...canonical.items,\n ],\n query.sortField,\n sortDir,\n )\n const paged = paginateActivityItems(merged, query.page, query.pageSize)\n return {\n items: paged.items,\n total: paged.total,\n }\n })()\n\n return withAdapterHeaders(\n NextResponse.json({\n items: result.items,\n total: result.total,\n page: query.page,\n pageSize: query.pageSize,\n totalPages: Math.max(1, Math.ceil(result.total / query.pageSize)),\n }),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.get failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function POST(request: Request): Promise<Response> {\n try {\n const { commandContext, container, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityCreateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute('customers.interactions.create', {\n input: {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId ?? auth.orgId,\n entityId: parsed.entityId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? null,\n body: parsed.body ?? null,\n occurredAt: parsed.occurredAt ?? null,\n status: parsed.occurredAt ? 'done' : 'planned',\n dealId: parsed.dealId ?? null,\n authorUserId: parsed.authorUserId ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const createdId =\n result && typeof result === 'object' && 'interactionId' in result && typeof result.interactionId === 'string'\n ? result.interactionId\n : result && typeof result === 'object' && 'id' in result && typeof result.id === 'string'\n ? result.id\n : null\n\n return withAdapterHeaders(\n withOperationMetadata(\n NextResponse.json({ id: createdId }, { status: 201 }),\n logEntry,\n { resourceKind: 'customers.activity', resourceId: createdId },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.post failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function PUT(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityUpdateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n\n const { logEntry } = await commandBus.execute('customers.interactions.update', {\n input: {\n id: interactionId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? undefined,\n body: parsed.body ?? undefined,\n occurredAt: parsed.occurredAt ?? undefined,\n status: parsed.occurredAt ? 'done' : undefined,\n dealId: parsed.dealId ?? undefined,\n authorUserId: parsed.authorUserId ?? undefined,\n appearanceIcon: parsed.appearanceIcon ?? undefined,\n appearanceColor: parsed.appearanceColor ?? undefined,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n return withAdapterHeaders(\n withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind: 'customers.activity', resourceId: parsed.id },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.put failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function DELETE(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityDeleteBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n const { logEntry } = await commandBus.execute('customers.interactions.delete', {\n input: { id: interactionId },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return withAdapterHeaders(\n withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind: 'customers.activity', resourceId: parsed.id },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.delete failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nconst activityListItemSchema = z\n .object({\n id: z.string().uuid(),\n activityType: z.string(),\n subject: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n entityId: z.string().uuid().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n activityTypeLabel: z.string().nullable().optional(),\n })\n .passthrough()\n\nconst activityCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = createCustomersCrudOpenApi({\n resourceName: 'Activity',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(activityListItemSchema),\n create: {\n schema: activityCreateBodySchema,\n responseSchema: activityCreateResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Creates a timeline activity. Use POST /api/customers/interactions instead.',\n },\n update: {\n schema: activityUpdateBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Updates an activity. Use PUT /api/customers/interactions instead.',\n },\n del: {\n schema: activityDeleteBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Deletes an activity. Use DELETE /api/customers/interactions instead.',\n },\n})\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * @deprecated Use /api/customers/interactions instead. This route is maintained\n * as a compatibility bridge per SPEC-046b and delegates writes to canonical\n * interaction commands.\n */\nimport { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerActivity, CustomerDeal, CustomerInteraction } from '../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { activityCreateSchema, activityUpdateSchema } from '../../data/validators'\nimport { createCustomersCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from '../openapi'\nimport {\n mapInteractionRecordToActivitySummary,\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n} from '../../lib/interactionCompatibility'\nimport { withOperationMetadata } from '../../lib/operationMetadata'\nimport { resolveCustomerInteractionFeatureFlags } from '../../lib/interactionFeatureFlags'\nimport { resolveCustomersRequestContext } from '../../lib/interactionRequestContext'\nimport { hydrateCanonicalInteractions } from '../../lib/interactionReadModel'\nimport { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'\nimport { buildEmailVisibilityMikroFilter } from '../../lib/visibilityFilter'\n\nconst listSchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n entityId: z.string().uuid().optional(),\n dealId: z.string().uuid().optional(),\n activityType: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.activities.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst activityCreateBodySchema = activityCreateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityUpdateBodySchema = activityUpdateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityDeleteBodySchema = z.object({\n id: z.string().uuid(),\n})\n\nconst ADAPTER_HEADERS = {\n Deprecation: 'true',\n Sunset: 'Tue, 30 Jun 2026 00:00:00 GMT',\n Link: '</api/customers/interactions>; rel=\"successor-version\"',\n}\n\n// Caps the per-source fetch window used by the deprecated merged (legacy +\n// canonical bridge) read path. Keeps memory bounded on tenants with large\n// activity history; deep-pagination beyond this window is not supported here \u2014\n// use /api/customers/interactions instead.\n//\n// Audited for the #3386 rollout (P2): this merged path sorts only on\n// non-encrypted system timestamps (createdAt/occurredAt, see\n// resolveActivitySortValue), so the #3278 two-phase *encrypted*-sort migration\n// is intentionally not applied here. Merge-order correctness across the page\n// boundary is covered by __tests__/merged-pagination.test.ts.\nconst MERGED_ACTIVITY_FETCH_CAP = 2000\n\ntype ActivityItem = {\n id: string\n activityType: string\n subject?: string | null\n body?: string | null\n occurredAt?: string | null\n createdAt: string\n appearanceIcon?: string | null\n appearanceColor?: string | null\n entityId?: string | null\n authorUserId?: string | null\n authorName?: string | null\n authorEmail?: string | null\n dealId?: string | null\n dealTitle?: string | null\n customValues?: Record<string, unknown> | null\n activityTypeLabel?: string | null\n}\n\ntype CanonicalActivityListResult = {\n items: ActivityItem[]\n total: number\n bridgeIds: Set<string>\n}\n\nfunction resolveGuardUserId(auth: {\n sub?: string | null\n userId?: string | null\n keyId?: string | null\n}): string {\n if (typeof auth.sub === 'string' && auth.sub.trim().length > 0) return auth.sub\n if (typeof auth.userId === 'string' && auth.userId.trim().length > 0) return auth.userId\n if (typeof auth.keyId === 'string' && auth.keyId.trim().length > 0) return auth.keyId\n return 'system'\n}\n\nfunction withAdapterHeaders(response: Response): Response {\n const headers = new Headers(response.headers)\n Object.entries(ADAPTER_HEADERS).forEach(([key, value]) => headers.set(key, value))\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n}\n\nasync function legacyAdaptersDisabledResponse(): Promise<Response> {\n const { translate } = await resolveTranslations()\n return withAdapterHeaders(NextResponse.json(\n {\n error: translate(\n 'customers.interactions.legacyAdapters.disabled',\n 'This legacy adapter has been disabled. Use /api/customers/interactions instead.',\n ),\n },\n { status: 410 },\n ))\n}\n\nfunction buildLegacyOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction buildCanonicalOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction resolveActivitySortValue(item: ActivityItem, sortField: string | undefined): number {\n const raw =\n sortField === 'createdAt'\n ? item.createdAt\n : item.occurredAt ?? item.createdAt\n const timestamp = raw ? new Date(raw).getTime() : Number.NaN\n return Number.isNaN(timestamp) ? 0 : timestamp\n}\n\nfunction sortActivityItems(\n items: ActivityItem[],\n sortField: string | undefined,\n sortDir: 'asc' | 'desc',\n): ActivityItem[] {\n return [...items].sort((left, right) => {\n const leftValue = resolveActivitySortValue(left, sortField)\n const rightValue = resolveActivitySortValue(right, sortField)\n if (leftValue === rightValue) {\n return sortDir === 'asc'\n ? left.id.localeCompare(right.id)\n : right.id.localeCompare(left.id)\n }\n return sortDir === 'asc' ? leftValue - rightValue : rightValue - leftValue\n })\n}\n\nfunction paginateActivityItems(\n items: ActivityItem[],\n page: number,\n pageSize: number,\n): { items: ActivityItem[]; total: number } {\n const start = (page - 1) * pageSize\n return {\n items: items.slice(start, start + pageSize),\n total: items.length,\n }\n}\n\nexport async function decorateActivityItems(\n em: EntityManager,\n items: ActivityItem[],\n decryptionScope?: { tenantId: string; organizationId: string },\n): Promise<ActivityItem[]> {\n if (items.length === 0) return items\n\n const authorIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.authorUserId === 'string' ? item.authorUserId : null))\n .filter((value): value is string => !!value),\n ),\n )\n const dealIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.dealId === 'string' ? item.dealId : null))\n .filter((value): value is string => !!value),\n ),\n )\n\n if (dealIds.length > 0 && (!decryptionScope?.tenantId || !decryptionScope?.organizationId)) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(400, {\n error: translate('customers.errors.tenant_required', 'Tenant context is required'),\n })\n }\n\n const [users, deals] = await Promise.all([\n authorIds.length > 0 ? em.find(User, { id: { $in: authorIds } }) : Promise.resolve([]),\n dealIds.length > 0 && decryptionScope\n ? findWithDecryption(\n em,\n CustomerDeal,\n { id: { $in: dealIds }, tenantId: decryptionScope.tenantId, organizationId: decryptionScope.organizationId },\n undefined,\n decryptionScope,\n )\n : Promise.resolve([]),\n ])\n\n const userMap = new Map(\n users.map((user) => [\n user.id,\n {\n name: user.name ?? null,\n email: user.email ?? null,\n },\n ]),\n )\n const dealMap = new Map(deals.map((deal) => [deal.id, deal.title]))\n\n return items.map((item) => ({\n ...item,\n activityTypeLabel: item.activityType,\n authorName: item.authorUserId ? userMap.get(item.authorUserId)?.name ?? null : null,\n authorEmail: item.authorUserId ? userMap.get(item.authorUserId)?.email ?? null : null,\n dealTitle: item.dealId ? dealMap.get(item.dealId) ?? null : null,\n }))\n}\n\nfunction mapLegacyActivity(activity: CustomerActivity): ActivityItem {\n return {\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n entityId: typeof activity.entity === 'string' ? activity.entity : activity.entity.id,\n authorUserId: activity.authorUserId ?? null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n customValues: null,\n }\n}\n\nasync function listCanonicalActivities(\n em: EntityManager,\n container: { resolve: (name: string) => unknown },\n auth: { tenantId: string | null; orgId: string | null; sub?: string | null; userId?: string | null; keyId?: string | null },\n selectedOrganizationId: string | null,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { includeDeleted?: boolean; source?: string | string[] | null; paginate?: boolean },\n): Promise<CanonicalActivityListResult> {\n const where: Record<string, unknown> = {\n tenantId,\n interactionType: { $ne: 'task' },\n }\n if (!options?.includeDeleted) {\n where.deletedAt = null\n }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.dealId = query.dealId\n if (query.activityType) where.interactionType = query.activityType\n if (options?.source) {\n where.source = Array.isArray(options.source) ? { $in: options.source } : options.source\n }\n\n // Per-user email privacy: exclude other users' private email interactions from\n // the deprecated /activities surface (mirrors the /interactions Layer-1 filter).\n // v1 strict owner-only \u2014 no admin bypass (the filter ignores caller features).\n const activitiesViewerUserId = auth.keyId ? null : (auth.sub ?? auth.userId ?? null)\n Object.assign(\n where,\n buildEmailVisibilityMikroFilter({\n currentUserId: activitiesViewerUserId,\n userFeatures: undefined,\n }),\n )\n\n const findOptions = {\n orderBy: buildCanonicalOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerInteraction, where, findOptions)\n : (await em.findAndCount(CustomerInteraction, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.filter((row) => !row.deletedAt).length\n : await em.count(CustomerInteraction, where)\n\n const activeRows = rows.filter((row) => !row.deletedAt)\n const hydrated = await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId,\n interactions: activeRows,\n })\n const items = hydrated.map((row) => ({\n ...mapInteractionRecordToActivitySummary(row),\n customValues: row.customValues ?? null,\n activityTypeLabel: row.interactionType,\n }))\n\n return {\n items,\n total,\n bridgeIds: new Set(rows.map((row) => row.id)),\n }\n}\n\nasync function listLegacyActivities(\n em: EntityManager,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { paginate?: boolean },\n selectedOrganizationId?: string | null,\n): Promise<{ items: ActivityItem[]; total: number }> {\n const where: Record<string, unknown> = { tenantId }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.deal = query.dealId\n if (query.activityType) where.activityType = query.activityType\n\n const findOptions = {\n populate: ['entity', 'deal'] as const,\n orderBy: buildLegacyOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerActivity, where, findOptions)\n : (await em.findAndCount(CustomerActivity, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.length\n : await em.count(CustomerActivity, where)\n\n return {\n items: await decorateActivityItems(\n em,\n rows.map(mapLegacyActivity),\n selectedOrganizationId ? { tenantId, organizationId: selectedOrganizationId } : undefined,\n ),\n total,\n }\n}\n\nexport async function GET(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url)\n const query = listSchema.parse(Object.fromEntries(url.searchParams))\n const {\n auth,\n em,\n organizationIds,\n container,\n selectedOrganizationId,\n } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n\n const sortDir = query.sortDir ?? 'desc'\n\n const result = flags.unified\n ? await listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n query,\n )\n : await (async () => {\n const windowSize = Math.min(\n MERGED_ACTIVITY_FETCH_CAP,\n Math.max(query.pageSize, query.page * query.pageSize + query.pageSize),\n )\n const windowedQuery = { ...query, page: 1, pageSize: windowSize }\n const [legacy, canonical] = await Promise.all([\n listLegacyActivities(\n em,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n { paginate: true },\n selectedOrganizationId,\n ),\n listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n {\n includeDeleted: true,\n paginate: true,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n },\n ),\n ])\n const merged = sortActivityItems(\n [\n ...legacy.items.filter((item) => !canonical.bridgeIds.has(item.id)),\n ...canonical.items,\n ],\n query.sortField,\n sortDir,\n )\n const paged = paginateActivityItems(merged, query.page, query.pageSize)\n return {\n items: paged.items,\n total: paged.total,\n }\n })()\n\n return withAdapterHeaders(\n NextResponse.json({\n items: result.items,\n total: result.total,\n page: query.page,\n pageSize: query.pageSize,\n totalPages: Math.max(1, Math.ceil(result.total / query.pageSize)),\n }),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.get failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function POST(request: Request): Promise<Response> {\n try {\n const { commandContext, container, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityCreateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result, logEntry } = await commandBus.execute('customers.interactions.create', {\n input: {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId ?? auth.orgId,\n entityId: parsed.entityId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? null,\n body: parsed.body ?? null,\n occurredAt: parsed.occurredAt ?? null,\n status: parsed.occurredAt ? 'done' : 'planned',\n dealId: parsed.dealId ?? null,\n authorUserId: parsed.authorUserId ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n const createdId =\n result && typeof result === 'object' && 'interactionId' in result && typeof result.interactionId === 'string'\n ? result.interactionId\n : result && typeof result === 'object' && 'id' in result && typeof result.id === 'string'\n ? result.id\n : null\n\n return withAdapterHeaders(\n withOperationMetadata(\n NextResponse.json({ id: createdId }, { status: 201 }),\n logEntry,\n { resourceKind: 'customers.activity', resourceId: createdId },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.post failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function PUT(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityUpdateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n\n const { logEntry } = await commandBus.execute('customers.interactions.update', {\n input: {\n id: interactionId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? undefined,\n body: parsed.body ?? undefined,\n occurredAt: parsed.occurredAt ?? undefined,\n status: parsed.occurredAt ? 'done' : undefined,\n dealId: parsed.dealId ?? undefined,\n authorUserId: parsed.authorUserId ?? undefined,\n appearanceIcon: parsed.appearanceIcon ?? undefined,\n appearanceColor: parsed.appearanceColor ?? undefined,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n return withAdapterHeaders(\n withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind: 'customers.activity', resourceId: parsed.id },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.put failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function DELETE(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityDeleteBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n const { logEntry } = await commandBus.execute('customers.interactions.delete', {\n input: { id: interactionId },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return withAdapterHeaders(\n withOperationMetadata(\n NextResponse.json({ ok: true }),\n logEntry,\n { resourceKind: 'customers.activity', resourceId: parsed.id },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.delete failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nconst activityListItemSchema = z\n .object({\n id: z.string().uuid(),\n activityType: z.string(),\n subject: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n entityId: z.string().uuid().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n activityTypeLabel: z.string().nullable().optional(),\n })\n .passthrough()\n\nconst activityCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = createCustomersCrudOpenApi({\n resourceName: 'Activity',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(activityListItemSchema),\n create: {\n schema: activityCreateBodySchema,\n responseSchema: activityCreateResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Creates a timeline activity. Use POST /api/customers/interactions instead.',\n },\n update: {\n schema: activityUpdateBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Updates an activity. Use PUT /api/customers/interactions instead.',\n },\n del: {\n schema: activityDeleteBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Deletes an activity. Use DELETE /api/customers/interactions instead.',\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -74,6 +74,11 @@ import { BulkActionsBar } from "./components/BulkActionsBar.js";
|
|
|
74
74
|
import { ChangeStageDialog } from "./components/ChangeStageDialog.js";
|
|
75
75
|
import { ChangeOwnerDialog } from "./components/ChangeOwnerDialog.js";
|
|
76
76
|
import { buildCrudExportUrl, deleteCrud } from "@open-mercato/ui/backend/utils/crud";
|
|
77
|
+
import {
|
|
78
|
+
readVersionedPreference,
|
|
79
|
+
writeVersionedPreference,
|
|
80
|
+
clearVersionedPreference
|
|
81
|
+
} from "@open-mercato/shared/lib/browser/versionedPreference";
|
|
77
82
|
import { runBulkDelete, groupBulkDeleteFailures } from "@open-mercato/ui/backend/utils/bulkDelete";
|
|
78
83
|
import {
|
|
79
84
|
fetchAssignableStaffMembers
|
|
@@ -87,33 +92,32 @@ const MIN_LANE_WIDTH = 240;
|
|
|
87
92
|
const MAX_LANE_WIDTH = 576;
|
|
88
93
|
const LANE_GAP = 14;
|
|
89
94
|
const LANE_WIDTHS_STORAGE_KEY_PREFIX = "kanban-lane-widths-v2";
|
|
95
|
+
const LANE_WIDTHS_STORAGE_VERSION = 1;
|
|
96
|
+
function isNumberRecord(value) {
|
|
97
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((v) => typeof v === "number");
|
|
98
|
+
}
|
|
90
99
|
function loadLaneWidths(scopeKey) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const raw = readVersionedPreference(
|
|
101
|
+
`${LANE_WIDTHS_STORAGE_KEY_PREFIX}:${scopeKey}`,
|
|
102
|
+
LANE_WIDTHS_STORAGE_VERSION,
|
|
103
|
+
isNumberRecord,
|
|
104
|
+
{},
|
|
105
|
+
{ legacyIsValid: isNumberRecord }
|
|
106
|
+
);
|
|
107
|
+
const out = {};
|
|
108
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
109
|
+
if (Number.isFinite(v) && v >= MIN_LANE_WIDTH && v <= MAX_LANE_WIDTH) {
|
|
110
|
+
out[k] = v;
|
|
102
111
|
}
|
|
103
|
-
return out;
|
|
104
|
-
} catch {
|
|
105
|
-
return {};
|
|
106
112
|
}
|
|
113
|
+
return out;
|
|
107
114
|
}
|
|
108
115
|
function saveLaneWidths(scopeKey, widths) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
window.localStorage.setItem(`${LANE_WIDTHS_STORAGE_KEY_PREFIX}:${scopeKey}`, JSON.stringify(widths));
|
|
115
|
-
}
|
|
116
|
-
} catch {
|
|
116
|
+
const key = `${LANE_WIDTHS_STORAGE_KEY_PREFIX}:${scopeKey}`;
|
|
117
|
+
if (Object.keys(widths).length === 0) {
|
|
118
|
+
clearVersionedPreference(key);
|
|
119
|
+
} else {
|
|
120
|
+
writeVersionedPreference(key, LANE_WIDTHS_STORAGE_VERSION, widths);
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
function normalizeAmount(value) {
|