Initial content: opener, project, subscribed, applied

This commit is contained in:
Bendik Aagaard Lynghaug
2026-07-29 12:51:55 +02:00
commit 5321f70540
5 changed files with 167 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
# portal-content
Question/alternative/feature content for the [`portal`](../portal) app,
kept in its own repo so content edits don't require a Rust rebuild or
touch app code at all.
## Schema
Each file in `questions/` is one `Question` (see `portal`'s
`src/content.rs` for the exact struct). A question has one or more
`alternatives`; each alternative is a small form made of `features`,
each holding zero or more `requirements` (input fields).
```yaml
id: /some-path # matches a route; "/" is the landing page; English slugs
name: Headline
description: >
Markdown body text.
alternatives:
- name: Alternative label
description: One line explaining this path.
action: /next-question # id of the question to advance to on submit
consequence: [Button label]
features:
- name: A feature/section heading
description: Optional supporting text.
requirements:
- name: email
label: Email
type: email
```
`type` on a requirement is one of: `text`, `textarea`, `email`, `tel`,
`select`. Omit for plain text. Mark a requirement `optional: true` if
it isn't required.
There is deliberately no `color`/`icon` styling here — the app has a
single brand accent variable, not per-alternative colors. And there's
no branching/criteria language yet: today a human reads submissions off
NATS and decides what happens next. If that grows into something an LLM
posts follow-up questions into later, it publishes into the same shape
these files already are — this repo's format doesn't need to change for
that, just its source.
## Adding a question
Drop a new `questions/<id>.yaml` file and reference its `id` from an
existing alternative's `action`. No registration step - the app loads
every file in the directory at startup.
+18
View File
@@ -0,0 +1,18 @@
id: /applied
route: ^/applied
name: Thanks — it's in front of us
description: >
Someone here will actually read this and write back. If it's a
match, you'll get a personal invite next, not an automated welcome
email.
alternatives:
- name: What happens now
description: ""
features:
- name: A person reads it
description: No filter decides for us.
- name: You get an invite, not an account
description: >
If it's a match, we hand you a real key that gives you
access and a bit of responsibility — and, eventually, the
ability to invite the next person yourself.
+70
View File
@@ -0,0 +1,70 @@
id: /
name: We build things worth using
description: >
Software, run the way a connoisseur pours a drink: slowly enough to
notice what's actually there. Three ways in — pick the one that fits.
alternatives:
- name: I want something built
description: >
Infrastructure, tools, or a product that needs an owner who reads
the whole glass before writing tasting notes.
action: /project
consequence: [Tell us what you're after]
encouragements:
- No proposal mill — a real reply from a person who read it.
features:
- name: What are you after?
description: A few lines is plenty to start a conversation.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: project
label: What do you need built?
type: textarea
placeholder: The shape of it, not a spec — we'll ask questions.
- name: Keep me posted
description: >
Occasional notes on what we're building and why. No funnel, no
growth-hacked cadence.
action: /subscribed
consequence: [Subscribe]
features:
- name: Where to send it
description: ""
requirements:
- name: email
label: Email
type: email
- name: I want in
description: >
We onboard collaborators the same deliberate way we build —
by hand, with a real conversation, not a form that vanishes into
a queue.
action: /applied
consequence: [Apply]
encouragements:
- Every application gets read by a person, not a filter.
features:
- name: Who are you?
description: ""
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: What draws you here?
description: ""
requirements:
- name: interest
label: What do you want to work on?
type: textarea
- name: note
label: Anything else worth knowing
type: textarea
optional: true
+16
View File
@@ -0,0 +1,16 @@
id: /project
route: ^/project
name: Got it
description: >
That's on its way to a real inbox, not a CRM stage. Expect a reply
from a person within a couple of days.
alternatives:
- name: What happens now
description: ""
features:
- name: We read it
description: Properly — before we write back, not while we write back.
- name: We ask questions
description: >
Usually more of them than you expect. Good software starts
with a good argument about what it's actually for.
+14
View File
@@ -0,0 +1,14 @@
id: /subscribed
route: ^/subscribed
name: You're on the list
description: >
We'll write when there's something worth your time — that's the
whole promise.
alternatives:
- name: What to expect
description: ""
features:
- name: Rare, not routine
description: No weekly filler. A few notes a year, maybe.
- name: Easy to leave
description: Every note has a real unsubscribe link, not a maze.