Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
307 lines
14 KiB
TypeScript
307 lines
14 KiB
TypeScript
import { z } from 'zod';
|
|
import {
|
|
BaseDomainEventPayloadSchema,
|
|
changesSchema,
|
|
updatedFieldsSchema,
|
|
uuidSchema,
|
|
} from './commonEventPayloadSchemas';
|
|
|
|
/**
|
|
* Ticket event payloads for workflow runtime v2 simulation and validation.
|
|
*
|
|
* Notes:
|
|
* - Payloads follow PRD conventions: tenantId + occurredAt required; actor fields optional.
|
|
* - These are intentionally higher-level and stable; they can be expanded/versioned as needed.
|
|
*/
|
|
|
|
const ticketIdSchema = uuidSchema('Ticket ID');
|
|
const userIdSchema = uuidSchema('User ID');
|
|
const contactIdSchema = uuidSchema('Contact ID');
|
|
const messageIdSchema = uuidSchema('Message ID');
|
|
const noteIdSchema = uuidSchema('Note ID');
|
|
const timeEntryIdSchema = uuidSchema('Time Entry ID');
|
|
const assigneeTypeSchema = z.enum(['user', 'team']).describe('Assignee type');
|
|
|
|
export const ticketCreatedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
createdByUserId: userIdSchema.optional().describe('User who created the ticket'),
|
|
actorUserId: userIdSchema.optional().describe('Actor User ID (preferred)'),
|
|
createdAt: z.string().optional().describe('Created timestamp (ISO 8601)'),
|
|
updatedFields: updatedFieldsSchema,
|
|
changes: changesSchema,
|
|
}).describe('Payload for TICKET_CREATED');
|
|
|
|
export type TicketCreatedEventPayload = z.infer<typeof ticketCreatedEventPayloadSchema>;
|
|
|
|
export const ticketAssignedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
assignedToUserId: userIdSchema.optional().describe('Deprecated: user assigned to the ticket'),
|
|
assignedByUserId: userIdSchema.optional().describe('User who performed the assignment'),
|
|
previousAssigneeId: z.string().uuid().optional(),
|
|
previousAssigneeType: assigneeTypeSchema.optional(),
|
|
newAssigneeId: z.string().uuid().optional(),
|
|
newAssigneeType: assigneeTypeSchema.optional(),
|
|
assignedAt: z.string().optional().describe('Assigned timestamp (ISO 8601)'),
|
|
updatedFields: updatedFieldsSchema,
|
|
changes: changesSchema,
|
|
}).describe('Payload for TICKET_ASSIGNED');
|
|
|
|
export type TicketAssignedEventPayload = z.infer<typeof ticketAssignedEventPayloadSchema>;
|
|
|
|
export const ticketClosedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
closedByUserId: userIdSchema.optional().describe('User who closed the ticket'),
|
|
closedAt: z.string().optional().describe('Closed timestamp (ISO 8601)'),
|
|
reason: z.string().optional().describe('Optional close reason'),
|
|
updatedFields: updatedFieldsSchema,
|
|
changes: changesSchema,
|
|
}).describe('Payload for TICKET_CLOSED');
|
|
|
|
export type TicketClosedEventPayload = z.infer<typeof ticketClosedEventPayloadSchema>;
|
|
|
|
export const ticketUpdatedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
updatedByUserId: userIdSchema.optional().describe('User who updated the ticket'),
|
|
updatedFields: updatedFieldsSchema,
|
|
changes: changesSchema,
|
|
}).describe('Payload for TICKET_UPDATED');
|
|
|
|
export type TicketUpdatedEventPayload = z.infer<typeof ticketUpdatedEventPayloadSchema>;
|
|
|
|
export const ticketResponseStateChangedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
previousResponseState: z.string().optional().describe('Previous response state'),
|
|
newResponseState: z.string().optional().describe('New response state'),
|
|
}).describe('Payload for TICKET_RESPONSE_STATE_CHANGED');
|
|
|
|
export type TicketResponseStateChangedEventPayload = z.infer<
|
|
typeof ticketResponseStateChangedEventPayloadSchema
|
|
>;
|
|
|
|
export const ticketStatusChangedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
previousStatusId: z.string().min(1).describe('Previous status ID'),
|
|
newStatusId: z.string().min(1).describe('New status ID'),
|
|
reason: z.string().optional(),
|
|
changedAt: z.string().datetime().optional().describe('Timestamp when status changed (ISO 8601)'),
|
|
}).describe('Payload for TICKET_STATUS_CHANGED');
|
|
|
|
export type TicketStatusChangedEventPayload = z.infer<typeof ticketStatusChangedEventPayloadSchema>;
|
|
|
|
export const ticketPriorityChangedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
previousPriorityId: z.string().min(1).describe('Previous priority ID'),
|
|
newPriorityId: z.string().min(1).describe('New priority ID'),
|
|
reason: z.string().optional(),
|
|
changedAt: z.string().datetime().optional().describe('Timestamp when priority changed (ISO 8601)'),
|
|
}).describe('Payload for TICKET_PRIORITY_CHANGED');
|
|
|
|
export type TicketPriorityChangedEventPayload = z.infer<typeof ticketPriorityChangedEventPayloadSchema>;
|
|
|
|
export const ticketUnassignedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
previousAssigneeId: z.string().uuid().describe('Previous assignee ID'),
|
|
previousAssigneeType: assigneeTypeSchema.describe('Previous assignee type'),
|
|
newAssigneeId: z.string().uuid().optional().describe('New assignee ID (typically absent after unassignment)'),
|
|
newAssigneeType: assigneeTypeSchema.optional().describe('New assignee type (typically absent after unassignment)'),
|
|
unassignedAt: z.string().datetime().optional(),
|
|
reason: z.string().optional(),
|
|
}).describe('Payload for TICKET_UNASSIGNED');
|
|
|
|
export type TicketUnassignedEventPayload = z.infer<typeof ticketUnassignedEventPayloadSchema>;
|
|
|
|
export const ticketReopenedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
previousStatusId: z.string().min(1).describe('Previous status ID'),
|
|
newStatusId: z.string().min(1).describe('New status ID'),
|
|
reopenedAt: z.string().datetime().optional(),
|
|
reason: z.string().optional(),
|
|
}).describe('Payload for TICKET_REOPENED');
|
|
|
|
export type TicketReopenedEventPayload = z.infer<typeof ticketReopenedEventPayloadSchema>;
|
|
|
|
export const ticketMergedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
sourceTicketId: ticketIdSchema.describe('Source ticket ID'),
|
|
targetTicketId: ticketIdSchema.describe('Target ticket ID'),
|
|
mergedAt: z.string().datetime().optional(),
|
|
reason: z.string().optional(),
|
|
}).describe('Payload for TICKET_MERGED');
|
|
|
|
export type TicketMergedEventPayload = z.infer<typeof ticketMergedEventPayloadSchema>;
|
|
|
|
export const ticketSplitEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
originalTicketId: ticketIdSchema.describe('Original ticket ID'),
|
|
newTicketIds: z.array(ticketIdSchema).min(1).describe('New ticket IDs'),
|
|
splitAt: z.string().datetime().optional(),
|
|
reason: z.string().optional(),
|
|
}).describe('Payload for TICKET_SPLIT');
|
|
|
|
export type TicketSplitEventPayload = z.infer<typeof ticketSplitEventPayloadSchema>;
|
|
|
|
export const ticketTagsChangedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
addedTagIds: z.array(z.string().uuid()).optional(),
|
|
removedTagIds: z.array(z.string().uuid()).optional(),
|
|
changedAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_TAGS_CHANGED');
|
|
|
|
export type TicketTagsChangedEventPayload = z.infer<typeof ticketTagsChangedEventPayloadSchema>;
|
|
|
|
export const ticketQueueChangedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
previousBoardId: z.string().uuid().optional(),
|
|
newBoardId: z.string().uuid().optional(),
|
|
changedAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_QUEUE_CHANGED');
|
|
|
|
export type TicketQueueChangedEventPayload = z.infer<typeof ticketQueueChangedEventPayloadSchema>;
|
|
|
|
export const ticketEscalatedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
fromQueueId: z.string().uuid().optional(),
|
|
toQueueId: z.string().uuid().optional(),
|
|
escalatedAt: z.string().datetime().optional(),
|
|
reason: z.string().optional(),
|
|
}).describe('Payload for TICKET_ESCALATED');
|
|
|
|
export type TicketEscalatedEventPayload = z.infer<typeof ticketEscalatedEventPayloadSchema>;
|
|
|
|
const visibilitySchema = z.enum(['public', 'internal']).describe('Message visibility');
|
|
const messageChannelSchema = z.enum(['email', 'portal', 'ui', 'api']).describe('Message channel');
|
|
const authorTypeSchema = z.enum(['user', 'contact']).describe('Author type');
|
|
|
|
export const ticketMessageAddedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
messageId: messageIdSchema,
|
|
visibility: visibilitySchema,
|
|
authorId: z.string().uuid().describe('Author ID (user/contact)'),
|
|
authorType: authorTypeSchema,
|
|
channel: messageChannelSchema,
|
|
createdAt: z.string().datetime().optional(),
|
|
attachmentsCount: z.number().int().nonnegative().optional(),
|
|
}).describe('Payload for TICKET_MESSAGE_ADDED');
|
|
|
|
export type TicketMessageAddedEventPayload = z.infer<typeof ticketMessageAddedEventPayloadSchema>;
|
|
|
|
export const ticketCustomerRepliedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
messageId: messageIdSchema,
|
|
contactId: contactIdSchema,
|
|
channel: messageChannelSchema,
|
|
receivedAt: z.string().datetime().optional(),
|
|
attachmentsCount: z.number().int().nonnegative().optional(),
|
|
}).describe('Payload for TICKET_CUSTOMER_REPLIED');
|
|
|
|
export type TicketCustomerRepliedEventPayload = z.infer<typeof ticketCustomerRepliedEventPayloadSchema>;
|
|
|
|
export const ticketInternalNoteAddedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
noteId: noteIdSchema,
|
|
createdAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_INTERNAL_NOTE_ADDED');
|
|
|
|
export type TicketInternalNoteAddedEventPayload = z.infer<
|
|
typeof ticketInternalNoteAddedEventPayloadSchema
|
|
>;
|
|
|
|
export const ticketTimeEntryAddedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
timeEntryId: timeEntryIdSchema,
|
|
minutes: z.number().int().positive(),
|
|
billable: z.boolean(),
|
|
createdAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_TIME_ENTRY_ADDED');
|
|
|
|
export type TicketTimeEntryAddedEventPayload = z.infer<typeof ticketTimeEntryAddedEventPayloadSchema>;
|
|
|
|
const slaStageSchema = z.enum(['response', 'resolution', 'custom']).describe('SLA stage');
|
|
|
|
export const ticketSlaStageEnteredEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
slaPolicyId: z.string().uuid(),
|
|
stage: slaStageSchema,
|
|
enteredAt: z.string().datetime().optional(),
|
|
targetAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_SLA_STAGE_ENTERED');
|
|
|
|
export type TicketSlaStageEnteredEventPayload = z.infer<typeof ticketSlaStageEnteredEventPayloadSchema>;
|
|
|
|
export const ticketSlaStageMetEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
slaPolicyId: z.string().uuid(),
|
|
stage: slaStageSchema,
|
|
metAt: z.string().datetime().optional(),
|
|
targetAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_SLA_STAGE_MET');
|
|
|
|
export type TicketSlaStageMetEventPayload = z.infer<typeof ticketSlaStageMetEventPayloadSchema>;
|
|
|
|
export const ticketSlaStageBreachedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
slaPolicyId: z.string().uuid(),
|
|
stage: slaStageSchema,
|
|
breachedAt: z.string().datetime().optional(),
|
|
targetAt: z.string().datetime().optional(),
|
|
overdueBySeconds: z.number().int().nonnegative().optional(),
|
|
}).describe('Payload for TICKET_SLA_STAGE_BREACHED');
|
|
|
|
export type TicketSlaStageBreachedEventPayload = z.infer<
|
|
typeof ticketSlaStageBreachedEventPayloadSchema
|
|
>;
|
|
|
|
export const ticketApprovalRequestedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
approvalRequestId: z.string().uuid(),
|
|
approvalType: z.string().min(1),
|
|
requestedByUserId: userIdSchema.optional(),
|
|
requestedAt: z.string().datetime().optional(),
|
|
notes: z.string().optional(),
|
|
}).describe('Payload for TICKET_APPROVAL_REQUESTED');
|
|
|
|
export type TicketApprovalRequestedEventPayload = z.infer<typeof ticketApprovalRequestedEventPayloadSchema>;
|
|
|
|
export const ticketApprovalGrantedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
approvalRequestId: z.string().uuid(),
|
|
approvedByUserId: userIdSchema.optional(),
|
|
approvedAt: z.string().datetime().optional(),
|
|
conditions: z.unknown().optional(),
|
|
}).describe('Payload for TICKET_APPROVAL_GRANTED');
|
|
|
|
export type TicketApprovalGrantedEventPayload = z.infer<typeof ticketApprovalGrantedEventPayloadSchema>;
|
|
|
|
export const ticketApprovalRejectedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
approvalRequestId: z.string().uuid(),
|
|
rejectedByUserId: userIdSchema.optional(),
|
|
rejectedAt: z.string().datetime().optional(),
|
|
reason: z.string().optional(),
|
|
}).describe('Payload for TICKET_APPROVAL_REJECTED');
|
|
|
|
export type TicketApprovalRejectedEventPayload = z.infer<typeof ticketApprovalRejectedEventPayloadSchema>;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Legacy ticket events (still used in harness fixtures)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const ticketCommentAddedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
commentId: z.string().uuid().optional(),
|
|
visibility: z.enum(['public', 'internal']).optional(),
|
|
authorId: z.string().uuid().optional(),
|
|
authorType: z.enum(['user', 'contact']).optional(),
|
|
createdAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_COMMENT_ADDED');
|
|
|
|
export type TicketCommentAddedEventPayload = z.infer<typeof ticketCommentAddedEventPayloadSchema>;
|
|
|
|
export const ticketAdditionalAgentAssignedEventPayloadSchema = BaseDomainEventPayloadSchema.extend({
|
|
ticketId: ticketIdSchema,
|
|
primaryAgentId: userIdSchema,
|
|
additionalAgentId: userIdSchema,
|
|
assignedByUserId: userIdSchema.optional(),
|
|
assignedAt: z.string().datetime().optional(),
|
|
}).describe('Payload for TICKET_ADDITIONAL_AGENT_ASSIGNED');
|
|
|
|
export type TicketAdditionalAgentAssignedEventPayload = z.infer<typeof ticketAdditionalAgentAssignedEventPayloadSchema>;
|