feat(collector): ✨ Add structured DTOs for user interaction tracking (TrackViewDto, TrackEngagementDto, TrackInteractionDto) with re-exports in collector/index.ts
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
ea3cddccde
commit
0e5e4dff58
4 changed files with 132 additions and 3 deletions
|
|
@ -1,4 +1,6 @@
|
|||
export * from './track-event.dto';
|
||||
export * from './track-view.dto';
|
||||
export * from './track-engagement.dto';
|
||||
export * from './track-interaction.dto';
|
||||
export * from './client-device.dto';
|
||||
export * from './attribution.dto';
|
||||
|
|
|
|||
37
services/collector/src/dto/track-engagement.dto.ts
Normal file
37
services/collector/src/dto/track-engagement.dto.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsOptional, IsObject } from 'class-validator';
|
||||
|
||||
/**
|
||||
* Engagement event DTO — meaningful user interactions.
|
||||
* Matches EngagementEventData from @lilith/domain-events.
|
||||
*/
|
||||
export class TrackEngagementDto {
|
||||
@ApiProperty({ description: 'User ID (required for engagement events)' })
|
||||
@IsString()
|
||||
userId!: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Engagement metric type',
|
||||
enum: ['like', 'comment', 'share', 'subscribe', 'tip', 'purchase'],
|
||||
example: 'subscribe',
|
||||
})
|
||||
@IsString()
|
||||
metricType!: string;
|
||||
|
||||
@ApiProperty({ description: 'Target entity ID' })
|
||||
@IsString()
|
||||
targetId!: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Target entity type',
|
||||
enum: ['content', 'user', 'product', 'stream', 'profile'],
|
||||
example: 'profile',
|
||||
})
|
||||
@IsString()
|
||||
targetType!: string;
|
||||
|
||||
@ApiProperty({ description: 'Additional engagement metadata', required: false })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
60
services/collector/src/dto/track-interaction.dto.ts
Normal file
60
services/collector/src/dto/track-interaction.dto.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsString,
|
||||
IsOptional,
|
||||
IsObject,
|
||||
IsArray,
|
||||
IsNumber,
|
||||
ValidateNested,
|
||||
IsIn,
|
||||
} from 'class-validator';
|
||||
|
||||
/**
|
||||
* Single interaction event payload.
|
||||
* Matches InteractionEventPayload from @lilith/domain-events.
|
||||
*/
|
||||
export class InteractionEventDto {
|
||||
@ApiProperty({
|
||||
description: 'Interaction type',
|
||||
enum: ['click', 'scroll', 'funnel_step', 'resize'],
|
||||
example: 'click',
|
||||
})
|
||||
@IsString()
|
||||
@IsIn(['click', 'scroll', 'funnel_step', 'resize'])
|
||||
type!: 'click' | 'scroll' | 'funnel_step' | 'resize';
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Event-specific data (ClickEventData, ScrollEventData, FunnelStepData, or ResizeEventData)',
|
||||
})
|
||||
@IsObject()
|
||||
data!: Record<string, unknown>;
|
||||
|
||||
@ApiProperty({ description: 'Session ID from client' })
|
||||
@IsString()
|
||||
sessionId!: string;
|
||||
|
||||
@ApiProperty({ description: 'User ID if authenticated', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
userId?: string;
|
||||
|
||||
@ApiProperty({ description: 'Client-side timestamp (Unix epoch ms)' })
|
||||
@IsNumber()
|
||||
timestamp!: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch of interaction events DTO.
|
||||
* Matches the payload sent by @lilith/analytics-client flushInteractions().
|
||||
*/
|
||||
export class TrackInteractionBatchDto {
|
||||
@ApiProperty({
|
||||
description: 'Batch of interaction events',
|
||||
type: [InteractionEventDto],
|
||||
})
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => InteractionEventDto)
|
||||
events!: InteractionEventDto[];
|
||||
}
|
||||
|
|
@ -1,16 +1,46 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsString, IsOptional, IsObject, ValidateNested } from 'class-validator';
|
||||
import { IsString, IsOptional, IsObject, IsNumber, ValidateNested } from 'class-validator';
|
||||
import { ClientDeviceDto } from './client-device.dto';
|
||||
import { AttributionDto } from './attribution.dto';
|
||||
|
||||
/**
|
||||
* Page view tracking DTO
|
||||
*
|
||||
* Accepts both the collector's original shape (pageUrl) and the
|
||||
* @lilith/analytics-client ViewEventData shape (contentId + contentType).
|
||||
* The controller normalises both into the same TrackViewInput.
|
||||
*/
|
||||
export class TrackViewDto {
|
||||
@ApiProperty({ description: 'Full URL of the page being viewed' })
|
||||
@ApiProperty({ description: 'Full URL of the page being viewed', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
pageUrl!: string;
|
||||
pageUrl?: string;
|
||||
|
||||
@ApiProperty({ description: 'Content identifier (from analytics-client)', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
contentId?: string;
|
||||
|
||||
@ApiProperty({ description: 'Content type (page, post, video, etc.)', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
contentType?: string;
|
||||
|
||||
@ApiProperty({ description: 'Application name (from analytics-client)', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
app?: string;
|
||||
|
||||
@ApiProperty({ description: 'View duration in milliseconds', required: false })
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
duration?: number;
|
||||
|
||||
@ApiProperty({ description: 'Device type (mobile, tablet, desktop)', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
deviceType?: string;
|
||||
|
||||
@ApiProperty({ description: 'Referrer URL', required: false })
|
||||
@IsOptional()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue