# Event Schema
Version: 0.1
## Bryan notes
### What we need to address
* Multiple potential triggers for certain UX sequences
* A: Start ux sequence when action takes place (i.e. when selecting to edit/open form)
* A: Shorter sequences are generally better
* A: Can track what happened before with userId or sessionId
* Generally: adding additional fields or making do with a leaner schema
* A: More fields is generally better (leads to less maintenance with later changes)
* Measuring xy distance - better to record assets when placed or record pre and post coordinates when moving, or use old_value & new_value
* Adding field point_id to measure different movement of specific points
* How to write flow steps, given differences in steps between platforms (Web, iOS, Android)
* A: Go with simplest flow between the different platforms
* Defining allowed types for input_type
* A: Bryan to come up with recommendation for what options are for each field in schema
* See: https://www.w3schools.com/html/html_form_input_types.asp
* Designers may already have requirements for what they want to track
## Goals
1. Allow any Unearth team member to see how customers are using our product
1. Define a schema that can be used by each Unearth client device to log customer behavior
### Non-goals
1. Remove syslog
1. Change structure of today's syslog files
## Vocabulary
The following terms are used throughout this document
- Syslog: A popular system logging software solution
- Event: a single user action, such as when a button is clicked
- Event Burst: an array of multiple events
- Centralized logging: the process of storing log files in one central location. In Unearth, syslogs are written S3
- Sequence: a series of events that will occur as part of a greater workflow like "Adding a Sewer lateral" or "Clear a parcel".
## What we want to track
### User Flow Events
- when a user starts, completes, or aborts a new sequence
- when a user activates a tool
- when a task has been assigned, or marked as complete
- events listed in https://docs.google.com/spreadsheets/d/188m1ELalgfFJBMV7Jf-qMAo77DVGIGigteWarwrsK34/edit#gid=0
- [...]
### System Events
- When the device is put to sleep / reawakened
- When network connectivity is lost / reacquired
## Event Schema
Please note that not every event attribute will be used in each request
- evt_id: A unique GUID
- evt_tags: One or more text labels used to describe the event. For instance, when a user has finished adding a sewer manhole to a map, the final event in the sequence might have two evt_tags: `on_sequence_complete` and `on_vertex_added`
- evt_triggered_date: the datetime (accurate to the second) of when the event was fired
- os_version: the numerical version number
- os_name: the name of the operating system
- host_id: a unique identifier representing the user's device
- host_wifi_enabled: whether the device's wifi is turned on
- host_wifi_connected: whether the device has a wifi connection
- host_cellular_enabled: whether the device's cellular data is turned on
- host_cellular_connected: whether the device has a cellular connection
- host_airplane_mode_enabled: whether airplane mode is on
- host_camera_permission_granted: if camera access is ok
- host_location_permission_granted: if location access is ok
- host_screen_pixels_width: like 1024
- host_screen_pixels_height: like 768
- input_type: the type of control that emitted the event. These should be consistent across all platforms, e.g. 'text' instead of 'iosTextArea'
- input_label: like "Submit Button" or "Datepicker"
- tool_id: If the event was generated by a tool, provide the tool id
- tool_label: If the event was generated by a tool, provide its label
- user_id: Unearth user GUID
- user_name
- user_account_id: Unearth account GUID
- user_account_name: like "Champion Cleaning"
- user_role_name: like "Admin""
- user_role_id: Unearth role guid
- browser_name: Like "Mozilla Firefox"
- browser_version: like "53.3"
- event_triggered_date: when the event was fired in ISO 8601 (UTC) format
- ux_seq_name: like "add_lateral"
- ux_seq_instance_id: A GUID generated each time a user starts a sequence. The sequence instance id is used to track all events that belong to a sequence
- old_lat: latitude coordinate for a point on the map, before a change in location
- old_long: longitude coordinate for a point on the map, before a change in location
- new_lat: latitude coordinate for a point on the map, after a change in location
- new_long: longitude coordinate for a point on the map, after a change in location
- old_value: the value before a transition in value of a form field
- new_value: the value after a transition
## Tasks
1. Identify each event_tag value that will be used in the initial launch
1. For each event sequence we want to track, create a series of examples that demonstrate to engineers the events that will be fired
## Example: User adds a Sewer Lateral
### Flow summary
1. Trigger: User opens toolkit and selects sewer lateral
1. User draws line
1. (Optional) user skips mapping
1. (Optional) user cancels
1. User fills out form
1. (Optional) user adds to map
1. User Submits form
1. (Optional) form fails validation
### Flow details
1. User opens toolkit
1. Select lateral tool
1. (primary) Happy path
```
{
evt_tags: on_tool_activated
ux_sequence_name: add_lateral
ux_sequence_instance_id: 1234-abcdef-123..
tool_name: "Sewer Lateral"
tool_id: 1234-...
tool_kit_id: 1234...
tool_geometry: "MultiLineString"
input_type: button
}
```
1. (Exceptional cases) User or system ends sequence.
1. **Skip mapping:** user has elected to skip mapping the asset
```
{
evt_tags: on_skip_mapping
input_label: "btn.skip_map"
input_type: button
[ux_sequence_*]
[tool_*]
}
```
1. **User abort:** user has stopped the sequence
```
{
evt_tags: on_user_abort
input_type: button
input_label: "btn.cancel"
[ux_sequence_*]
[tool_*]
}
```
1. **Service unavailable:** a service required to complete the sequence cannot be obtained
```
{
evt_tags: on_service_unavailable
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
1. **Add to map:** an unmapped asset is added to the map; after this the user goes to the following "User adds point"
```
{
evt_tags: add_to_map
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
1. User draws a line
1. User adds vertex 1
```
{
evt_tags: add_vertex
evt_triggered_date: DATETIME
input_type: map_interaction
[ux_sequence_*]
[tool_*]
}
```
1. User adds vertex 2 - same as vertex 1
1. User adds vertex 3 - same as vertex 1
1. User closes line
```
{
evt_tags: close_line
input_type: map_interaction
}
```
1. User fills out form. Form observers should log an event in two instances: 1) when a form input is updated or 2) the form is submitted.
1. User changes access point to cleanout
{
evt_tags: on_input_changed
input_type: select
input_label: access_point
old_value: 'Mainline Tap',
new_value: 'Cleanout'
}
1. User updates the length inspected text input
{
evt_tags: on_input_changed
input_type: text
input_label: length_inspected_ft
old_value: 74.49
new_value: 72.5
}
1. User submits form
{
evt_tags: on_form_submit
input_type: button
input_label: btn.submit
}
1. Client evaluates form
1. The form is valid
1. The form is invalid
1. Client logs whether
1. Record saved
{
evt_tags: on_flow_success
ux_sequence_success: true
}
1. Record not saved
{
ux_sequence_success: false
ux_sequence_abort_reason:
}
## Example: User adds a Manhole
### Flow summary
1. Trigger: User opens toolkit and selects Manhole
1. User taps on map to draw manhole
1. (Optional) user skips mapping
1. (Optional) user cancels
1. User fills out form
1. (Optional) user adds to map
1. User Submits form
1. (Optional) form fails validation
### Flow details
1. User opens toolkit
1. Select lateral tool
1. (primary) Happy path
```
{
evt_tags: on_tool_activated
ux_sequence_name: add_manhole
ux_sequence_instance_id: 1234-abcdef-123..
tool_name: "Sewer Manhole"
tool_id: 1234-...
tool_kit_id: 1234...
tool_geometry: "Point"
input_type: button
}
```
1. (Exceptional cases) User or system ends sequence.
1. **Skip mapping:** user has elected to skip mapping the asset
```
{
evt_tags: on_skip_mapping
input_label: "btn.skip_map"
input_type: button
[ux_sequence_*]
[tool_*]
}
```
1. **User abort:** user has stopped the sequence
```
{
evt_tags: on_user_abort
input_type: button
input_label: "btn.cancel"
[ux_sequence_*]
[tool_*]
}
```
1. **Service unavailable:** a service required to complete the sequence cannot be obtained
```
{
evt_tags: on_service_unavailable
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
1. **Add to map:** an unmapped asset is added to the map; after this the user goes to the following "User adds point"
```
{
evt_tags: add_to_map
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
1. User draws a point
1. User adds point
```
{
evt_tags: add_vertex
evt_tags: add_point
evt_triggered_date: DATETIME
input_type: map_interaction
[ux_sequence_*]
[tool_*]
}
```
1. User fills out form. Form observers should log an event in two instances: 1) when a form input is updated or 2) the form is submitted.
1. User changes status to not clear
{
evt_tags: on_input_changed
input_type: radio
input_label: status
old_value: 'Clear',
new_value: 'Not Clear'
}
1. User submits form
{
evt_tags: on_form_submit
input_type: button
input_label: btn.submit
}
1. Client evaluates form
1. The form is valid
1. The form is invalid
1. Client logs whether
1. Record saved
{
evt_tags: on_flow_success
ux_sequence_success: true
}
1. Record not saved
{
ux_sequence_success: false
ux_sequence_abort_reason:
}
## Example: User adds a Parcel Boundary
### Flow summary
1. Trigger: User opens toolkit and selects sewer lateral
1. User draws polygon
1. (Optional) user skips mapping
1. (Optional) user cancels
1. User fills out form
1. (Optional) user adds to map
1. User Submits form
1. (Optional) form fails validation
### Flow details
1. User opens toolkit
1. Select parcel boundary tool
1. (primary) Happy path
```
{
evt_tags: on_tool_activated
ux_sequence_name: add_parcel_poly
ux_sequence_instance_id: 1234-abcdef-123..
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234...
tool_geometry: "Polygon"
input_type: button
}
```
1. (Exceptional cases) User or system ends sequence.
1. **Skip mapping:** user has elected to skip mapping the asset
```
{
evt_tags: on_skip_mapping
input_label: "btn.skip_map"
input_type: button
[ux_sequence_*]
[tool_*]
}
```
1. **User abort:** user has stopped the sequence
```
{
evt_tags: on_user_abort
input_type: button
input_label: "btn.cancel"
[ux_sequence_*]
[tool_*]
}
```
1. **Service unavailable:** a service required to complete the sequence cannot be obtained
```
{
evt_tags: on_service_unavailable
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
1. **Add to map:** an unmapped asset is added to the map; after this the user goes to the following "User adds point"
```
{
evt_tags: add_to_map
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
1. User draws a line
1. User adds vertex 1
```
{
evt_tags: add_vertex
evt_triggered_date: DATETIME
input_type: map_interaction
[ux_sequence_*]
[tool_*]
}
```
1. User adds vertex 2 - same as vertex 1
1. User adds vertex 3 - same as vertex 1
1. User adds vertex 3 - same as vertex 1
1. User closes polygon
```
{
evt_tags: close_polygon
input_type: map_interaction
}
```
1. User fills out form. Form observers should log an event in two instances: 1) when a form input is updated or 2) the form is submitted.
1. User changes status to Complete
{
evt_tags: on_input_changed
input_type: dropdown
input_label: status
old_value: 'Incomplete',
new_value: 'Complete'
}
1. User submits form
{
evt_tags: on_form_submit
input_type: button
input_label: btn.submit
}
1. Client evaluates form
1. The form is valid
1. The form is invalid
1. Client logs whether
1. Record saved
{
evt_tags: on_flow_success
ux_sequence_success: true
}
1. Record not saved
{
ux_sequence_success: false
ux_sequence_abort_reason:
}
## Example: User edits form values for Parcel Boundary
### Flow summary
1. Trigger: User clicks on asset on map, or list or table view is on screen
2. User gets to asset form
1. From map
1. User clicks on asset on map
2. User selects View Info (not included on iOS)
2. From list view or table view
1. User clicks on asset's name
3. User edits form values
1. (Optional) user cancels before adding
4. User submits form with Done
1. (Optional) user cancels form editing
### Flow details (note: where should we note this as a unique flow / assign ux_sequence_name?)
1. User clicks on asset on map and then on view info, or on asset in list or table view
1. Asset on map and view info
1. User clicks on asset (note: this doesn't definitively start any specific UX sequence)
```
{
evt_tags: on_asset_from_map
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234.
tool_geometry: "Polygon"
input_type: asset
}
```
2. User clicks on View Info (note: this also doesn't definitively start a specific UX sequence, as the user could delete the asset from the following screen)
```
{
evt_tags: on_view_info
[tool_*]
}
```
2. Asset from list or table view (doesn't definitively start specific UX sequence)
```
{
evt_tags: on_asset_from_table
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234.
tool_geometry: "Polygon"
input_type: table
}
1. User edits form. Form observers should log an event in two instances: 1) when a form input is updated or 2) the form is submitted.
1. User changes status to Complete
{
evt_tags: on_input_changed
ux_sequence_name: edit_form
ux_sequence_instance_id: 1234-abcdef-123..
input_type: dropdown
input_label: status
old_value: 'Incomplete',
new_value: 'Complete'
}
1. User submits form
{
evt_tags: on_form_submit
[ux_sequence_*]
input_type: button
input_label: btn.submit
}
1. (Optional) user cancels form editing
```
{
evt_tags: on_form_exit
[ux_sequence_*]
input_type: button
input_label: btn.exit
}
```
1. Client evaluates form
1. The form is valid
1. The form is invalid
1. Client logs whether
1. Record saved
{
evt_tags: on_flow_success
ux_sequence_success: true
}
1. Record not saved
{
ux_sequence_success: false
ux_sequence_abort_reason:
}
## Example: User edits asset geometry
### Flow summary
1. Trigger: User clicks on asset
1. On map
1. Click on asset on map
2. Select Edit feature
2. In list or table view
2. If going from list or table view, or if the user selected View form instead of Edit feature, then click on asset
3. Move vertex (note: this can't be done on Android currently)
4. Click done
### Flow details
1. User clicks on asset
1. Click on asset
```
{
evt_tags: on_asset_from_map
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234.
tool_geometry: "Polygon"
input_type: asset
}
```
2. Move vertex
```
{
evt_tags: move vertex
ux_sequence_name: edit_geometry
ux_sequence_instance_id: 1234-abcdef-123..
[tool_*]
input_type: asset
old_lat = 123.123
old_long = 44.44
new_lat = 123.122
new_long = 44.43
}
```
1. **User abort:** user has stopped the sequence
```
{
evt_tags: on_user_abort
input_type: button
input_label: "btn.cancel"
[ux_sequence_*]
[tool_*]
}
```
1. **Service unavailable:** a service required to complete the sequence cannot be obtained
```
{
evt_tags: on_service_unavailable
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```
3. (Repeat moving vertices if a line or polygon)
4. User clicks done
1. User submits form
{
evt_tags: on_form_submit
input_type: button
input_label: btn.submit
}
2. Client evaluates form
1. The form is valid
1. The form is invalid
3. Client logs whether
1. Record saved
```
{
evt_tags: on_flow_success
ux_sequence_success: true
}
```
1. Record not saved
```
{
ux_sequence_success: false
ux_sequence_abort_reason:
}
```
## Example: User deletes asset
### Flow summary
1. Trigger: User clicks on asset on map, or list or table view is on screen
2. User gets to asset form
1. From map
1. User clicks on asset on map
2. User selects either View info or Edit feature (not included on mobile)
2. From list view or table view
1. User clicks on asset's name
3. User deletes asset
1. (Optional) user cancels before deleting
### Flow details
1. User clicks on asset on map and then on view info, or on asset in list or table view
1. Asset on map and view info
1. User clicks on asset (note: this doesn't definitively start any specific UX sequence)
```
{
evt_tags: on_asset_from_map
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234.
tool_geometry: "Polygon"
input_type: asset
}
```
2. User clicks on View Info (note: this also doesn't definitively start a specific UX sequence, as the user could delete the asset from the following screen)
```
{
evt_tags: on_view_info
[tool_*]
}
```
2. Asset from list or table view (doesn't definitively start specific UX sequence)
```
{
evt_tags: on_asset_from_table
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234.
tool_geometry: "Polygon"
input_type: table
}
2. User deletes asset
```
{
evt_tags: on_delete_asset
ux_sequence_name: delete_asset
ux_sequence_instance_id: 1234-abcdef-123..
tool_name: "Parcel Boundary"
tool_id: 1234-...
tool_kit_id: 1234.
tool_geometry: "Polygon"
input_type: button
}
```
1. **User abort:** user has stopped the sequence
```
{
evt_tags: on_user_abort
input_type: button
input_label: "btn.cancel"
[ux_sequence_*]
[tool_*]
}
```
1. **Service unavailable:** a service required to complete the sequence cannot be obtained
```
{
evt_tags: on_service_unavailable
input_type: null
input_label: null
[ux_sequence_*]
[tool_*]
}
```