457 lines
11 KiB
Markdown
457 lines
11 KiB
Markdown
|
|
# Email Activity Logging System
|
||
|
|
|
||
|
|
## Oversigt
|
||
|
|
|
||
|
|
Komplet audit trail system der logger **alt** hvad der sker med emails i BMC Hub. Hver handling, ændring og event bliver logget automatisk med timestamps, metadata og kontekst.
|
||
|
|
|
||
|
|
## 🎯 Hvad Bliver Logget?
|
||
|
|
|
||
|
|
### System Events
|
||
|
|
- **fetched**: Email hentet fra mail server
|
||
|
|
- **classified**: Email klassificeret af AI/keyword system
|
||
|
|
- **workflow_executed**: Workflow kørt på email
|
||
|
|
- **rule_matched**: Email regel matchet
|
||
|
|
- **status_changed**: Email status ændret
|
||
|
|
- **error**: Fejl opstået under processing
|
||
|
|
|
||
|
|
### User Events
|
||
|
|
- **read**: Email læst af bruger
|
||
|
|
- **attachment_downloaded**: Attachment downloaded
|
||
|
|
- **attachment_uploaded**: Attachment uploaded
|
||
|
|
|
||
|
|
### Integration Events
|
||
|
|
- **linked**: Email linket til vendor/customer/case
|
||
|
|
- **invoice_extracted**: Faktura data ekstraheret fra PDF
|
||
|
|
- **ticket_created**: Support ticket oprettet
|
||
|
|
- **notification_sent**: Notifikation sendt
|
||
|
|
|
||
|
|
## 📊 Database Schema
|
||
|
|
|
||
|
|
### email_activity_log Table
|
||
|
|
```sql
|
||
|
|
CREATE TABLE email_activity_log (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
email_id INTEGER NOT NULL, -- Hvilken email
|
||
|
|
event_type VARCHAR(50) NOT NULL, -- Hvad skete der
|
||
|
|
event_category VARCHAR(30) NOT NULL, -- Kategori (system/user/workflow/etc)
|
||
|
|
description TEXT NOT NULL, -- Human-readable beskrivelse
|
||
|
|
metadata JSONB, -- Ekstra data som JSON
|
||
|
|
user_id INTEGER, -- Bruger hvis user-triggered
|
||
|
|
created_at TIMESTAMP, -- Hvornår
|
||
|
|
created_by VARCHAR(255) -- Hvem/hvad
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
### email_timeline View
|
||
|
|
Pre-built view med joins til users og email_messages:
|
||
|
|
```sql
|
||
|
|
SELECT * FROM email_timeline WHERE email_id = 123;
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔧 Hvordan Bruges Det?
|
||
|
|
|
||
|
|
### I Python Code
|
||
|
|
|
||
|
|
```python
|
||
|
|
from app.services.email_activity_logger import email_activity_logger
|
||
|
|
|
||
|
|
# Log email fetch
|
||
|
|
await email_activity_logger.log_fetched(
|
||
|
|
email_id=123,
|
||
|
|
source='imap',
|
||
|
|
message_id='msg-abc-123'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Log classification
|
||
|
|
await email_activity_logger.log_classified(
|
||
|
|
email_id=123,
|
||
|
|
classification='invoice',
|
||
|
|
confidence=0.85,
|
||
|
|
method='ai'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Log workflow execution
|
||
|
|
await email_activity_logger.log_workflow_executed(
|
||
|
|
email_id=123,
|
||
|
|
workflow_id=5,
|
||
|
|
workflow_name='Invoice Processing',
|
||
|
|
status='completed',
|
||
|
|
steps_completed=3,
|
||
|
|
execution_time_ms=1250
|
||
|
|
)
|
||
|
|
|
||
|
|
# Log status change
|
||
|
|
await email_activity_logger.log_status_changed(
|
||
|
|
email_id=123,
|
||
|
|
old_status='active',
|
||
|
|
new_status='processed',
|
||
|
|
reason='workflow completed'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Log entity linking
|
||
|
|
await email_activity_logger.log_linked(
|
||
|
|
email_id=123,
|
||
|
|
entity_type='vendor',
|
||
|
|
entity_id=42,
|
||
|
|
entity_name='Acme Corp'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Log invoice extraction
|
||
|
|
await email_activity_logger.log_invoice_extracted(
|
||
|
|
email_id=123,
|
||
|
|
invoice_number='INV-2025-001',
|
||
|
|
amount=1234.56,
|
||
|
|
success=True
|
||
|
|
)
|
||
|
|
|
||
|
|
# Log error
|
||
|
|
await email_activity_logger.log_error(
|
||
|
|
email_id=123,
|
||
|
|
error_type='extraction_failed',
|
||
|
|
error_message='PDF corrupted',
|
||
|
|
context={'file': 'invoice.pdf', 'size': 0}
|
||
|
|
)
|
||
|
|
|
||
|
|
# Generic log (for custom events)
|
||
|
|
await email_activity_logger.log(
|
||
|
|
email_id=123,
|
||
|
|
event_type='custom_event',
|
||
|
|
category='integration',
|
||
|
|
description='Custom event happened',
|
||
|
|
metadata={'key': 'value'}
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Via SQL
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Log event directly via function
|
||
|
|
SELECT log_email_event(
|
||
|
|
123, -- email_id
|
||
|
|
'custom_event', -- event_type
|
||
|
|
'system', -- event_category
|
||
|
|
'Something happened', -- description
|
||
|
|
'{"foo": "bar"}'::jsonb, -- metadata (optional)
|
||
|
|
NULL, -- user_id (optional)
|
||
|
|
'system' -- created_by
|
||
|
|
);
|
||
|
|
|
||
|
|
-- Query logs for specific email
|
||
|
|
SELECT * FROM email_activity_log
|
||
|
|
WHERE email_id = 123
|
||
|
|
ORDER BY created_at DESC;
|
||
|
|
|
||
|
|
-- Use the view for nicer output
|
||
|
|
SELECT * FROM email_timeline
|
||
|
|
WHERE email_id = 123;
|
||
|
|
```
|
||
|
|
|
||
|
|
### Via API
|
||
|
|
|
||
|
|
```http
|
||
|
|
GET /api/v1/emails/123/activity
|
||
|
|
```
|
||
|
|
|
||
|
|
Response:
|
||
|
|
```json
|
||
|
|
[
|
||
|
|
{
|
||
|
|
"id": 1,
|
||
|
|
"email_id": 123,
|
||
|
|
"event_type": "fetched",
|
||
|
|
"event_category": "system",
|
||
|
|
"description": "Email fetched from email server",
|
||
|
|
"metadata": {
|
||
|
|
"source": "imap",
|
||
|
|
"message_id": "msg-abc-123"
|
||
|
|
},
|
||
|
|
"user_id": null,
|
||
|
|
"user_name": null,
|
||
|
|
"created_at": "2025-12-15T10:30:00",
|
||
|
|
"created_by": "system"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": 2,
|
||
|
|
"email_id": 123,
|
||
|
|
"event_type": "classified",
|
||
|
|
"event_category": "system",
|
||
|
|
"description": "Classified as invoice (confidence: 85%)",
|
||
|
|
"metadata": {
|
||
|
|
"classification": "invoice",
|
||
|
|
"confidence": 0.85,
|
||
|
|
"method": "ai"
|
||
|
|
},
|
||
|
|
"created_at": "2025-12-15T10:30:02",
|
||
|
|
"created_by": "system"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🎨 UI Integration
|
||
|
|
|
||
|
|
### Email Detail View
|
||
|
|
|
||
|
|
Når du vælger en email i email UI:
|
||
|
|
1. Klik på **"Log"** tab i højre sidebar
|
||
|
|
2. Se komplet timeline af alle events
|
||
|
|
3. Ekspander metadata for detaljer
|
||
|
|
|
||
|
|
### Timeline Features
|
||
|
|
- **Kronologisk visning**: Nyeste først
|
||
|
|
- **Color-coded ikoner**: Baseret på event category
|
||
|
|
- 🔵 System events (blue)
|
||
|
|
- 🟢 User events (green)
|
||
|
|
- 🔷 Workflow events (cyan)
|
||
|
|
- 🟡 Rule events (yellow)
|
||
|
|
- ⚫ Integration events (gray)
|
||
|
|
- **Expandable metadata**: Klik for at se JSON details
|
||
|
|
- **User attribution**: Viser hvem der udførte action
|
||
|
|
|
||
|
|
## 📈 Analytics & Monitoring
|
||
|
|
|
||
|
|
### Recent Activity Across All Emails
|
||
|
|
|
||
|
|
```http
|
||
|
|
GET /api/v1/emails/activity/recent?limit=50&event_type=error
|
||
|
|
```
|
||
|
|
|
||
|
|
### Activity Statistics
|
||
|
|
|
||
|
|
```http
|
||
|
|
GET /api/v1/emails/activity/stats
|
||
|
|
```
|
||
|
|
|
||
|
|
Response:
|
||
|
|
```json
|
||
|
|
[
|
||
|
|
{
|
||
|
|
"event_type": "classified",
|
||
|
|
"event_category": "system",
|
||
|
|
"count": 1523,
|
||
|
|
"last_occurrence": "2025-12-15T12:45:00"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"event_type": "workflow_executed",
|
||
|
|
"event_category": "workflow",
|
||
|
|
"count": 892,
|
||
|
|
"last_occurrence": "2025-12-15T12:44:30"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔍 Use Cases
|
||
|
|
|
||
|
|
### 1. Debugging Email Processing
|
||
|
|
```sql
|
||
|
|
-- See complete flow for problematic email
|
||
|
|
SELECT
|
||
|
|
event_type,
|
||
|
|
description,
|
||
|
|
created_at
|
||
|
|
FROM email_activity_log
|
||
|
|
WHERE email_id = 123
|
||
|
|
ORDER BY created_at;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Performance Monitoring
|
||
|
|
```sql
|
||
|
|
-- Find slow workflow executions
|
||
|
|
SELECT
|
||
|
|
email_id,
|
||
|
|
description,
|
||
|
|
(metadata->>'execution_time_ms')::int as exec_time
|
||
|
|
FROM email_activity_log
|
||
|
|
WHERE event_type = 'workflow_executed'
|
||
|
|
ORDER BY exec_time DESC
|
||
|
|
LIMIT 10;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. User Activity Audit
|
||
|
|
```sql
|
||
|
|
-- See what user did
|
||
|
|
SELECT
|
||
|
|
e.subject,
|
||
|
|
a.event_type,
|
||
|
|
a.description,
|
||
|
|
a.created_at
|
||
|
|
FROM email_activity_log a
|
||
|
|
JOIN email_messages e ON a.email_id = e.id
|
||
|
|
WHERE a.user_id = 5
|
||
|
|
ORDER BY a.created_at DESC;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Error Analysis
|
||
|
|
```sql
|
||
|
|
-- Find common errors
|
||
|
|
SELECT
|
||
|
|
metadata->>'error_type' as error_type,
|
||
|
|
COUNT(*) as count
|
||
|
|
FROM email_activity_log
|
||
|
|
WHERE event_type = 'error'
|
||
|
|
GROUP BY error_type
|
||
|
|
ORDER BY count DESC;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5. Workflow Success Rate
|
||
|
|
```sql
|
||
|
|
-- Calculate workflow success rate
|
||
|
|
SELECT
|
||
|
|
metadata->>'workflow_name' as workflow,
|
||
|
|
COUNT(*) FILTER (WHERE metadata->>'status' = 'completed') as success,
|
||
|
|
COUNT(*) FILTER (WHERE metadata->>'status' = 'failed') as failed,
|
||
|
|
ROUND(
|
||
|
|
100.0 * COUNT(*) FILTER (WHERE metadata->>'status' = 'completed') / COUNT(*),
|
||
|
|
2
|
||
|
|
) as success_rate
|
||
|
|
FROM email_activity_log
|
||
|
|
WHERE event_type = 'workflow_executed'
|
||
|
|
GROUP BY workflow
|
||
|
|
ORDER BY success_rate DESC;
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🚀 Auto-Logging
|
||
|
|
|
||
|
|
Følgende er allerede implementeret og logger automatisk:
|
||
|
|
|
||
|
|
✅ **Email Fetching** - Logged når emails hentes
|
||
|
|
✅ **Classification** - Logged når AI klassificerer
|
||
|
|
✅ **Workflow Execution** - Logged ved start og completion
|
||
|
|
✅ **Status Changes** - Logged når email status ændres
|
||
|
|
|
||
|
|
### Kommende Auto-Logging
|
||
|
|
⏳ Rule matching (tilføjes snart)
|
||
|
|
⏳ User read events (når user åbner email)
|
||
|
|
⏳ Attachment actions (download/upload)
|
||
|
|
⏳ Entity linking (vendor/customer association)
|
||
|
|
|
||
|
|
## 💡 Best Practices
|
||
|
|
|
||
|
|
### 1. Always Include Metadata
|
||
|
|
```python
|
||
|
|
# ❌ Bad - No context
|
||
|
|
await email_activity_logger.log(
|
||
|
|
email_id=123,
|
||
|
|
event_type='action_performed',
|
||
|
|
category='system',
|
||
|
|
description='Something happened'
|
||
|
|
)
|
||
|
|
|
||
|
|
# ✅ Good - Rich context
|
||
|
|
await email_activity_logger.log(
|
||
|
|
email_id=123,
|
||
|
|
event_type='invoice_sent',
|
||
|
|
category='integration',
|
||
|
|
description='Invoice sent to e-conomic',
|
||
|
|
metadata={
|
||
|
|
'invoice_number': 'INV-2025-001',
|
||
|
|
'economic_id': 12345,
|
||
|
|
'amount': 1234.56,
|
||
|
|
'sent_at': datetime.now().isoformat()
|
||
|
|
}
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Use Descriptive Event Types
|
||
|
|
```python
|
||
|
|
# ❌ Bad - Generic
|
||
|
|
event_type='action'
|
||
|
|
|
||
|
|
# ✅ Good - Specific
|
||
|
|
event_type='invoice_sent_to_economic'
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Choose Correct Category
|
||
|
|
- **system**: Automated system actions
|
||
|
|
- **user**: User-triggered actions
|
||
|
|
- **workflow**: Workflow executions
|
||
|
|
- **rule**: Rule-based actions
|
||
|
|
- **integration**: External system integrations
|
||
|
|
|
||
|
|
### 4. Log Errors with Context
|
||
|
|
```python
|
||
|
|
try:
|
||
|
|
result = extract_invoice_data(pdf_path)
|
||
|
|
except Exception as e:
|
||
|
|
await email_activity_logger.log_error(
|
||
|
|
email_id=email_id,
|
||
|
|
error_type='extraction_failed',
|
||
|
|
error_message=str(e),
|
||
|
|
context={
|
||
|
|
'pdf_path': pdf_path,
|
||
|
|
'file_size': os.path.getsize(pdf_path),
|
||
|
|
'traceback': traceback.format_exc()
|
||
|
|
}
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔒 Data Retention
|
||
|
|
|
||
|
|
Activity logs kan vokse hurtigt. Implementer cleanup strategi:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Delete logs older than 90 days
|
||
|
|
DELETE FROM email_activity_log
|
||
|
|
WHERE created_at < NOW() - INTERVAL '90 days';
|
||
|
|
|
||
|
|
-- Archive old logs to separate table
|
||
|
|
INSERT INTO email_activity_log_archive
|
||
|
|
SELECT * FROM email_activity_log
|
||
|
|
WHERE created_at < NOW() - INTERVAL '30 days';
|
||
|
|
|
||
|
|
DELETE FROM email_activity_log
|
||
|
|
WHERE created_at < NOW() - INTERVAL '30 days';
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📊 Performance Considerations
|
||
|
|
|
||
|
|
Med indexes på `email_id`, `event_type`, `created_at` og `event_category`, kan systemet håndtere millioner af log entries uden performance issues.
|
||
|
|
|
||
|
|
### Index Usage
|
||
|
|
```sql
|
||
|
|
-- Fast: Uses idx_email_activity_log_email_id
|
||
|
|
SELECT * FROM email_activity_log WHERE email_id = 123;
|
||
|
|
|
||
|
|
-- Fast: Uses idx_email_activity_log_event_type
|
||
|
|
SELECT * FROM email_activity_log WHERE event_type = 'workflow_executed';
|
||
|
|
|
||
|
|
-- Fast: Uses idx_email_activity_log_created_at
|
||
|
|
SELECT * FROM email_activity_log WHERE created_at > NOW() - INTERVAL '1 day';
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🎓 Examples
|
||
|
|
|
||
|
|
### Complete Email Lifecycle Log
|
||
|
|
```python
|
||
|
|
# 1. Email arrives
|
||
|
|
await email_activity_logger.log_fetched(email_id, 'imap', message_id)
|
||
|
|
|
||
|
|
# 2. AI classifies it
|
||
|
|
await email_activity_logger.log_classified(email_id, 'invoice', 0.92, 'ai')
|
||
|
|
|
||
|
|
# 3. Workflow processes it
|
||
|
|
await email_activity_logger.log_workflow_executed(
|
||
|
|
email_id, workflow_id, 'Invoice Processing', 'completed', 3, 1100
|
||
|
|
)
|
||
|
|
|
||
|
|
# 4. Links to vendor
|
||
|
|
await email_activity_logger.log_linked(email_id, 'vendor', 42, 'Acme Corp')
|
||
|
|
|
||
|
|
# 5. Extracts invoice
|
||
|
|
await email_activity_logger.log_invoice_extracted(
|
||
|
|
email_id, 'INV-001', 1234.56, True
|
||
|
|
)
|
||
|
|
|
||
|
|
# 6. Status changes
|
||
|
|
await email_activity_logger.log_status_changed(
|
||
|
|
email_id, 'active', 'processed', 'workflow completed'
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
Result: **Complete audit trail af email fra fetch til processed!**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Version**: 1.0
|
||
|
|
**Last Updated**: 15. december 2025
|
||
|
|
**Status**: ✅ Production Ready
|