@@ -8,8 +8,13 @@ import {
88 Query ,
99 Request ,
1010 UseGuards ,
11+ UseInterceptors ,
1112} from '@nestjs/common' ;
13+ import { ApiTags , ApiBearerAuth , ApiOperation , ApiOkResponse , ApiCreatedResponse , ApiHeader } from '@nestjs/swagger' ;
1214import { JwtAuthGuard } from '../../../auth/guards/jwt-auth.guard' ;
15+ import { Idempotent } from '../../idempotency/idempotency.decorator' ;
16+ import { IdempotencyGuard } from '../../idempotency/idempotency.guard' ;
17+ import { IdempotencyInterceptor } from '../../idempotency/idempotency.interceptor' ;
1318import { FxConversionService } from '../services/fx-conversion.service' ;
1419import {
1520 ConversionHistoryDto ,
@@ -19,6 +24,8 @@ import {
1924} from '../dto/fx-conversion.dto' ;
2025import { LoyaltyTier } from '../../loyalty/entities/loyalty-account.entity' ;
2126
27+ @ApiTags ( 'FX Conversion' )
28+ @ApiBearerAuth ( 'access-token' )
2229@UseGuards ( JwtAuthGuard )
2330@Controller ( 'fx' )
2431export class FxConversionController {
@@ -35,6 +42,8 @@ export class FxConversionController {
3542 * - regulatoryDisclosure text for the user's jurisdiction
3643 */
3744 @Get ( 'convert/quote' )
45+ @ApiOperation ( { summary : 'Get a locked FX conversion quote' } )
46+ @ApiOkResponse ( { description : 'Quote with locked rate, fees, and TTL' } )
3847 async getQuote ( @Request ( ) req , @Query ( ) dto : GetQuoteDto ) {
3948 const user = req . user ;
4049 return this . fxService . createQuote (
@@ -57,6 +66,12 @@ export class FxConversionController {
5766 */
5867 @Post ( 'convert' )
5968 @HttpCode ( HttpStatus . CREATED )
69+ @Idempotent ( )
70+ @UseGuards ( IdempotencyGuard )
71+ @UseInterceptors ( IdempotencyInterceptor )
72+ @ApiOperation ( { summary : 'Execute a currency conversion at a locked quote rate' } )
73+ @ApiCreatedResponse ( { description : 'Conversion executed successfully' } )
74+ @ApiHeader ( { name : 'Idempotency-Key' , description : 'Unique key to prevent duplicate conversions (min 16 chars)' , required : true } )
6075 async executeConversion ( @Request ( ) req , @Body ( ) dto : ExecuteConversionDto ) {
6176 return this . fxService . executeConversion ( req . user . id , dto ) ;
6277 }
@@ -72,6 +87,8 @@ export class FxConversionController {
7287 * Does NOT lock a quote — purely informational.
7388 */
7489 @Get ( 'fees' )
90+ @ApiOperation ( { summary : 'Get FX fee breakdown (informational, no quote lock)' } )
91+ @ApiOkResponse ( { description : 'Fee breakdown with mid-rate, markup and total cost' } )
7592 async getFees ( @Request ( ) req , @Query ( ) dto : GetFeesDto ) {
7693 return this . fxService . getFeeBreakdown (
7794 dto . fromCurrency . toUpperCase ( ) ,
@@ -87,6 +104,8 @@ export class FxConversionController {
87104 * Paginated conversion history — newest first.
88105 */
89106 @Get ( 'convert/history' )
107+ @ApiOperation ( { summary : 'Get paginated FX conversion history' } )
108+ @ApiOkResponse ( { description : 'Paginated conversion history' } )
90109 async getHistory ( @Request ( ) req , @Query ( ) dto : ConversionHistoryDto ) {
91110 return this . fxService . getHistory ( req . user . id , dto ) ;
92111 }
0 commit comments