Skip to content

Commit fc5bdb4

Browse files
committed
backend changes
update and delete ticket comments cleanup repository cleanup cleanup indexes and seeds fix tests code smell fix tests linter
1 parent ba81d8e commit fc5bdb4

39 files changed

+4528
-1
lines changed

api/src/models/comment.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ export const Comment = z.object({
55
comment: z.string()
66
});
77
export type Comment = z.infer<typeof Comment>;
8+
9+
export interface UpdateComment {
10+
comment: string;
11+
}

api/src/models/ticket-comment.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { z } from 'zod';
2+
3+
export const TicketComment = z.object({
4+
ticket_comment_id: z.string().uuid(),
5+
ticket_id: z.string().uuid(),
6+
user_identifier: z.string(),
7+
create_date: z.string(),
8+
comment: z.string()
9+
});
10+
11+
export type TicketComment = z.infer<typeof TicketComment>;
12+
13+
export const CreateTicketCommentRequest = z.object({
14+
comment: z.string().min(1).max(3000)
15+
});
16+
17+
export type CreateTicketCommentRequest = z.infer<typeof CreateTicketCommentRequest>;
18+
19+
export const UpdateTicketCommentRequest = z.object({
20+
comment: z.string().min(1).max(3000)
21+
});
22+
23+
export type UpdateTicketCommentRequest = z.infer<typeof UpdateTicketCommentRequest>;
24+
25+
export const CreateTicketComment = z.object({
26+
ticketId: z.string().uuid(),
27+
comment: z.string().min(1).max(3000)
28+
});
29+
30+
export type CreateTicketComment = z.infer<typeof CreateTicketComment>;
31+
32+
export const UpdateTicketComment = z.object({
33+
ticketId: z.string().uuid(),
34+
ticketCommentId: z.string().uuid(),
35+
comment: z.string().min(1).max(3000)
36+
});
37+
38+
export type UpdateTicketComment = z.infer<typeof UpdateTicketComment>;

api/src/models/ticket-reference.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { z } from 'zod';
2+
3+
export const TicketRelationshipType = z.enum([
4+
'blocks',
5+
'blocked_by',
6+
'duplicates',
7+
'duplicate_of',
8+
'relates_to',
9+
'resolves',
10+
'resolved_by'
11+
]);
12+
13+
export type TicketRelationshipType = z.infer<typeof TicketRelationshipType>;
14+
15+
export const TicketReference = z.object({
16+
ticket_reference_id: z.string().uuid(),
17+
source_ticket_id: z.string().uuid(),
18+
source_ticket_slug: z.string().regex(/^\d{8}$/),
19+
source_ticket_subject: z.string(),
20+
target_ticket_id: z.string().uuid(),
21+
target_ticket_slug: z.string().regex(/^\d{8}$/),
22+
target_ticket_subject: z.string(),
23+
relationship: TicketRelationshipType,
24+
user_identifier: z.string(),
25+
create_date: z.string()
26+
});
27+
28+
export type TicketReference = z.infer<typeof TicketReference>;
29+
30+
export const CreateTicketReference = z.object({
31+
source_ticket_id: z.string().uuid(),
32+
target_ticket_id: z.string().uuid(),
33+
relationship: TicketRelationshipType
34+
});
35+
36+
export type CreateTicketReference = z.infer<typeof CreateTicketReference>;
37+
38+
export const CreateTicketReferenceRequest = z.object({
39+
target_ticket_id: z.string().uuid(),
40+
relationship: TicketRelationshipType
41+
});
42+
43+
export type CreateTicketReferenceRequest = z.infer<typeof CreateTicketReferenceRequest>;

api/src/models/ticket-status.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { z } from 'zod';
2+
3+
export const TicketStatus = z.object({
4+
ticket_status_history_id: z.string().uuid(),
5+
ticket_id: z.string().uuid(),
6+
user_identifier: z.string(),
7+
create_date: z.string(),
8+
status: z.enum(['open', 'closed'])
9+
});
10+
11+
export type TicketStatus = z.infer<typeof TicketStatus>;

api/src/models/ticket.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { z } from 'zod';
2+
import { TicketComment } from './ticket-comment';
3+
import { TicketReference } from './ticket-reference';
4+
import { TicketStatus as TicketStatusRecord } from './ticket-status';
5+
6+
export const TicketPriority = z.enum(['low', 'medium', 'high', 'critical']);
7+
export type TicketPriority = z.infer<typeof TicketPriority>;
8+
9+
export const TicketStatus = z.enum(['open', 'closed']);
10+
export type TicketStatus = z.infer<typeof TicketStatus>;
11+
12+
export interface TicketFilters {
13+
team_id?: string;
14+
status?: TicketStatus;
15+
}
16+
17+
export const Ticket = z.object({
18+
ticket_id: z.string().uuid(),
19+
ticket_slug: z.string().regex(/^\d{8}$/),
20+
subject: z.string(),
21+
description: z.string().nullable(),
22+
team_id: z.string().uuid(),
23+
create_date: z.string(),
24+
priority: TicketPriority,
25+
status: TicketStatus
26+
});
27+
28+
export type Ticket = z.infer<typeof Ticket>;
29+
30+
export const TicketSlug = Ticket.pick({ ticket_slug: true });
31+
export type TicketSlug = z.infer<typeof TicketSlug>;
32+
33+
export const CreateTicketRequest = z.object({
34+
subject: z.string().max(100),
35+
description: z.string().max(2000).nullable(),
36+
priority: TicketPriority
37+
});
38+
39+
export type CreateTicketRequest = z.infer<typeof CreateTicketRequest>;
40+
41+
export type CreateTicketPayload = CreateTicketRequest & {
42+
team_id: string;
43+
ticket_slug: string;
44+
};
45+
46+
export const UpdateTicketRequest = z.object({
47+
subject: z.string().max(100).optional(),
48+
description: z.string().max(2000).nullable().optional(),
49+
priority: TicketPriority.optional(),
50+
status: TicketStatus.optional()
51+
});
52+
53+
export type UpdateTicketRequest = z.infer<typeof UpdateTicketRequest>;
54+
55+
export const UpdateTicketStatusRequest = z.object({
56+
status: TicketStatus
57+
});
58+
59+
export type UpdateTicketStatusRequest = z.infer<typeof UpdateTicketStatusRequest>;
60+
61+
export * from './ticket-comment';
62+
export * from './ticket-reference';
63+
export * from './ticket-status';
64+
65+
export const TicketWithHistory = Ticket.extend({
66+
status_history: z.array(TicketStatusRecord),
67+
comments: z.array(TicketComment),
68+
references: z.array(TicketReference)
69+
});
70+
71+
export type TicketWithHistory = z.infer<typeof TicketWithHistory>;

api/src/openapi/schemas/ticket.ts

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
import { OpenAPIV3 } from 'openapi-types';
2+
import { paginationResponseSchema } from './pagination';
3+
4+
const TicketPriorityEnum = ['low', 'medium', 'high', 'critical'];
5+
const TicketStatusEnum = ['open', 'closed'];
6+
7+
export const TicketCommentSchema: OpenAPIV3.SchemaObject = {
8+
type: 'object',
9+
required: ['ticket_comment_id', 'ticket_id', 'user_identifier', 'create_date', 'comment'],
10+
properties: {
11+
ticket_comment_id: { type: 'string', format: 'uuid' },
12+
ticket_id: { type: 'string', format: 'uuid' },
13+
user_identifier: { type: 'string' },
14+
create_date: { type: 'string', format: 'date-time' },
15+
comment: { type: 'string' }
16+
}
17+
};
18+
19+
export const TicketReferenceSchema: OpenAPIV3.SchemaObject = {
20+
type: 'object',
21+
required: [
22+
'ticket_reference_id',
23+
'source_ticket_id',
24+
'source_ticket_slug',
25+
'source_ticket_subject',
26+
'target_ticket_id',
27+
'target_ticket_slug',
28+
'target_ticket_subject',
29+
'relationship',
30+
'user_identifier',
31+
'create_date'
32+
],
33+
properties: {
34+
ticket_reference_id: { type: 'string', format: 'uuid' },
35+
source_ticket_id: { type: 'string', format: 'uuid' },
36+
source_ticket_slug: { type: 'string', minLength: 8, maxLength: 8, pattern: String.raw`^\d{8}$` },
37+
source_ticket_subject: { type: 'string', maxLength: 100 },
38+
target_ticket_id: { type: 'string', format: 'uuid' },
39+
target_ticket_slug: { type: 'string', minLength: 8, maxLength: 8, pattern: String.raw`^\d{8}$` },
40+
target_ticket_subject: { type: 'string', maxLength: 100 },
41+
relationship: {
42+
type: 'string',
43+
enum: ['blocks', 'blocked_by', 'duplicates', 'duplicate_of', 'relates_to', 'resolves', 'resolved_by']
44+
},
45+
user_identifier: { type: 'string' },
46+
create_date: { type: 'string', format: 'date-time' }
47+
}
48+
};
49+
50+
export const TicketSchema: OpenAPIV3.SchemaObject = {
51+
type: 'object',
52+
required: ['ticket_id', 'ticket_slug', 'subject', 'team_id', 'create_date', 'priority', 'status'],
53+
properties: {
54+
ticket_id: { type: 'string', format: 'uuid' },
55+
ticket_slug: { type: 'string', minLength: 8, maxLength: 8, pattern: String.raw`^\d{8}$` },
56+
subject: { type: 'string', maxLength: 100 },
57+
description: { type: 'string', maxLength: 2000, nullable: true },
58+
team_id: { type: 'string', format: 'uuid' },
59+
create_date: { type: 'string', format: 'date-time' },
60+
priority: { type: 'string', enum: TicketPriorityEnum },
61+
status: { type: 'string', enum: TicketStatusEnum }
62+
}
63+
};
64+
65+
export const TicketWithHistorySchema: OpenAPIV3.SchemaObject = {
66+
type: 'object',
67+
required: [
68+
'ticket_id',
69+
'ticket_slug',
70+
'subject',
71+
'team_id',
72+
'create_date',
73+
'priority',
74+
'status',
75+
'status_history',
76+
'comments',
77+
'references'
78+
],
79+
properties: {
80+
ticket_id: { type: 'string', format: 'uuid' },
81+
ticket_slug: { type: 'string', minLength: 8, maxLength: 8, pattern: String.raw`^\d{8}$` },
82+
subject: { type: 'string', maxLength: 100 },
83+
description: { type: 'string', maxLength: 2000, nullable: true },
84+
team_id: { type: 'string', format: 'uuid' },
85+
create_date: { type: 'string', format: 'date-time' },
86+
priority: { type: 'string', enum: TicketPriorityEnum },
87+
status: { type: 'string', enum: TicketStatusEnum },
88+
status_history: {
89+
type: 'array',
90+
items: {
91+
type: 'object',
92+
required: ['ticket_status_history_id', 'ticket_id', 'user_identifier', 'create_date', 'status'],
93+
properties: {
94+
ticket_status_history_id: { type: 'string', format: 'uuid' },
95+
ticket_id: { type: 'string', format: 'uuid' },
96+
user_identifier: { type: 'string' },
97+
create_date: { type: 'string', format: 'date-time' },
98+
status: { type: 'string', enum: TicketStatusEnum }
99+
}
100+
}
101+
},
102+
comments: {
103+
type: 'array',
104+
items: TicketCommentSchema
105+
},
106+
references: {
107+
type: 'array',
108+
items: TicketReferenceSchema
109+
}
110+
}
111+
};
112+
113+
export const CreateTicketRequestSchema: OpenAPIV3.SchemaObject = {
114+
type: 'object',
115+
additionalProperties: false,
116+
required: ['subject', 'description', 'priority'],
117+
properties: {
118+
subject: { type: 'string', maxLength: 100 },
119+
description: { type: 'string', maxLength: 2000, nullable: true },
120+
priority: { type: 'string', enum: TicketPriorityEnum }
121+
}
122+
};
123+
124+
export const UpdateTicketRequestSchema: OpenAPIV3.SchemaObject = {
125+
type: 'object',
126+
additionalProperties: false,
127+
properties: {
128+
subject: { type: 'string', maxLength: 100 },
129+
description: { type: 'string', maxLength: 2000, nullable: true },
130+
priority: { type: 'string', enum: TicketPriorityEnum },
131+
status: { type: 'string', enum: TicketStatusEnum }
132+
}
133+
};
134+
135+
export const UpdateTicketStatusRequestSchema: OpenAPIV3.SchemaObject = {
136+
type: 'object',
137+
additionalProperties: false,
138+
required: ['status'],
139+
properties: {
140+
status: { type: 'string', enum: TicketStatusEnum }
141+
}
142+
};
143+
144+
export const CreateTicketCommentRequestSchema: OpenAPIV3.SchemaObject = {
145+
type: 'object',
146+
additionalProperties: false,
147+
required: ['comment'],
148+
properties: {
149+
comment: { type: 'string', minLength: 1, maxLength: 3000 }
150+
}
151+
};
152+
153+
export const UpdateTicketCommentRequestSchema: OpenAPIV3.SchemaObject = {
154+
type: 'object',
155+
additionalProperties: false,
156+
required: ['comment'],
157+
properties: {
158+
comment: { type: 'string', minLength: 1, maxLength: 3000 }
159+
}
160+
};
161+
162+
export const CreateTicketReferenceRequestSchema: OpenAPIV3.SchemaObject = {
163+
type: 'object',
164+
additionalProperties: false,
165+
required: ['target_ticket_id', 'relationship'],
166+
properties: {
167+
target_ticket_id: { type: 'string', format: 'uuid' },
168+
relationship: {
169+
type: 'string',
170+
enum: ['blocks', 'blocked_by', 'duplicates', 'duplicate_of', 'relates_to', 'resolves', 'resolved_by']
171+
}
172+
}
173+
};
174+
175+
export const TicketStatusSchema: OpenAPIV3.SchemaObject = {
176+
type: 'object',
177+
required: ['ticket_id', 'user_identifier', 'create_date'],
178+
properties: {
179+
ticket_status_history_id: { type: 'string', format: 'uuid', nullable: true },
180+
ticket_comment_id: { type: 'string', format: 'uuid', nullable: true },
181+
ticket_id: { type: 'string', format: 'uuid' },
182+
user_identifier: { type: 'string' },
183+
create_date: { type: 'string', format: 'date-time' },
184+
status: { type: 'string', enum: TicketStatusEnum, nullable: true },
185+
comment: { type: 'string', nullable: true }
186+
}
187+
};
188+
189+
export const TicketListResponseSchema: OpenAPIV3.SchemaObject = {
190+
type: 'object',
191+
required: ['tickets', 'pagination'],
192+
properties: {
193+
tickets: {
194+
type: 'array',
195+
items: TicketSchema
196+
},
197+
pagination: paginationResponseSchema
198+
}
199+
};

0 commit comments

Comments
 (0)