import { Controller, HttpCode, Post, UploadedFile, UseInterceptors, } from '@nestjs/common'; import { Body } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { CustomerProfileService } from './customer-profile.service'; import { AdminUploadsService } from '../admin-uploads/admin-uploads.service'; import { CompleteProfileDto } from './dto/complete-profile.dto'; import { CurrentCustomer, CustomerAuth } from '../customer-auth/customer.guards'; import type { AuthenticatedCustomer } from '../customer-auth/customer-jwt.strategy'; /** See AdminUploadsController — the same locally-declared multer subset. */ interface UploadedMulterFile { originalname: string; mimetype: string; size: number; buffer: Buffer; } /** * The customer's own profile writes. * * Legacy endpoints: * POST file/create -> the PWA's SingleImageUploader posted here with the * customer token (routes/api.php:95, inside the * `auth:api-customer` group) * POST major/complete -> Major\CustomerController::complete * (routes/api.php:114) * * Both are mounted under /customer/me here so the customer surface stays in one * place. The subject always comes from the token — no id is accepted from the * client, per D21. */ @Controller('customer/me') export class CustomerProfileController { constructor( private readonly profile: CustomerProfileService, private readonly uploads: AdminUploadsService, ) {} /** * A customer uploading one of their own documents. * * The reference let the app upload through the very same `file/create` the * admin panel used, behind the customer guard (routes/api.php:95). The * target's copy of that route sits behind an ADMIN guard * (AdminUploadsController), which no app token can pass — so without this * route the page could not upload at all. * * It reuses AdminUploadsService unchanged, so the size limit, the MIME * whitelist and the stored-name scheme are identical on both paths. The * uploader is recorded as null rather than as an admin, because * `UploadedFile.uploadedByAdminUserId` is an AdminUser FK and this caller is * a customer; `purpose` carries the document kind instead. */ @CustomerAuth() @Post('documents') @HttpCode(200) @UseInterceptors(FileInterceptor('file')) upload( @UploadedFile() file: UploadedMulterFile | undefined, @Body('purpose') purpose: string | undefined, @CurrentCustomer() _me: AuthenticatedCustomer, ) { return this.uploads.store(file, purpose ?? 'customer-document', null); } /** Ports POST major/complete. The customer is the token's. */ @CustomerAuth() @Post('complete-profile') @HttpCode(200) complete(@Body() dto: CompleteProfileDto, @CurrentCustomer() me: AuthenticatedCustomer) { return this.profile.complete(me.id, dto); } }