Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions apps/platform/src/journey/JourneyUserStep.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AnyJson } from 'rules/Rule'
import Model from '../core/Model'
import { type JourneyStep } from './JourneyStep'

Expand All @@ -9,7 +10,7 @@ export default class JourneyUserStep extends Model {
delay_until?: Date
entrance_id?: number
ended_at?: Date
data?: Record<string, unknown> | null
data?: Record<string, AnyJson> | null
ref?: string

step?: JourneyStep
Expand All @@ -20,7 +21,7 @@ export default class JourneyUserStep extends Model {
static virtualAttributes = ['step']

static getDataMap(steps: JourneyStep[], userSteps: JourneyUserStep[]) {
return userSteps.reduceRight<Record<string, unknown>>((a, { data, step_id }) => {
return userSteps.reduceRight<Record<string, AnyJson>>((a, { data, step_id }) => {
const step = steps.find(s => s.id === step_id)
if (data && step && !a[step.dataKey]) {
a[step.dataKey] = data
Expand Down
15 changes: 12 additions & 3 deletions apps/platform/src/rules/RuleEngine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TemplateEvent } from '../users/UserEvent'
import { TemplateEvent } from 'users/UserEvent'
import { TemplateUser, User } from '../users/User'
import { Rule, AnyJson, RuleTree, Operator, RuleGroup, RuleType, EventRuleFrequency, EventRuleTree } from './Rule'
import NumberRule from './NumberRule'
Expand Down Expand Up @@ -26,6 +26,7 @@ class Registry<T> {
export interface RuleCheckInput {
user: TemplateUser
events: TemplateEvent[] // all of this user's events
journey: Record<string, AnyJson>
}

export interface RuleBaseParams {
Expand All @@ -39,7 +40,7 @@ export interface RuleQueryParams extends RuleBaseParams {

export interface RuleCheckParams extends RuleBaseParams {
input: RuleCheckInput // all contextual input data
value: Record<string, unknown> // current value to evaluate against
value: Record<string, AnyJson> // current value to evaluate against
}

export interface RuleCheck {
Expand Down Expand Up @@ -71,7 +72,15 @@ export const check = (input: RuleCheckInput, rule: RuleTree | RuleTree[]) => {
children: rule,
})
}
return ruleRegistry.get(rule.type).check({ registry: ruleRegistry, input, rule, value: input.user })

// NOTE: we have to flatten the user object to be backwards compatible with existing rules
// the journey property within the user object is overwritten if defined.
const value = {
...input.user,
journey: input.journey,
}

return ruleRegistry.get(rule.type).check({ registry: ruleRegistry, input, rule, value })
}

export const checkQuery = async (user: User, rule: RuleTree | RuleTree[]) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@
"user_update_desc": "Make updates to a user's profile.",
"user_update_edit_desc1": "Write a Handlebars template that renders JSON that will be shallow merged into the user's profile data.",
"user_update_edit_desc2": " The user's current profile data is available in the ",
"user_update_edit_desc3": "variable, and data collected at other steps are available in ",
"user_update_edit_desc3": " variable, and data collected at other steps are available in ",
"user_update_empty": "(click to see updated fields)",
"users": "Users",
"users_change_subscription_status": "Are you sure you want to change the status of this subscription?",
Expand Down
8 changes: 3 additions & 5 deletions docs/docs/how-to/journeys/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ This is the base data structure available in Journey (and Send step Campaign) pr
},
// Send steps that use webhooks can also store the response
"data_key_from_webhook_send": {
"response": {
"total_reward_points": 300,
"remaining_balance": 150
}
"total_reward_points": 300,
"remaining_balance": 150
}
}
}
Expand All @@ -52,7 +50,7 @@ To make stored step data available to subsequent steps, specify the Data Key:

![Journey Data Key Example](/img/journeys_data_key.png)

Gate steps can then access that data under `journey.DATA_KEY.*` (in this example, `journey.data_key_from_webhook_send.total_reward_points`).
Gate steps can then access that data under `$.journey.DATA_KEY.*` (in this example, `$.journey.data_key_from_webhook_send.total_reward_points`).

![Journey Data Key Gate Example](/img/journeys_data_key_gates.png)

Expand Down
27 changes: 27 additions & 0 deletions docs/docs/how-to/journeys/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ sidebar_position: 1
## Send
Sends are the main action you can perform inside of a journey. A send encapsulates a campaign under the hood giving you all of the same configuration you can get from a campaign. When a user reaches a send step the campaign is queued to be sent to the user.

You are able to access

```json
{
"result": "{{{ journeys[data_key]... }}}"
}
```

#### Parameters
- **Name**: What you would like to call the step
- **Data Key**: A unique key you can set to reference the result of the action ([more on that here](/how-to/journeys/data))
Expand Down Expand Up @@ -107,6 +115,13 @@ If you are trying to determine which of various options might perform the best,
## Gate
To split a user between paths depending on the result of a condition you can use a gate. Under the hood a gate uses the same rule builder as lists allowing you to build complex selectors targeting what a user has done (events) and properties on the user themselves. If a user matches the criteria, they are passed along to the `Yes` path, otherwise they are passed to the `No` path.

Variables in templates are prefixed with `$.`. User properties can be accessed directly at the root level. Journey step data can be accessed via `$.journey[data_key]`.

```
$.email # The user's email address
$.journey.webhook.updated # The "updated" field from the "webhook" journey step
```

![Journeys Gate](/img/journeys_gate.png)

#### Parameters
Expand All @@ -124,6 +139,18 @@ Links allow you to bring a user to the start of a selected journey. This can be
## Update
An update step allows you to make changes to the properties on a user. This can be useful if you are wanting to mark that a user went down a given path or you want to set values on the user from the result of another step.

It is possible to write Handlebars templates within the JSON that will be shallow merged into the user's profile data. The user's current profile data is available in the `user` variable. Data collected from previous journey steps can be accessed in `journey[data_key]`.

```json
{
"full_name": "{{{ journey.entrance.first_name }}} {{{ journey.entrance.last_name }}}"
"last_viewed_product": "{{{ journey.product.name }}}",
"last_viewed_category": "{{{ journey.product.category }}}"
}
```

> 🚧 The merge is shallow, nested objects are fully replaced, not merged.

#### Parameters
- **Name**: What you would like to call the step
- **Body**: A JSON object representing the values to be shallow merged onto the existing users properties. This is a Handlebars field so you can pull in user values or other values from the journey.