Skip to main content

Pulse Data Model

Pulse manages a single primary entity: Events. All entities use nanoid(8) identifiers and support both file-based and Convex storage backends.

Event

A tracked occurrence representing a user action, system event, or any measurable activity.

interface Event {
id: string; // nanoid(8) unique identifier
name: string; // Event name (e.g., "page.viewed", "button.clicked")
properties: Record<string, any>; // Arbitrary event properties
userId?: string; // Optional user who triggered the event
sessionId?: string; // Optional session identifier
timestamp: string; // ISO 8601 timestamp
}

Notes

  • The name field uses dot-notation by convention (e.g., page.viewed, api.called, button.clicked) but any string is accepted.
  • properties is a freeform object that can contain any event-specific data.
  • userId and sessionId are optional but recommended for meaningful reporting.
  • timestamp is set automatically at ingestion time if not provided.

Event Naming Conventions

While not enforced, the recommended naming pattern is <noun>.<verb>:

PatternExamples
page.*page.viewed, page.loaded
button.*button.clicked, button.hovered
api.*api.called, api.failed
user.*user.signed_up, user.logged_in
service.*service.deployed, service.restarted

Storage

File-Based (SHIFT_STORAGE=file)

.pulse/
events/
<id>.json # One file per event

Convex (SHIFT_STORAGE=convex)

Tables use the pulse_ prefix:

TableDescription
pulse_eventsEvent records

Each record includes a sid field (shift ID) that maps to the application-level id. Convex internal _id fields are abstracted away by the ConvexStore layer.