Skip to main content

Personalization Service

Overview

The Personalization Service is a key-value storage service for frontend applications for end-user-specific data. It can be thought of as a browser local storage but shared between clients across multiple devices.

Some supported use-cases:

  • User preferences
  • User profile data
  • Favorites
  • Usage history
  • Playback progress

Personalization Service is a managed multi-tenant service; it works together with the User Service and extends its capabilities.

Personalization Service C4 Context Diagram

Personalization Service C4 Context Diagram

Data Model

Key-Value pairs are stored in the Personalization Service. A Key is represented by a string, that contains any number of word characters separated by colon. The value can be a primitive type (string, number, boolean), a JSON, or an array of items.

note

Value size of primitive type and JSON is limited to 10 KB. For value of type array - each item size is limited to 10 KB.

Key Scope. Stored keys can have one of the following scopes:

ScopeDescription
UserKeys saved under User scope are specific to the user and can be shared between user’s profiles and applications.
ProfileProfile scope allows to save key-value pairs specific to the user’s profile, but can be shared between different applications. User can get access to values saved in this scope, only if authorized with same profile, as the one used for saving the key-value.
ApplicationThis scope is used for storing key-value pairs, that are specific to application. Keys stored in Application scope cannot be shared between multiple applications and profiles. User authorized with same profile and within same application, that were used for saving pair, can get access to keys.

Interfaces

Personalization Service exposes three APIs:

  • Data API - allows to set, retrieve and delete key-value pairs
  • Progress API - special asynchronous interface to support the playback progress use case
  • Array API - specialized API supporting list and array structures: storing Favorites, Watch history, etc

APIs are based on GraphQL.

Data API

Data API provides the general methods for manipulating the key-value pairs. Value supported by this API, are primitive type and JSON.

GraphQL Schema

"""
JSON custom scalar type with value size constraint.
"""
scalar JSON

enum KeyScope {
USER
PROFILE
APPLICATION
}

interface QueryResponse {
key: String!
value: JSON
}

type KeyValueResponse implements QueryResponse {
key: String!
value: JSON!
}

interface MutationResponse {
acknowledged: Boolean!
}

type SetKeyResponse implements MutationResponse {
acknowledged: Boolean!
insertedCount: Int!
updatedCount: Int!
}

input SetKeyInput {
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
value: JSON!
}

input DeleteKeyInput {
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
}

type DeleteKeyResponse implements MutationResponse {
acknowledged: Boolean!
deletedCount: Int!
}

input GetKeyInput {
scope: KeyScope!
keys: [String!]! @constraintArray(pattern: "^\\w+(:\\w+)*$")
}

type GetKeyResponse {
data: [KeyValueResponse!]!
}

type Query {
"""
Returns a value of a key or values of multiple keys.
"""
getKey(input: GetKeyInput!): GetKeyResponse!
}

type Mutation {
"""
Sets key to hold specified value.
"""
setKey(input: SetKeyInput!): SetKeyResponse!

"""
Deletes a key.
"""
deleteKey(input: DeleteKeyInput!): DeleteKeyResponse!
}


Progress API

Progress API provides an efficient solution to a specific use case - playback progress.

This use case is relevant for any video playback solution. This API supports storing end-users’s playback progress for each video they started to watch. To achieve this frontend player periodically sends its current playback position. The server stores the latest reported position and provides upon request.

Progress API is an asynchronous API that is optimized for storing frequent progress updates from a large number of concurrent clients. The API takes advantage of an optimized queue, which only retains the last relevant value for the playback progress.

Value can be only of type integer.

GraphQL Schema

"""
JSON custom scalar type with value size constraint.
"""
scalar JSON

enum KeyScope {
USER
PROFILE
APPLICATION
}

interface MutationResponse {
acknowledged: Boolean!
}

input SetProgressInput {
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
value: Int!
}

type SetProgressResponse implements MutationResponse {
acknowledged: Boolean!
}

input DeleteProgressInput {
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
}

type DeleteProgressResponse implements MutationResponse {
acknowledged: Boolean!
deletedCount: Int!
}

input GetProgressInput {
scope: KeyScope!
keys: [String!]! @constraintArray(pattern: "^\\w+(:\\w+)*$")
}

type ProgressData {
key: String!
value: Int!
}

type GetProgressResponse {
acknowledged: Boolean
data: [ProgressData!]!
}

type Query {
"""
Returns value of a progress key.
"""
getProgress(input: GetProgressInput!): GetProgressResponse!
}

type Mutation {
"""
Sets key to hold specified progress value.
"""
setProgress(input: SetProgressInput!): SetProgressResponse!

"""
Deletes a (progress) key.
"""
deleteProgress(input: DeleteProgressInput!): DeleteProgressResponse!
}


Array API

Array API provides functionality to store list of items as a value of a key. Endpoints provide possibility to set array of items to the key, adding item to already existing array, deleting, or updating item by auto-generated identifier. Endpoint Get Array supports pagination of array items.

Personalization Service supports sorting of array items. Each item in array can have up to three sort values, saved to predefined properties when adding new array item, or updating existing item. Sorting can be performed by one string value, one number and one date value.

Array can contain items of primitive and JSON types.

GraphQL Schema

"""
JSON custom scalar type with value size constraint.
"""
scalar JSON

"""
A point in time as described by the [ISO
8601](https://en.wikipedia.org/wiki/ISO_8601) standard. May or may not include a timezone.
"""
scalar Datetime

enum SortProperty {
sortString
sortNumber
sortDate
dateModified
id
}

enum SortDirection {
asc
desc
}

enum KeyScope {
USER
PROFILE
APPLICATION
}

input ArrayItem {
value: JSON!
sortString: String
sortNumber: Int
sortDate: Datetime
}

interface MutationResponse {
acknowledged: Boolean!
}

input SetArrayItemInput{
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
value: JSON!
id: String
sortString: String
sortNumber: Int
sortDate: Datetime
}

type SetArrayItemResponse implements MutationResponse{
acknowledged: Boolean!
modifiedCount: Int!
insertedCount: Int!
}

input SetArrayInput{
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
values: [ArrayItem!]!
}

type SetArrayResponse implements MutationResponse{
acknowledged: Boolean!
insertedCount: Int!
}

input GetArrayItemInput {
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
id: String!
}

type GetArrayItemResponse {
key: String!
value: JSON!
id: String
sortString: String
sortNumber: Int
sortDate: Datetime
dateModified: Datetime!
}

input GetArrayInput {
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
skip: Int
take: Int
sort: SortProperty
sortDirection: SortDirection
}

type GetArrayResponse {
key: String!
totalCount: Int!
skip: Int!
take: Int!
sort: SortProperty!
sortDirection: SortDirection!
data: [GetArrayItemResponse!]
}

input DeleteArrayInput{
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
}

type DeleteArrayResponse implements MutationResponse{
acknowledged: Boolean!
deletedCount: Int!
}

input DeleteArrayItemInput{
scope: KeyScope!
key: String! @constraint(pattern: "^\\w+(:\\w+)*$")
id: String!
}

type DeleteArrayItemResponse implements MutationResponse{
acknowledged: Boolean!
deletedCount: Int!
}

type Query {
"""
Returns a array of a key.
"""
getArray(input: GetArrayInput!): GetArrayResponse!

"""
Returns a array item of a key.
"""
getArrayItem(input: GetArrayItemInput!): GetArrayItemResponse!
}

type Mutation {
"""
Set array to the key.
"""
setArray(input: SetArrayInput!): SetArrayResponse!
"""
Adds new item to array, or updates existing, based on item id.
"""
setArrayItem(input: SetArrayItemInput!): SetArrayItemResponse!

"""
Deletes an array key.
"""
deleteArray(input: DeleteArrayInput!): DeleteArrayResponse!

"""
Deletes an array value by specified id.
"""
deleteArrayItem(input: DeleteArrayItemInput!): DeleteArrayItemResponse!
}


Authentication & Authorization

Personalization Service is a managed service facing frontend applications. All interface communication requires a JWT bearer token issued by the User Service.

Pricing

The service fee follows the tiered model depending on the number of end-users whose data is stored. See Mosaic Pricing for more details.