Files
portal/docs/storylines.md
T

61 lines
2.4 KiB
Markdown
Raw Normal View History

# Storylines
The same site, told two ways, and counted.
Anywhere content says something to a person, it may say it in several
ways by giving a list instead of one string:
```yaml
2026-09-30 15:31:59 +02:00
name: Want to help out in the neighbourhood?
description:
2026-09-30 15:31:59 +02:00
- The work day, the spring fair and the committees need more hands. Say what you can do.
- The neighbours do most things themselves. Sign up here for whatever you fancy.
alternatives:
2026-09-30 15:31:59 +02:00
- name: [Join in, Sign me up]
consequence: [[Send], [Count me in]]
```
Each index is a *storyline*. A visitor is given one at their first
request, kept in a cookie (`portal_storyline`) for a year, and reads
that storyline on every page, in every button and in every mail the
site sends them about their case. A single string is every storyline.
## The rules
- **Same length everywhere.** Every list of texts in the content has
the site's arity, so a storyline never has a hole in it. The lint
refuses a list of another length and names it.
- **What varies is what a person reads:** `name`, `description`,
`label`, `placeholder`, `title`, a mail's `subject` and `body`, a
list's `empty` line, `consequence` and `encouragements` (those two as
lists of lists).
- **What the machine reads never varies:** a field's `name` (the stored
key), a select's `options` (the stored values), states, groups,
paths, buckets.
- **One storyline per site**, not per page. That is what makes it a
storyline rather than a scatter of variants: a warm front door leads
to a warm form and a warm mail.
- A signed-in person keeps the storyline they had as a visitor.
- A site that tells one storyline sets no cookie.
## What is counted
Every record and every answer event carries the storyline it came
from (`storyline` on `Answer` and on `portal.answers.submitted`). The
mail a case gets tells the same storyline, so a person who read the
warm front door is not thanked in the plain voice.
`GET /report` gives the counts, per bucket, per storyline, per state:
```json
{ "storylines": 2,
2026-09-30 15:31:59 +02:00
"buckets": { "requests": { "0": { "open": 3, "solved": 9 },
"1": { "open": 5, "solved": 14 } } } }
```
Storylines are assigned evenly, so those numbers are the comparison:
which words brought more people to send, and how their cases went. No
record, field, address or time leaves the site. The trainer reads this
2026-09-30 15:31:59 +02:00
(`portal report`) next to what its personas scored offline, and
the plan's `tones` are where the storylines are written.