bmc_hub/migrations/014_email_workflows.sql
Christian 3fb43783a6 feat: Implement Email Workflow System with comprehensive documentation and migration scripts
- Added Email Workflow System with automated actions based on email classification.
- Created database schema with tables for workflows, executions, and actions.
- Developed API endpoints for CRUD operations on workflows and execution history.
- Included pre-configured workflows for invoice processing, time confirmation, and bankruptcy alerts.
- Introduced user guide and workflow system improvements for better usability.
- Implemented backup system for automated backup jobs and notifications.
- Established email activity log to track all actions and events related to emails.
2025-12-15 12:28:12 +01:00

226 lines
10 KiB
PL/PgSQL

-- 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';