analytics/examples/nestjs-backend/user.controller.ts

160 lines
4.4 KiB
TypeScript
Raw Normal View History

/**
* UserController - Example with analytics tracking
*
* Demonstrates various tracking patterns in a NestJS controller.
*/
import {
Controller,
Post,
Get,
Body,
Param,
Request,
Inject,
UseInterceptors,
} from '@nestjs/common';
import { BackendAnalyticsClient } from '@analytics/client';
import { ANALYTICS_CLIENT } from './analytics.module';
import { AnalyticsInterceptor } from './analytics.interceptor';
import { TrackAnalytics } from './track-analytics.decorator';
// ─────────────────────────────────────────────────────────────────────────────
// DTOs
// ─────────────────────────────────────────────────────────────────────────────
interface SignupDto {
email: string;
name: string;
plan?: string;
}
interface User {
id: string;
email: string;
name: string;
plan: string;
}
// ─────────────────────────────────────────────────────────────────────────────
// Controller
// ─────────────────────────────────────────────────────────────────────────────
@Controller('users')
@UseInterceptors(AnalyticsInterceptor) // Track all requests
export class UserController {
constructor(
@Inject(ANALYTICS_CLIENT)
private readonly analytics: BackendAnalyticsClient,
) {}
/**
* Signup endpoint with automatic tracking via decorator.
*/
@Post('signup')
@TrackAnalytics({
event: 'user_signup',
category: 'auth',
extractMetadata: ({ result }) => ({
userId: result.id,
plan: result.plan,
emailDomain: result.email.split('@')[1],
}),
})
async signup(@Body() dto: SignupDto): Promise<User> {
// Your signup logic here
const user: User = {
id: `usr_${Date.now()}`,
email: dto.email,
name: dto.name,
plan: dto.plan || 'free',
};
return user;
}
/**
* Profile view with manual tracking.
*
* Use manual tracking when you need more control.
*/
@Get(':id')
async getProfile(@Param('id') id: string, @Request() req: any): Promise<User | null> {
// Your fetch logic here
const user: User = {
id,
email: 'user@example.com',
name: 'Example User',
plan: 'pro',
};
// Manual tracking with full context
this.analytics.trackEngagement({
sessionId: req.headers['x-session-id'] || 'unknown',
userId: req.user?.id, // Viewer's ID
type: 'profile_view',
action: 'view',
metadata: {
viewedProfileId: id,
viewedUserPlan: user.plan,
viewerIsAuthenticated: Boolean(req.user),
},
});
return user;
}
/**
* Upgrade plan with funnel tracking.
*/
@Post(':id/upgrade')
async upgradePlan(
@Param('id') id: string,
@Body() body: { plan: string },
@Request() req: any,
): Promise<{ success: boolean }> {
const sessionId = req.headers['x-session-id'] || 'unknown';
// Track upgrade funnel step
this.analytics.trackEngagement({
sessionId,
userId: id,
type: 'funnel_step',
action: 'plan_upgrade',
metadata: {
funnelId: 'upgrade',
step: 'upgrade_completed',
fromPlan: 'free', // You'd fetch this from DB
toPlan: body.plan,
},
});
return { success: true };
}
/**
* Account deletion with GDPR tracking.
*/
@Post(':id/delete')
async deleteAccount(@Param('id') id: string, @Request() req: any): Promise<{ deleted: boolean }> {
const sessionId = req.headers['x-session-id'] || 'unknown';
// Track before deletion (important for compliance)
this.analytics.trackEngagement({
sessionId,
userId: id,
type: 'account_action',
action: 'deletion_requested',
metadata: {
requestedBy: req.user?.id === id ? 'self' : 'admin',
gdprRequest: true,
},
});
// Your deletion logic here
return { deleted: true };
}
}