import { Controller, Get, Query, Headers, UnauthorizedException, ParseIntPipe, DefaultValuePipe, } from '@nestjs/common'; import { GetReferralListUseCase } from '../../../application/use-cases/get-referral-list.use-case'; import { ReferralRelationshipRepository } from '../../../infrastructure/repositories/referral-relationship.repository'; import { ReferralRewardRepository } from '../../../infrastructure/repositories/referral-reward.repository'; import { ReferralStatus } from '../../../domain/entities/referral-relationship.entity'; import { RewardStatus } from '../../../domain/entities/referral-reward.entity'; import * as jwt from 'jsonwebtoken'; /** * Platform-admin endpoints for managing the referral system. * Requires JWT with platform_admin or platform_super_admin role. */ @Controller('api/v1/referral/admin') export class ReferralAdminController { constructor( private readonly getReferralList: GetReferralListUseCase, private readonly relationshipRepo: ReferralRelationshipRepository, private readonly rewardRepo: ReferralRewardRepository, ) {} /** GET /api/v1/referral/admin/relationships — all referral relationships */ @Get('relationships') async listRelationships( @Headers('authorization') auth: string, @Query('status') status: ReferralStatus | undefined, @Query('limit', new DefaultValuePipe(50), ParseIntPipe) limit: number, @Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number, ) { this.requireAdmin(auth); return this.relationshipRepo.findAll(status, Math.min(limit, 200), offset); } /** GET /api/v1/referral/admin/rewards — all reward records */ @Get('rewards') async listRewards( @Headers('authorization') auth: string, @Query('status') status: RewardStatus | undefined, @Query('limit', new DefaultValuePipe(50), ParseIntPipe) limit: number, @Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number, ) { this.requireAdmin(auth); return this.rewardRepo.findAll(status, Math.min(limit, 200), offset); } /** GET /api/v1/referral/admin/stats — global referral statistics */ @Get('stats') async getStats(@Headers('authorization') auth: string) { this.requireAdmin(auth); const [totalRel, activeRel, pendingRewards] = await Promise.all([ this.relationshipRepo.findAll(undefined, 1, 0).then((r) => r.total), this.relationshipRepo.findAll('ACTIVE', 1, 0).then((r) => r.total), this.rewardRepo.findAll('PENDING', 1, 0).then((r) => r.total), ]); return { totalReferrals: totalRel, activeReferrals: activeRel, pendingRewards, }; } private requireAdmin(auth: string) { if (!auth?.startsWith('Bearer ')) { throw new UnauthorizedException('Missing authorization header'); } const token = auth.slice(7); const secret = process.env.JWT_SECRET || 'dev-secret'; try { const payload = jwt.verify(token, secret) as any; const roles: string[] = Array.isArray(payload.roles) ? payload.roles : []; if ( !roles.includes('platform_admin') && !roles.includes('platform_super_admin') ) { throw new UnauthorizedException('Admin role required'); } } catch (err) { if (err instanceof UnauthorizedException) throw err; throw new UnauthorizedException('Invalid JWT'); } } }