﻿syntax = "proto3";

package user_behavior_insights.v1;

import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

// An event that occurred, typically in response to a user.
message TrackEventRequest {
  // When the event took place.
  // This timestamp is formatted according to the [ISO 8601 standard](https://en.wikipedia.org/wiki/ISO_8601).
  // Note: Timestamps should be sent in UTC by specifying `Z` as the offset.
  google.protobuf.Timestamp timestamp = 1 [json_name="timestamp"];
  
  // Name of the application that is integrated with UBI.
  // You can think of application as a source of search queries.
  // For example, if you have a type-ahead and a traditional search UI,
  // then you might have `type-ahead` and `primary-search` as values.
  optional string application = 2 [json_name="application"];

  // The name of the action that triggered the event.
  // We have a set of common defaults, such as "click_through", "add_to_cart", and "view";
  // however, you can pass in any custom value you need.
  string action_name = 3 [json_name="action_name"];

  // The unique identifier of a query, typically a [ULID](https://github.com/ulid/spec), but can be any string.
  optional string query_id = 4 [json_name="query_id"];

  // The session of the user creating the interactions.
  // This allows us to correlate the interactions with the other events created by
  // a service that recognizes session IDs. Can be used to track unique visits for
  // authenticated and anonymous users.
  optional string session_id = 5 [json_name="session_id"];

  // The client issuing the query.
  // This could be a unique browser, a microservice that performs searches, or a crawling bot.
  optional string client_id = 6 [json_name="client_id"];

  // The user ID associated with the person performing the interactions being logged on the site.
  // Can be null/empty in case of an unauthenticated user.
  optional string user_id = 7 [json_name="user_id"];

  // The query as the user entered it.
  // No length limit specified. Currently not required to support recommendation
  // systems, etc., that might not have a user-generated query.
  optional string user_query = 8 [json_name="user_query"];
  
  // Group various `action_name`'s into logical bins.
  optional string message_type = 9 [json_name="message_type"];

  // Optional text message for the log entry.
  // For example, for a message_type of QUERY, we would expect the text to
  // be about what the user is searching on.
  optional string message = 10 [json_name="message"];

  // Extensible details about a specific event.
  optional EventAttributes event_attributes = 11 [json_name="event_attributes"];
}

// Extensible details about a specific event.
message EventAttributes {
  // Structure that contains identifying information of the object returned
  // from the query that the user interacts with (i.e.: a book, a product, a post, etc.).
  optional ObjectDetails object = 1 [json_name="object"];

  // Structure that contains information on the location of the event origin,
  // such as screen x, y coordinates, or the nth object out of 10 results.
  Position position = 2 [json_name="position"];
  
  // Additional properties
  map<string, google.protobuf.Value> additional_properties = 3; 
}

// Structure that contains identifying information of the object returned
// from the query that the user interacts with (i.e.: a book, a product, a post, etc.).
message ObjectDetails {
  // The id that a user could look up and find the object instance within the document corpus.
  // Examples include: _ssn_, _isbn_, _ean_, etc.
  // Variants need to be incorporated in the `object_id`, so for a t-shirt that is red,
  // you would need SKU level as the `object_id`.
  string object_id = 1 [json_name="object_id"];

  // The type of the object id that the user is searching for.
  // For a social e-commerce site, these could include product, user, post, comment, and so on.
  optional string object_id_type = 2 [json_name="object_id_type"];

  // The name of the field that has the id of the objects that will be stored in the backend queries data store.
  // If you do not provide this value, then the default primary identifier in your search index will be used.
  // For example, `_id` in Elasticsearch and OpenSearch.
  optional string object_id_field = 3 [json_name="object_id_field"];

  // A unique id that an individual search engine uses internally to index the object.
  // For example, in Elasticsearch and OpenSearch, this might be the `_id` field in the indices.
  optional string internal_id = 4 [json_name="internal_id"];

  // Additional properties
  map<string, google.protobuf.Value> additional_properties = 5;
}

// Structure that contains information on the location of the event origin,
// such as screen x, y coordinates, or the nth object out of 10 results.
message Position {
  // The nth position of the document on the search results page.
  google.protobuf.Int32Value ordinal = 1 [json_name="ordinal"];

  // The horizontal location on the page or screen of the event.
  google.protobuf.DoubleValue x = 2 [json_name="x"];

  // The vertical location on the page or screen of the event.
  google.protobuf.DoubleValue y = 3 [json_name="y"];
  
  // Additional properties
  map<string, google.protobuf.Value> additional_properties = 4;
}

// A request to track one or more events.
message TrackEventsRequest {
  repeated TrackEventRequest events = 1 [json_name="events"];
}

message TrackEventResponse {
}

message TrackEventsResponse {
}

// Represents a query made by a user for UBI tracking.
message TrackQueryRequest {
  // When the query was issued.
  // This timestamp is formatted according to the [ISO 8601 standard](https://en.wikipedia.org/wiki/ISO_8601).
  // If you are replaying data, or want to track the timezone
  // of the caller specifically, instead of using the search engine's timezone,
  // you will need to provide the timestamp instead.
  // Note: Timestamps should be sent in UTC by specifying `Z` as the offset.
  optional google.protobuf.Timestamp timestamp = 1 [json_name="timestamp"];
  
  // Name of the application that is integrated with UBI.
  // You can think of application as a source of search queries.
  // For example, if you have a type-ahead and a traditional search UI,
  // then you might have `type-ahead` and `primary-search` as values.
  optional string application = 2 [json_name="application"];

  // The unique identifier of a query, typically a [ULID](https://github.com/ulid/spec), but can be any string.
  // If unspecified, a unique id will be generated.
  optional string query_id = 3 [json_name="query_id"];
  
  // The client issuing the query.
  // This could be a unique browser, a microservice that performs searches, or a crawling bot.
  // If only authenticated users are tracked, then you could use a specific user ID here;
  // otherwise, you should use something permanent and track the user ID as an additional property.
  optional string client_id = 4 [json_name="client_id"];

  // The query as the user entered it.
  // No length limit specified. Currently not required to support recommendation
  // systems, etc., that might not have a user-generated query.
  string user_query = 5 [json_name="user_query"];
  
  // Any query modifiers like filter choices or pagination. Other attributes such as 
  // experiment identifiers that need to be tracked with the query.
  map<string, google.protobuf.Value> query_attributes = 7 [json_name="query_attributes"];

  // The unique identifier of a query response, typically a [ULID](https://github.com/ulid/spec), but can be any string.
  // If unspecified, a unique id will be generated.
  optional string query_response_id = 8 [json_name="query_response_id"];
  
  // The IDs of the hits for the query.
  repeated string query_response_hit_ids = 9 [json_name="query_response_hit_ids"];
  
  // The name of the field that has the ID of the objects that will be stored in the backend queries data store.
  // For example, if you have a query for products and want to save the SKUs, then this might be `sku`,
  // and if you are querying for people, maybe this is `ssn`. If you do not provide this value,
  // then the default primary identifier in your search index will be used.
  // For example, `_id` in Elasticsearch and OpenSearch.
  optional string object_id_field = 10 [json_name="object_id_field"];
}

// The response to a query made by a user should support this schema
message TrackQueryResponse {
  // The unique identifier of a query, typically a [ULID](https://github.com/ulid/spec), but can be any string.
  string query_id = 1 [json_name="query_id"];

  // The unique identifier of a query response, typically a ULID, but can be any string.
  // If unspecified, a unique id will be generated.
  string query_response_id = 2 [json_name="query_response_id"];
}