import { Body, Controller, Get, Param, Post, Request, Sse, UsePipes, UseGuards, UnauthorizedException, type MessageEvent, } from "@nestjs/common"; import { RateLimitGuard, RateLimit } from "@bff/core/rate-limiting/index.js"; import { OrderOrchestrator } from "./services/order-orchestrator.service.js"; import type { RequestWithUser } from "@bff/modules/auth/auth.types.js"; import { Logger } from "nestjs-pino"; import { ZodValidationPipe } from "nestjs-zod"; import { createOrderRequestSchema, orderCreateResponseSchema, sfOrderIdParamSchema, type CreateOrderRequest, type SfOrderIdParam, } from "@customer-portal/domain/orders"; import { apiSuccessResponseSchema } from "@customer-portal/domain/common"; import { Observable } from "rxjs"; import { OrderEventsService } from "./services/order-events.service.js"; import { SalesforceReadThrottleGuard } from "@bff/integrations/salesforce/guards/salesforce-read-throttle.guard.js"; import { SalesforceWriteThrottleGuard } from "@bff/integrations/salesforce/guards/salesforce-write-throttle.guard.js"; @Controller("orders") @UseGuards(RateLimitGuard) export class OrdersController { constructor( private orderOrchestrator: OrderOrchestrator, private readonly orderEvents: OrderEventsService, private readonly logger: Logger ) {} private readonly createOrderResponseSchema = apiSuccessResponseSchema(orderCreateResponseSchema); @Post() @UseGuards(SalesforceWriteThrottleGuard) @RateLimit({ limit: 5, ttl: 60 }) // 5 order creations per minute @UsePipes(new ZodValidationPipe(createOrderRequestSchema)) async create(@Request() req: RequestWithUser, @Body() body: CreateOrderRequest) { this.logger.log( { userId: req.user?.id, orderType: body.orderType, skuCount: body.skus?.length || 0, }, "Order creation request received" ); try { const result = await this.orderOrchestrator.createOrder(req.user.id, body); return this.createOrderResponseSchema.parse({ success: true, data: result }); } catch (error) { this.logger.error( { error: error instanceof Error ? error.message : String(error), userId: req.user?.id, orderType: body.orderType, }, "Order creation failed" ); throw error; } } @Get("user") @UseGuards(SalesforceReadThrottleGuard) async getUserOrders(@Request() req: RequestWithUser) { return this.orderOrchestrator.getOrdersForUser(req.user.id); } @Get(":sfOrderId") @UsePipes(new ZodValidationPipe(sfOrderIdParamSchema)) @UseGuards(SalesforceReadThrottleGuard) async get(@Request() req: RequestWithUser, @Param() params: SfOrderIdParam) { if (!req.user?.id) { throw new UnauthorizedException("Authentication required"); } return this.orderOrchestrator.getOrderForUser(params.sfOrderId, req.user.id); } @Sse(":sfOrderId/events") @UsePipes(new ZodValidationPipe(sfOrderIdParamSchema)) streamOrderUpdates(@Param() params: SfOrderIdParam): Observable { return this.orderEvents.subscribe(params.sfOrderId); } // Note: Order provisioning has been moved to SalesforceProvisioningController // This controller now focuses only on customer-facing order operations }