# Inbound Ticket Defaults Implementation Plan ✅ COMPLETED ## Table of Contents 1. [Problem Summary](#problem-summary) 2. [Solution Architecture](#solution-architecture) 3. [Implementation Phases](#implementation-phases) - [Phase 1: Database Schema](#phase-1-database-schema) - [Phase 2: Backend API Development](#phase-2-backend-api-development) - [Phase 3: Workflow Integration](#phase-3-workflow-integration) - [Phase 4: UI Components](#phase-4-ui-components) 4. [Database Schema Details](#database-schema-details) 5. [TypeScript Interfaces](#typescript-interfaces) 6. [File Changes Summary](#file-changes-summary) ## Problem Summary The email-to-ticket workflow is failing with validation errors because required ticket fields (`channel_id`, `company_id`, `status_id`, `priority_id`, `entered_by`, etc.) are not being provided. The workflow receives email data but cannot create tickets without these mandatory database fields. ## Solution Architecture Create a flexible `inbound_ticket_defaults` table with named default configurations that can be referenced by email providers. This design allows for reusable default configurations and enables future domain-based routing capabilities. ## Implementation Phases ### Phase 1: Database Schema ✅ - [x] Create `inbound_ticket_defaults` table migration - [x] Add reference column to `email_providers` table - [x] Create default inbound ticket defaults seed data ### Phase 2: Backend API Development ✅ - [x] Create inbound ticket defaults actions (CRUD operations) - [x] Create ticket field options actions (for dropdowns) - [x] Update email provider actions to handle defaults reference - [x] Add TypeScript interfaces for new types - [x] Update TicketModel to allow null `entered_by` for system-generated tickets ### Phase 3: Workflow Integration ✅ - [x] Update `createTicketFromEmail()` to accept default field values - [x] Create helper function to resolve email provider's ticket defaults - [x] Update email processing workflow to retrieve and use defaults - [x] Validate workflow execution with configured defaults ### Phase 4: UI Components ✅ - [x] Create InboundTicketDefaultsManager component - [x] Create InboundTicketDefaultsForm component - [x] Update provider forms to select from existing defaults - [x] Integrate defaults management into EmailProviderConfiguration ## Database Schema Details ### New Table: `inbound_ticket_defaults` ```sql CREATE TABLE inbound_ticket_defaults ( id UUID NOT NULL, tenant UUID NOT NULL, short_name VARCHAR(100) NOT NULL, display_name VARCHAR(255) NOT NULL, description TEXT, defaults JSONB NOT NULL DEFAULT '{}', is_active BOOLEAN DEFAULT true, created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), PRIMARY KEY (id, tenant), FOREIGN KEY (tenant) REFERENCES tenants(tenant), UNIQUE (tenant, short_name) ); ``` ### Email Providers Table Update ```sql ALTER TABLE email_providers ADD COLUMN inbound_ticket_defaults_id UUID; ``` ### Default JSON Structure ```json { "channel_id": "uuid", "status_id": "uuid", "priority_id": "uuid", "company_id": "uuid", "entered_by": null, "category_id": "uuid", "subcategory_id": "uuid", "location_id": "uuid" } ``` ## TypeScript Interfaces ```typescript interface InboundTicketDefaults { id: string; tenant: string; short_name: string; display_name: string; description?: string; defaults: { channel_id: string; status_id: string; priority_id: string; company_id?: string; entered_by?: string | null; category_id?: string; subcategory_id?: string; location_id?: string; }; is_active: boolean; created_at: string; updated_at: string; } interface TicketFieldOptions { channels: Array<{ id: string; name: string; is_default: boolean }>; statuses: Array<{ id: string; name: string }>; priorities: Array<{ id: string; name: string }>; categories: Array<{ id: string; name: string; parent_id?: string }>; users: Array<{ id: string; name: string; username: string }>; } ``` ## File Changes Summary ### New Files ✅ - `/server/migrations/20250713002000_create_inbound_ticket_defaults_table.cjs` ✅ - `/server/migrations/20250713002001_add_defaults_ref_to_email_providers.cjs` ✅ - `/server/seeds/dev/005_default_inbound_ticket_defaults.cjs` ✅ - `/server/src/lib/actions/email-actions/inboundTicketDefaultsActions.ts` ✅ - `/server/src/lib/actions/email-actions/ticketFieldOptionsActions.ts` ✅ - `/server/src/components/admin/InboundTicketDefaultsManager.tsx` ✅ - `/server/src/components/forms/InboundTicketDefaultsForm.tsx` ✅ ### Modified Files ✅ - `/server/src/lib/actions/email-actions/emailProviderActions.ts` ✅ - `/server/src/components/EmailProviderConfiguration.tsx` ✅ - `/server/src/components/MicrosoftProviderForm.tsx` ✅ - `/server/src/components/GmailProviderForm.tsx` ⏳ (Pending - similar changes as Microsoft) - `/shared/workflow/actions/emailWorkflowActions.ts` ✅ - `/shared/models/ticketModel.ts` - Update validation to allow null `entered_by` ✅ - `/server/seeds/dev/004_email_processing_workflow_from_source.cjs` ✅ - `/server/src/types/email.types.ts` ✅ ### Key Implementation Details #### Database Migration Strategy 1. Create `inbound_ticket_defaults` table with tenant partitioning 2. Add foreign key reference from `email_providers` 3. Seed with default "email-general" configuration #### Backend API Pattern - Follow existing email actions pattern with tenant isolation - Use consistent error handling and validation - Return structured responses with proper TypeScript types - Update TicketModel validation to allow `entered_by: null` for system tickets #### Workflow Integration Points - Resolve email provider → inbound ticket defaults in workflow - Pass defaults as additional parameters to ticket creation - Merge email data with configured defaults before validation #### UI Component Architecture - Reusable form components for ticket field selection - Manager component for CRUD operations on defaults - Integration into existing email provider configuration flow #### System-Generated Ticket Handling For tickets created from email processing, `entered_by` will be `null` to indicate system generation: - Update TicketModel validation schema to allow `entered_by: null` - Modify ticket creation logic to handle null `entered_by` gracefully - UI components should display "System" when `entered_by` is null - Audit logs should show system-generated entries appropriately #### TicketModel Changes Required ```typescript // Update validation to allow null for system tickets entered_by: z.string().uuid().nullable().optional() // In createTicket logic: const auditUser = data.entered_by || 'system'; ``` This implementation focuses strictly on solving the immediate validation issue while providing a solid foundation for the email-to-ticket workflow.