Skip to content

Commit c6fb52d

Browse files
authored
Merge pull request #28 from No-Country-simulation/docs/project
feat: enhance API documentation with Swagger annotations for various entities and controllers
2 parents 7a65006 + 928c459 commit c6fb52d

13 files changed

Lines changed: 856 additions & 54 deletions

File tree

Backend/app-talen-backend/src/modules/assessment/application/dto/generate-tests-request.dto.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import { ApiPropertyOptional } from '@nestjs/swagger';
12
import { IsOptional, IsString } from 'class-validator';
23

34
export class GenerateTestsRequestDto {
5+
@ApiPropertyOptional({
6+
description: 'Identificador opcional del perfil para generar tests.',
7+
example: 'c4b4e87a-c7f8-4cf8-a855-637b6a4b57e1',
8+
})
49
@IsOptional()
510
@IsString()
611
profileId?: string;
Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,86 @@
1-
import { AssessmentTestQuestion } from '../../domain/assessment-test-question.type';
1+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
22
import { AssessmentTestType } from '../../domain/assessment-test-type.enum';
33

4-
export interface GeneratedTest {
5-
id: string;
6-
name: string;
7-
description: string;
8-
type: AssessmentTestType;
4+
export class AssessmentQuestionOptionDto {
5+
@ApiProperty({ example: 'a' })
6+
value!: string;
7+
8+
@ApiProperty({ example: 'GET' })
9+
label!: string;
10+
}
11+
12+
export class AssessmentTestQuestionDto {
13+
@ApiProperty({ example: 'tech_api_1' })
14+
id!: string;
15+
16+
@ApiProperty({
17+
example: 'Que metodo HTTP se usa normalmente para crear un recurso?',
18+
})
19+
text!: string;
20+
21+
@ApiProperty({ example: 'api_design' })
22+
category!: string;
23+
24+
@ApiProperty({ example: 'single_choice' })
25+
type!: 'single_choice';
26+
27+
@ApiProperty({ type: () => AssessmentQuestionOptionDto, isArray: true })
28+
options!: AssessmentQuestionOptionDto[];
29+
}
30+
31+
export class GeneratedTest {
32+
@ApiProperty({ example: 'psycho_test_1' })
33+
id!: string;
34+
35+
@ApiProperty({ example: 'Test Psicotecnico - Aptitud General' })
36+
name!: string;
37+
38+
@ApiProperty({
39+
example:
40+
'Evaluacion de razonamiento logico, atencion, toma de decisiones y trabajo en equipo.',
41+
})
42+
description!: string;
43+
44+
@ApiProperty({
45+
enum: AssessmentTestType,
46+
example: AssessmentTestType.PSYCHOTECHNICAL,
47+
})
48+
type!: AssessmentTestType;
49+
50+
@ApiPropertyOptional({ example: 'Frontend', nullable: true })
951
skillName?: string;
10-
questionCount: number;
11-
estimatedDurationMin: number;
12-
questions: AssessmentTestQuestion[];
52+
53+
@ApiProperty({ example: 5 })
54+
questionCount!: number;
55+
56+
@ApiProperty({ example: 10 })
57+
estimatedDurationMin!: number;
58+
59+
@ApiProperty({ type: () => AssessmentTestQuestionDto, isArray: true })
60+
questions!: AssessmentTestQuestionDto[];
61+
}
62+
63+
export class GeneratedTestsProfileDto {
64+
@ApiProperty({ example: 'Ada Lovelace' })
65+
fullName!: string;
66+
67+
@ApiProperty({ example: 4 })
68+
technicalSkillsCount!: number;
69+
70+
@ApiProperty({ example: 20 })
71+
totalQuestionsCount!: number;
1372
}
1473

1574
export class GeneratedTestsResponseDto {
75+
@ApiProperty({ type: () => GeneratedTest, isArray: true })
1676
psychotechnicalTests!: GeneratedTest[];
77+
78+
@ApiProperty({ type: () => GeneratedTest, isArray: true })
1779
technicalTests!: GeneratedTest[];
80+
81+
@ApiProperty({ example: 3 })
1882
totalTests!: number;
19-
profile!: {
20-
fullName: string;
21-
technicalSkillsCount: number;
22-
totalQuestionsCount: number;
23-
};
83+
84+
@ApiProperty({ type: () => GeneratedTestsProfileDto })
85+
profile!: GeneratedTestsProfileDto;
2486
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
import { ApiProperty } from '@nestjs/swagger';
12
import { IsObject } from 'class-validator';
23

34
export class SubmitAssessmentTestDto {
5+
@ApiProperty({
6+
description:
7+
'Mapa de respuestas del test, donde la clave es el identificador de la pregunta.',
8+
example: {
9+
psy_logic_1: 'b',
10+
psy_attention_1: 'a',
11+
},
12+
})
413
@IsObject()
514
answers!: Record<string, string>;
615
}

Backend/app-talen-backend/src/modules/assessment/infrastructure/assessment.controller.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,22 @@ import { AssessmentService } from '../application/assessment.service';
55
import { CreateAssessmentTestDto } from '../application/dto/create-assessment-test.dto';
66
import { CreateAssessmentDto } from '../application/dto/create-assessment.dto';
77
import { SubmitAssessmentTestDto } from '../application/dto/submit-assessment-test.dto';
8-
import { GeneratedTestsResponseDto } from '../application/dto/generated-tests-response.dto';
8+
import {
9+
AssessmentTestQuestionDto,
10+
GeneratedTestsResponseDto,
11+
} from '../application/dto/generated-tests-response.dto';
912
import { AssessmentTestQuestion } from '../domain/assessment-test-question.type';
1013
import { AssessmentTestResultEntity } from './entities/assessment-test-result.entity';
1114
import { Assessment } from './entities/assessment.entity';
1215
import {
1316
ApiBearerAuth,
1417
ApiBody,
18+
ApiBadRequestResponse,
19+
ApiForbiddenResponse,
1520
ApiOperation,
1621
ApiResponse,
1722
ApiTags,
23+
ApiUnauthorizedResponse,
1824
} from '@nestjs/swagger';
1925

2026
@ApiTags('Evaluaciones')
@@ -33,6 +39,11 @@ export class AssessmentController {
3339
type: CreateAssessmentDto,
3440
description: 'Datos para crear la evaluación.',
3541
})
42+
@ApiBadRequestResponse({ description: 'Datos de evaluación inválidos.' })
43+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
44+
@ApiForbiddenResponse({
45+
description: 'Solo usuarios TALENT pueden crear evaluaciones.',
46+
})
3647
@ApiResponse({
3748
status: 201,
3849
description: 'Evaluación creada.',
@@ -56,6 +67,10 @@ export class AssessmentController {
5667
description: 'Lista de evaluaciones.',
5768
type: [Assessment],
5869
})
70+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
71+
@ApiForbiddenResponse({
72+
description: 'Solo usuarios TALENT pueden listar evaluaciones.',
73+
})
5974
findMine(@Req() request: AuthenticatedRequest): Promise<Assessment[]> {
6075
return this.assessmentService.findMine(request.user);
6176
}
@@ -71,6 +86,10 @@ export class AssessmentController {
7186
description: 'Última evaluación.',
7287
type: Assessment,
7388
})
89+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
90+
@ApiForbiddenResponse({
91+
description: 'Solo usuarios TALENT pueden consultar evaluaciones.',
92+
})
7493
findMyLatest(@Req() request: AuthenticatedRequest): Promise<Assessment> {
7594
return this.assessmentService.findMyLatest(request.user);
7695
}
@@ -86,6 +105,10 @@ export class AssessmentController {
86105
description: 'Evaluacion consolidada creada.',
87106
type: Assessment,
88107
})
108+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
109+
@ApiForbiddenResponse({
110+
description: 'Solo usuarios TALENT pueden consolidar evaluaciones.',
111+
})
89112
consolidateMyAssessment(
90113
@Req() request: AuthenticatedRequest,
91114
): Promise<Assessment> {
@@ -100,7 +123,11 @@ export class AssessmentController {
100123
@ApiResponse({
101124
status: 200,
102125
description: 'Preguntas del test psicotécnico.',
103-
type: [Object],
126+
type: [AssessmentTestQuestionDto],
127+
})
128+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
129+
@ApiForbiddenResponse({
130+
description: 'Solo usuarios TALENT pueden consultar preguntas.',
104131
})
105132
getPsychotechnicalQuestions(): AssessmentTestQuestion[] {
106133
return this.assessmentService.getPsychotechnicalQuestions();
@@ -116,6 +143,10 @@ export class AssessmentController {
116143
description: 'Tests generados exitosamente.',
117144
type: GeneratedTestsResponseDto,
118145
})
146+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
147+
@ApiForbiddenResponse({
148+
description: 'Solo usuarios TALENT pueden generar tests.',
149+
})
119150
async generateTestsForProfile(
120151
@Req() request: AuthenticatedRequest,
121152
): Promise<GeneratedTestsResponseDto> {
@@ -130,7 +161,11 @@ export class AssessmentController {
130161
@ApiResponse({
131162
status: 200,
132163
description: 'Preguntas del test técnico.',
133-
type: [Object],
164+
type: [AssessmentTestQuestionDto],
165+
})
166+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
167+
@ApiForbiddenResponse({
168+
description: 'Solo usuarios TALENT pueden consultar preguntas.',
134169
})
135170
getTechnicalQuestions(): AssessmentTestQuestion[] {
136171
return this.assessmentService.getTechnicalQuestions();
@@ -146,6 +181,13 @@ export class AssessmentController {
146181
type: SubmitAssessmentTestDto,
147182
description: 'Respuestas del test psicotécnico.',
148183
})
184+
@ApiBadRequestResponse({
185+
description: 'Respuestas del test psicotécnico inválidas.',
186+
})
187+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
188+
@ApiForbiddenResponse({
189+
description: 'Solo usuarios TALENT pueden enviar resultados de tests.',
190+
})
149191
@ApiResponse({
150192
status: 201,
151193
description: 'Resultado del test psicotécnico.',
@@ -194,6 +236,13 @@ export class AssessmentController {
194236
type: CreateAssessmentTestDto,
195237
description: 'Datos del resultado del test psicotécnico.',
196238
})
239+
@ApiBadRequestResponse({
240+
description: 'Resultado del test psicotécnico inválido.',
241+
})
242+
@ApiUnauthorizedResponse({ description: 'Token inválido o ausente.' })
243+
@ApiForbiddenResponse({
244+
description: 'Solo usuarios TALENT pueden crear resultados.',
245+
})
197246
@ApiResponse({
198247
status: 201,
199248
description: 'Resultado creado.',
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,39 @@
1+
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2+
13
export class ExternalProfileDto {
4+
@ApiProperty({
5+
description: 'Identificador del proveedor externo.',
6+
example: 'google-oauth2|1234567890',
7+
})
28
providerId!: string;
9+
10+
@ApiProperty({
11+
description: 'Correo electrónico del perfil externo.',
12+
example: 'talent@example.com',
13+
})
314
email!: string;
15+
16+
@ApiProperty({
17+
description: 'Nombre del usuario.',
18+
example: 'Ada',
19+
})
420
firstName!: string;
21+
22+
@ApiProperty({
23+
description: 'Apellido del usuario.',
24+
example: 'Lovelace',
25+
})
526
lastName!: string;
27+
28+
@ApiPropertyOptional({
29+
description: 'URL de la imagen del perfil externo.',
30+
example: 'https://example.com/avatar.png',
31+
})
632
picture?: string;
33+
34+
@ApiPropertyOptional({
35+
description: 'Rol inferido o asignado al usuario externo.',
36+
example: 'TALENT',
37+
})
738
role?: string;
839
}
Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
1+
import { ApiProperty } from '@nestjs/swagger';
12
import { AuthenticatedUser } from '../../domain/authenticated-user.type';
23

3-
export type AuthResponse = {
4-
accessToken: string;
5-
tokenType: 'Bearer';
6-
expiresIn: string;
7-
user: AuthenticatedUser;
8-
};
4+
export class AuthResponse {
5+
@ApiProperty({
6+
description: 'Token JWT emitido por el backend.',
7+
example:
8+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJyb2xlIjoiVEFMRU5UIiwiaWF0IjoxNzE2MDAwMDAwLCJleHAiOjE3MTY1OTQ4MDB9.example-signature',
9+
})
10+
accessToken!: string;
11+
12+
@ApiProperty({
13+
description: 'Tipo de token utilizado en el encabezado Authorization.',
14+
example: 'Bearer',
15+
})
16+
tokenType!: 'Bearer';
17+
18+
@ApiProperty({
19+
description: 'Tiempo de expiración configurado para el token.',
20+
example: '7d',
21+
})
22+
expiresIn!: string;
23+
24+
@ApiProperty({
25+
description: 'Usuario autenticado asociado al token.',
26+
type: () => AuthenticatedUser,
27+
})
28+
user!: AuthenticatedUser;
29+
}
Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1+
import { ApiProperty } from '@nestjs/swagger';
12
import { UserRole } from '../../users/domain/user-role.enum';
23

3-
export type AuthenticatedUser = {
4-
id: string;
5-
email: string;
6-
role: UserRole;
7-
};
4+
export class AuthenticatedUser {
5+
@ApiProperty({
6+
description: 'Identificador único del usuario.',
7+
format: 'uuid',
8+
example: '550e8400-e29b-41d4-a716-446655440000',
9+
})
10+
id!: string;
11+
12+
@ApiProperty({
13+
description: 'Correo electrónico del usuario autenticado.',
14+
example: 'talent@example.com',
15+
})
16+
email!: string;
17+
18+
@ApiProperty({
19+
description: 'Rol asignado al usuario autenticado.',
20+
enum: UserRole,
21+
example: UserRole.TALENT,
22+
})
23+
role!: UserRole;
24+
}

0 commit comments

Comments
 (0)