Timeline Architecture
The timeline is the immutable audit log of Ikamet OS. Every meaningful action — status change, communication sent, task completed, document uploaded, payment received — writes a TimelineEvent.
Core principle
writeTimelineEvent()is the single entry point for all timeline writes. Never write to theTimelineEventtable directly in a route handler.
TimelineEvent structure
interface TimelineEvent { id: string event_type: string // e.g. "STATUS_CHANGE", "DOCUMENT_UPLOADED" title: string // Human-readable summary body?: string // Optional detail / notes metadata?: object // Machine-readable extra data staff?: StaffMember // Who triggered it (null = system) createdAt: Date
// Polymorphic links — one of these is set per event: user_id?: string // Customer timeline order_id?: string // Order timeline policy_id?: string // Policy timeline task_id?: string // Task timeline renewal_id?: string // Renewal timeline // ... other entity links}Event types
| Event type | Triggered when |
|---|---|
STATUS_CHANGE | Any workflow status updates |
ORDER_CREATED | New order placed |
POLICY_ISSUED | Insurance policy issued |
DOCUMENT_UPLOADED | Customer uploads a document |
DOCUMENT_REJECTED | Staff rejects a document |
COMMUNICATION_SENT | WhatsApp / email / SMS sent |
COMMUNICATION_RECEIVED | Inbound WhatsApp / email |
PAYMENT_RECEIVED | Payment confirmed |
PAYMENT_FAILED | Payment declined |
TASK_CREATED | New task created |
TASK_COMPLETED | Task marked complete |
RENEWAL_TRIGGERED | Renewal threshold crossed |
RENEWAL_COMPLETED | Renewal processed |
NOTE_ADDED | Internal note written |
AGENT_ASSIGNED | Customer assigned to agent |
COMPLIANCE_FLAG | Compliance issue flagged |
SYSTEM_EVENT | Automated system action |
Writing timeline events
import { writeTimelineEvent } from '@/lib/timeline.service';
// Direct writeawait writeTimelineEvent({ event_type: 'DOCUMENT_UPLOADED', title: 'Passport uploaded', body: 'Customer uploaded passport scan for verification.', user_id: customer.id, staff_id: req.staff?.id,});
// Convenience wrapper for status changesawait writeStatusChange( user_id, 'Residency Application', 'SUBMITTED', 'UNDER_REVIEW', { staff_id: req.staff.id, order_id: order.id });Reading timeline events
The getCustomerTimeline() function fetches events for a customer, ordered newest-first, with staff details included:
const timeline = await getCustomerTimeline(userId, { limit: 100 });// Returns: { data: TimelineEvent[], total: number }Why timeline-first?
- Auditability — every action is traceable to a person, time, and context
- Debugging — when something goes wrong, the timeline shows exactly what happened
- Customer visibility — the customer-facing portal can show appropriate timeline events
- AI context — the timeline gives AI agents the full operational history of a customer
- Compliance — regulated workflows (immigration, insurance) require complete audit trails