Skip to content

Commit da0cadd

Browse files
github-actions[bot]chasprowebdevMarfuen
authored
create endpoints for Vendors (#1469)
Signed-off-by: Mariano Fuentes <marfuen98@gmail.com> Co-authored-by: chasprowebdev <chasgarciaprowebdev@gmail.com> Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
1 parent e6a67ed commit da0cadd

15 files changed

Lines changed: 1279 additions & 0 deletions

‎apps/api/src/app.module.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import { awsConfig } from './config/aws.config';
1111
import { HealthModule } from './health/health.module';
1212
import { OrganizationModule } from './organization/organization.module';
1313
import { TasksModule } from './tasks/tasks.module';
14+
import { VendorsModule } from './vendors/vendors.module';
1415
import { ContextModule } from './context/context.module';
1516

17+
1618
@Module({
1719
imports: [
1820
ConfigModule.forRoot({
@@ -25,6 +27,7 @@ import { ContextModule } from './context/context.module';
2527
}),
2628
AuthModule,
2729
OrganizationModule,
30+
VendorsModule,
2831
ContextModule,
2932
DevicesModule,
3033
DeviceAgentModule,
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString, IsNotEmpty, IsOptional, IsEnum, IsUrl } from 'class-validator';
3+
import {
4+
VendorCategory,
5+
VendorStatus,
6+
Likelihood,
7+
Impact
8+
} from '@trycompai/db';
9+
10+
export class CreateVendorDto {
11+
@ApiProperty({
12+
description: 'Vendor name',
13+
example: 'CloudTech Solutions Inc.',
14+
})
15+
@IsString()
16+
@IsNotEmpty()
17+
name: string;
18+
19+
@ApiProperty({
20+
description: 'Detailed description of the vendor and services provided',
21+
example: 'Cloud infrastructure provider offering AWS-like services including compute, storage, and networking solutions for enterprise customers.',
22+
})
23+
@IsString()
24+
@IsNotEmpty()
25+
description: string;
26+
27+
@ApiProperty({
28+
description: 'Vendor category',
29+
enum: VendorCategory,
30+
default: VendorCategory.other,
31+
example: VendorCategory.cloud,
32+
})
33+
@IsOptional()
34+
@IsEnum(VendorCategory)
35+
category?: VendorCategory;
36+
37+
@ApiProperty({
38+
description: 'Assessment status of the vendor',
39+
enum: VendorStatus,
40+
default: VendorStatus.not_assessed,
41+
example: VendorStatus.not_assessed,
42+
})
43+
@IsOptional()
44+
@IsEnum(VendorStatus)
45+
status?: VendorStatus;
46+
47+
@ApiProperty({
48+
description: 'Inherent probability of risk before controls',
49+
enum: Likelihood,
50+
default: Likelihood.very_unlikely,
51+
example: Likelihood.possible,
52+
})
53+
@IsOptional()
54+
@IsEnum(Likelihood)
55+
inherentProbability?: Likelihood;
56+
57+
@ApiProperty({
58+
description: 'Inherent impact of risk before controls',
59+
enum: Impact,
60+
default: Impact.insignificant,
61+
example: Impact.moderate,
62+
})
63+
@IsOptional()
64+
@IsEnum(Impact)
65+
inherentImpact?: Impact;
66+
67+
@ApiProperty({
68+
description: 'Residual probability after controls are applied',
69+
enum: Likelihood,
70+
default: Likelihood.very_unlikely,
71+
example: Likelihood.unlikely,
72+
})
73+
@IsOptional()
74+
@IsEnum(Likelihood)
75+
residualProbability?: Likelihood;
76+
77+
@ApiProperty({
78+
description: 'Residual impact after controls are applied',
79+
enum: Impact,
80+
default: Impact.insignificant,
81+
example: Impact.minor,
82+
})
83+
@IsOptional()
84+
@IsEnum(Impact)
85+
residualImpact?: Impact;
86+
87+
@ApiProperty({
88+
description: 'Vendor website URL',
89+
required: false,
90+
example: 'https://www.cloudtechsolutions.com',
91+
})
92+
@IsOptional()
93+
@IsUrl()
94+
website?: string;
95+
96+
@ApiProperty({
97+
description: 'ID of the user assigned to manage this vendor',
98+
required: false,
99+
example: 'mem_abc123def456',
100+
})
101+
@IsOptional()
102+
@IsString()
103+
assigneeId?: string;
104+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { PartialType } from '@nestjs/swagger';
2+
import { CreateVendorDto } from './create-vendor.dto';
3+
4+
export class UpdateVendorDto extends PartialType(CreateVendorDto) {}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import {
3+
VendorCategory,
4+
VendorStatus,
5+
Likelihood,
6+
Impact
7+
} from '@trycompai/db';
8+
9+
export class VendorResponseDto {
10+
@ApiProperty({
11+
description: 'Vendor ID',
12+
example: 'vnd_abc123def456',
13+
})
14+
id: string;
15+
16+
@ApiProperty({
17+
description: 'Vendor name',
18+
example: 'CloudTech Solutions Inc.',
19+
})
20+
name: string;
21+
22+
@ApiProperty({
23+
description: 'Detailed description of the vendor and services provided',
24+
example: 'Cloud infrastructure provider offering AWS-like services including compute, storage, and networking solutions for enterprise customers.',
25+
})
26+
description: string;
27+
28+
@ApiProperty({
29+
description: 'Vendor category',
30+
enum: VendorCategory,
31+
example: VendorCategory.cloud,
32+
})
33+
category: VendorCategory;
34+
35+
@ApiProperty({
36+
description: 'Assessment status of the vendor',
37+
enum: VendorStatus,
38+
example: VendorStatus.not_assessed,
39+
})
40+
status: VendorStatus;
41+
42+
@ApiProperty({
43+
description: 'Inherent probability of risk before controls',
44+
enum: Likelihood,
45+
example: Likelihood.possible,
46+
})
47+
inherentProbability: Likelihood;
48+
49+
@ApiProperty({
50+
description: 'Inherent impact of risk before controls',
51+
enum: Impact,
52+
example: Impact.moderate,
53+
})
54+
inherentImpact: Impact;
55+
56+
@ApiProperty({
57+
description: 'Residual probability after controls are applied',
58+
enum: Likelihood,
59+
example: Likelihood.unlikely,
60+
})
61+
residualProbability: Likelihood;
62+
63+
@ApiProperty({
64+
description: 'Residual impact after controls are applied',
65+
enum: Impact,
66+
example: Impact.minor,
67+
})
68+
residualImpact: Impact;
69+
70+
@ApiProperty({
71+
description: 'Vendor website URL',
72+
nullable: true,
73+
example: 'https://www.cloudtechsolutions.com',
74+
})
75+
website: string | null;
76+
77+
@ApiProperty({
78+
description: 'Organization ID',
79+
example: 'org_abc123def456',
80+
})
81+
organizationId: string;
82+
83+
@ApiProperty({
84+
description: 'ID of the user assigned to manage this vendor',
85+
nullable: true,
86+
example: 'mem_abc123def456',
87+
})
88+
assigneeId: string | null;
89+
90+
@ApiProperty({
91+
description: 'When the vendor was created',
92+
type: String,
93+
format: 'date-time',
94+
example: '2024-01-15T10:30:00Z',
95+
})
96+
createdAt: Date;
97+
98+
@ApiProperty({
99+
description: 'When the vendor was last updated',
100+
type: String,
101+
format: 'date-time',
102+
example: '2024-01-16T14:45:00Z',
103+
})
104+
updatedAt: Date;
105+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import type { ApiResponseOptions } from '@nestjs/swagger';
2+
3+
export const CREATE_VENDOR_RESPONSES: Record<number, ApiResponseOptions> = {
4+
201: {
5+
status: 201,
6+
description: 'Vendor created successfully',
7+
schema: {
8+
type: 'object',
9+
properties: {
10+
id: {
11+
type: 'string',
12+
description: 'Vendor ID',
13+
example: 'vnd_abc123def456',
14+
},
15+
name: {
16+
type: 'string',
17+
description: 'Vendor name',
18+
example: 'CloudTech Solutions Inc.',
19+
},
20+
description: {
21+
type: 'string',
22+
description: 'Vendor description',
23+
example: 'Cloud infrastructure provider offering AWS-like services including compute, storage, and networking solutions for enterprise customers.',
24+
},
25+
category: {
26+
type: 'string',
27+
enum: ['cloud', 'infrastructure', 'software_as_a_service', 'finance', 'marketing', 'sales', 'hr', 'other'],
28+
example: 'cloud',
29+
},
30+
status: {
31+
type: 'string',
32+
enum: ['not_assessed', 'in_progress', 'assessed'],
33+
example: 'not_assessed',
34+
},
35+
inherentProbability: {
36+
type: 'string',
37+
enum: ['very_unlikely', 'unlikely', 'possible', 'likely', 'very_likely'],
38+
example: 'possible',
39+
},
40+
inherentImpact: {
41+
type: 'string',
42+
enum: ['insignificant', 'minor', 'moderate', 'major', 'severe'],
43+
example: 'moderate',
44+
},
45+
residualProbability: {
46+
type: 'string',
47+
enum: ['very_unlikely', 'unlikely', 'possible', 'likely', 'very_likely'],
48+
example: 'unlikely',
49+
},
50+
residualImpact: {
51+
type: 'string',
52+
enum: ['insignificant', 'minor', 'moderate', 'major', 'severe'],
53+
example: 'minor',
54+
},
55+
website: {
56+
type: 'string',
57+
nullable: true,
58+
example: 'https://www.cloudtechsolutions.com',
59+
},
60+
organizationId: {
61+
type: 'string',
62+
example: 'org_abc123def456',
63+
},
64+
assigneeId: {
65+
type: 'string',
66+
nullable: true,
67+
description: 'ID of the user assigned to manage this vendor',
68+
example: 'mem_abc123def456',
69+
},
70+
createdAt: {
71+
type: 'string',
72+
format: 'date-time',
73+
description: 'When the vendor was created',
74+
},
75+
updatedAt: {
76+
type: 'string',
77+
format: 'date-time',
78+
description: 'When the vendor was last updated',
79+
},
80+
authType: {
81+
type: 'string',
82+
enum: ['api-key', 'session'],
83+
description: 'How the request was authenticated',
84+
},
85+
authenticatedUser: {
86+
type: 'object',
87+
description: 'User information (only for session auth)',
88+
properties: {
89+
id: { type: 'string', example: 'usr_def456ghi789' },
90+
email: { type: 'string', example: 'user@example.com' },
91+
},
92+
},
93+
},
94+
},
95+
},
96+
400: {
97+
status: 400,
98+
description: 'Bad request - Invalid input data',
99+
schema: {
100+
type: 'object',
101+
properties: {
102+
message: {
103+
type: 'array',
104+
items: { type: 'string' },
105+
example: [
106+
'name should not be empty',
107+
'description should not be empty',
108+
'category must be a valid enum value',
109+
'website must be a URL address',
110+
],
111+
},
112+
error: { type: 'string', example: 'Bad Request' },
113+
statusCode: { type: 'number', example: 400 },
114+
},
115+
},
116+
},
117+
401: {
118+
status: 401,
119+
description: 'Unauthorized - Invalid authentication or insufficient permissions',
120+
schema: {
121+
type: 'object',
122+
properties: {
123+
message: {
124+
type: 'string',
125+
examples: [
126+
'Invalid or expired API key',
127+
'Invalid or expired session',
128+
'User does not have access to organization',
129+
'Organization context required',
130+
],
131+
},
132+
},
133+
},
134+
},
135+
404: {
136+
status: 404,
137+
description: 'Organization not found',
138+
schema: {
139+
type: 'object',
140+
properties: {
141+
message: {
142+
type: 'string',
143+
example: 'Organization with ID org_abc123def456 not found',
144+
},
145+
},
146+
},
147+
},
148+
500: {
149+
status: 500,
150+
description: 'Internal server error',
151+
schema: {
152+
type: 'object',
153+
properties: {
154+
message: {
155+
type: 'string',
156+
example: 'Internal server error',
157+
},
158+
},
159+
},
160+
},
161+
};

0 commit comments

Comments
 (0)