-- Migration 014: Email Workflows System -- Automatic actions based on email classification categories -- Email Workflows Table CREATE TABLE email_workflows ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, -- Trigger Conditions classification_trigger VARCHAR(50) NOT NULL, -- invoice, freight_note, time_confirmation, etc. sender_pattern VARCHAR(255), -- Optional: only for emails from specific senders subject_pattern VARCHAR(255), -- Optional: regex pattern for subject confidence_threshold DECIMAL(3,2) DEFAULT 0.70, -- Minimum AI confidence to trigger -- Workflow Steps (JSON array of actions to perform) workflow_steps JSONB NOT NULL, -- [{"action": "create_ticket", "params": {...}}, ...] -- Priority and Status priority INTEGER DEFAULT 100, -- Lower number = higher priority enabled BOOLEAN DEFAULT true, stop_on_match BOOLEAN DEFAULT true, -- Stop processing other workflows if this matches -- Statistics execution_count INTEGER DEFAULT 0, success_count INTEGER DEFAULT 0, failure_count INTEGER DEFAULT 0, last_executed_at TIMESTAMP, -- Audit created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by_user_id INTEGER, FOREIGN KEY (created_by_user_id) REFERENCES users(user_id) ON DELETE SET NULL ); -- Workflow Execution Log Table CREATE TABLE email_workflow_executions ( id SERIAL PRIMARY KEY, workflow_id INTEGER NOT NULL, email_id INTEGER NOT NULL, -- Execution Details status VARCHAR(50) NOT NULL, -- pending, running, completed, failed, skipped steps_completed INTEGER DEFAULT 0, steps_total INTEGER, -- Results result_json JSONB, -- Store results from each step error_message TEXT, -- Timing started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, completed_at TIMESTAMP, execution_time_ms INTEGER, FOREIGN KEY (workflow_id) REFERENCES email_workflows(id) ON DELETE CASCADE, FOREIGN KEY (email_id) REFERENCES email_messages(id) ON DELETE CASCADE ); -- Workflow Step Actions Table (for pre-defined actions) CREATE TABLE email_workflow_actions ( id SERIAL PRIMARY KEY, action_code VARCHAR(100) UNIQUE NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, category VARCHAR(50), -- ticket_creation, notification, linking, extraction, etc. -- Action Schema (defines what parameters this action accepts) parameter_schema JSONB, -- JSON Schema for validation -- Examples example_config JSONB, -- Status enabled BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Indexes for Performance CREATE INDEX idx_email_workflows_classification ON email_workflows(classification_trigger) WHERE enabled = true; CREATE INDEX idx_email_workflows_priority ON email_workflows(priority, enabled); CREATE INDEX idx_email_workflow_executions_workflow ON email_workflow_executions(workflow_id); CREATE INDEX idx_email_workflow_executions_email ON email_workflow_executions(email_id); CREATE INDEX idx_email_workflow_executions_status ON email_workflow_executions(status); -- Update Trigger CREATE OR REPLACE FUNCTION update_email_workflows_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trigger_email_workflows_updated_at BEFORE UPDATE ON email_workflows FOR EACH ROW EXECUTE FUNCTION update_email_workflows_updated_at(); -- Insert Default Workflow Actions INSERT INTO email_workflow_actions (action_code, name, description, category, parameter_schema, example_config) VALUES -- Ticket/Case Creation ('create_ticket', 'Create Support Ticket', 'Creates a new support ticket/case from email', 'ticket_creation', '{"type": "object", "properties": {"module": {"type": "string"}, "priority": {"type": "string"}, "assign_to": {"type": "integer"}}}', '{"module": "support_cases", "priority": "normal", "assign_to": null}'), ('create_time_entry', 'Create Time Entry', 'Creates a time tracking entry from email', 'time_tracking', '{"type": "object", "properties": {"customer_id": {"type": "integer"}, "hours": {"type": "number"}, "extract_from": {"type": "string"}}}', '{"extract_from": "body", "default_hours": 1.0}'), -- Linking Actions ('link_to_vendor', 'Link to Vendor', 'Links email to vendor based on sender', 'linking', '{"type": "object", "properties": {"match_by": {"type": "string", "enum": ["email", "name", "cvr"]}, "auto_create": {"type": "boolean"}}}', '{"match_by": "email", "auto_create": false}'), ('link_to_customer', 'Link to Customer', 'Links email to customer', 'linking', '{"type": "object", "properties": {"match_by": {"type": "string"}, "domain_matching": {"type": "boolean"}}}', '{"match_by": "email_domain", "domain_matching": true}'), -- Extraction Actions ('extract_invoice_data', 'Extract Invoice Data', 'Extracts invoice number, amount, due date', 'extraction', '{"type": "object", "properties": {"ai_provider": {"type": "string"}, "fallback_to_regex": {"type": "boolean"}}}', '{"ai_provider": "ollama", "fallback_to_regex": true}'), ('extract_tracking_number', 'Extract Tracking Number', 'Extracts shipment tracking numbers', 'extraction', '{"type": "object", "properties": {"carriers": {"type": "array", "items": {"type": "string"}}}}', '{"carriers": ["postnord", "gls", "dao"]}'), -- Notification Actions ('send_slack_notification', 'Send Slack Notification', 'Posts notification to Slack channel', 'notification', '{"type": "object", "properties": {"channel": {"type": "string"}, "mention": {"type": "string"}, "template": {"type": "string"}}}', '{"channel": "#invoices", "template": "New invoice from {{sender}}: {{subject}}"}'), ('send_email_notification', 'Send Email Notification', 'Sends email notification to user/team', 'notification', '{"type": "object", "properties": {"recipients": {"type": "array"}, "template": {"type": "string"}}}', '{"recipients": ["admin@bmcnetworks.dk"], "template": "default"}'), -- Status Changes ('mark_as_processed', 'Mark as Processed', 'Updates email status to processed', 'status', '{"type": "object", "properties": {"status": {"type": "string"}}}', '{"status": "processed"}'), ('flag_for_review', 'Flag for Manual Review', 'Flags email for human review', 'status', '{"type": "object", "properties": {"reason": {"type": "string"}, "assign_to": {"type": "integer"}}}', '{"reason": "Low confidence classification", "assign_to": null}'), -- Conditional Actions ('conditional_branch', 'Conditional Branch', 'Executes different actions based on conditions', 'control_flow', '{"type": "object", "properties": {"condition": {"type": "string"}, "if_true": {"type": "array"}, "if_false": {"type": "array"}}}', '{"condition": "confidence_score > 0.85", "if_true": [{"action": "create_ticket"}], "if_false": [{"action": "flag_for_review"}]}'); -- Insert Example Workflows INSERT INTO email_workflows (name, description, classification_trigger, confidence_threshold, workflow_steps, priority, enabled) VALUES -- Invoice Workflow ('Invoice Processing', 'Automatic processing of invoice emails', 'invoice', 0.70, '[ {"action": "link_to_vendor", "params": {"match_by": "email", "auto_create": false}}, {"action": "extract_invoice_data", "params": {"ai_provider": "ollama", "fallback_to_regex": true}}, {"action": "create_ticket", "params": {"module": "billing_invoices", "priority": "normal"}}, {"action": "send_slack_notification", "params": {"channel": "#invoices", "template": "New invoice from {{sender}}: {{extracted_invoice_number}}"}}, {"action": "mark_as_processed", "params": {"status": "processed"}} ]'::jsonb, 10, true), -- Time Confirmation Workflow ('Time Confirmation Processing', 'Process time tracking confirmations', 'time_confirmation', 0.65, '[ {"action": "link_to_customer", "params": {"match_by": "email_domain", "domain_matching": true}}, {"action": "create_time_entry", "params": {"extract_from": "body", "default_hours": 1.0}}, {"action": "send_email_notification", "params": {"recipients": ["admin@bmcnetworks.dk"], "template": "time_confirmation"}}, {"action": "mark_as_processed", "params": {"status": "processed"}} ]'::jsonb, 20, true), -- Freight Note Workflow ('Freight Note Processing', 'Track shipments from freight notes', 'freight_note', 0.70, '[ {"action": "extract_tracking_number", "params": {"carriers": ["postnord", "gls", "dao"]}}, {"action": "link_to_vendor", "params": {"match_by": "email", "auto_create": false}}, {"action": "create_ticket", "params": {"module": "hardware_shipments", "priority": "low"}}, {"action": "mark_as_processed", "params": {"status": "processed"}} ]'::jsonb, 30, true), -- Bankruptcy Alert Workflow ('Bankruptcy Alert', 'Alert team when customer bankruptcy detected', 'bankruptcy', 0.80, '[ {"action": "flag_for_review", "params": {"reason": "Customer bankruptcy notification", "assign_to": null}}, {"action": "send_slack_notification", "params": {"channel": "#alerts", "template": "🚨 Bankruptcy alert: {{subject}}"}}, {"action": "send_email_notification", "params": {"recipients": ["admin@bmcnetworks.dk"], "template": "bankruptcy_alert"}}, {"action": "mark_as_processed", "params": {"status": "flagged"}} ]'::jsonb, 5, true), -- Low Confidence Review Workflow ('Low Confidence Review', 'Flag emails with uncertain classification', 'general', 0.50, '[ {"action": "flag_for_review", "params": {"reason": "Low confidence classification", "assign_to": null}} ]'::jsonb, 90, true); -- View for workflow monitoring CREATE OR REPLACE VIEW v_workflow_stats AS SELECT wf.id, wf.name, wf.classification_trigger, wf.enabled, wf.execution_count, wf.success_count, wf.failure_count, ROUND((wf.success_count::numeric / NULLIF(wf.execution_count, 0) * 100), 2) as success_rate, wf.last_executed_at, COUNT(wfe.id) as pending_executions, wf.created_at, wf.updated_at FROM email_workflows wf LEFT JOIN email_workflow_executions wfe ON wf.id = wfe.workflow_id AND wfe.status = 'pending' GROUP BY wf.id ORDER BY wf.priority; COMMENT ON TABLE email_workflows IS 'Automated workflows triggered by email classification'; COMMENT ON TABLE email_workflow_executions IS 'Log of all workflow executions'; COMMENT ON TABLE email_workflow_actions IS 'Registry of available workflow actions'; COMMENT ON VIEW v_workflow_stats IS 'Statistics and monitoring for email workflows';