There are problems with this design. Don't use it in prod
- We should have a naming grammar which uses adjectives end note
- id (primary key) - unique event id
- name (string) - event name
- user_id (int) - identifies the actor responsible for triggering the event
- distinct_id (string) - uuid from device or session token
- target_type (string)
- target_id (int)
- app_id (string) - name of the application running the code
- app_version (string) - deployed application code version creating the event
- ip_address (string) - IP of host creating the event
- platform (string) - one of "web", "ios", "android"
- meta (JSON hash) - misc. attributes necessary for logging and auditing the event (e.g. error messages for login failure)
- created_at (datetime)
Format: <noun phrase>:<verb phrase>
or <verb phrase>
Each phrase consists of words in underscore case joined by periods. This keeps names consistent and preserves word distinctions for case-insensitive SQL
good: signed_in.success
, signed_out
bad: signed in success
, SignedOut
Nouns are always before the verb. (string prefix indexes will be more performant grouping actions on similar objects, instead of actions)
good: app:launched
, lesson:completed
bad: launched:app
, completed:lesson
Noun phrases begin with the object, followed by an optional keypath to a specific attribute. This groups events on similar entities for SQL's string prefix indexes
good: user.email:changed
bad: user:email_changed
, email:changed
Every event has exactly one word which is a verb. Each record should represent exactly one event
good: app:launched
, account:created
bad: app
, account:created.signed_in
Verb phrases consist of exactly one word which is a verb, followed by an optional modifier.
good: account:created
, signed_in.success
bad: account:created.signed_in
, signed_in_success
Modifiers indicate notable categories of the event, like success or the first occurrence. This groups similar events together for better performance with SQL string prefix indexes
good: account:created.success
, app:launched.first
bad: account:failure.created
, app:launched.once
Verbs must be in past tense. Events represent an event which has just happened (i.e. in the past)
good: app:launched
bad: app:launch
Events which revert a previous event should be named with a new verb.
good: answers:reset
, answers:restored
bad: answers:reset
answer:reset.undo
For Mixpanel, the name is the noun phrase and verb converted to title case to follow their naming conventions. (e.g. lesson:watched
=> "Lesson Watched"). The modifier should be sent as a value in the properties hash.
Events represent sentences in the past tense of a subject-object-verb language where the subject is indicated by user_id
/distinct_id
and the object and verb as segments in name
.
The object in name
is indefinite (e.g. video:watched
means "watched a video"), unless there's a target
to make the object definite (e.g. "watched the video with id of 74").
Modifiers are adverbs (e.g. .success
means "successfully") which modify whichever verb they follow.
Timing of the event is established by created_at
, location of the event with ip_address
, and originating application by app_id
/app_version
/platform
.
This should cover who, what, when, where, and how. It's up to our analysis to figure out the why.
app:launched
app:launched.first
experiment:started
(assigned an A/B variant)intro:viewed
intro:finished
account:created
signed_in.success
signed_in.failure
signed_out
lesson:completed
lesson:uncompleted
lesson:watched
user.email:changed
flashcard_answers:reset
flashcard_answers:restored
app.playback_rate:changed
- Are there other dimensions (e.g. "count") or attributes we should be tracking in their own columns?
- Is there a more readable phrase separator than colons?
- Should nouns allow namespacing? (e.g.
flashcard/answers:reset
instead offlashcard_answers:reset
) - What else?