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
namefield uses dot-notation by convention (e.g.,page.viewed,api.called,button.clicked) but any string is accepted. propertiesis a freeform object that can contain any event-specific data.userIdandsessionIdare optional but recommended for meaningful reporting.timestampis set automatically at ingestion time if not provided.
Event Naming Conventions
While not enforced, the recommended naming pattern is <noun>.<verb>:
| Pattern | Examples |
|---|---|
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:
| Table | Description |
|---|---|
pulse_events | Event 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.