Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f243494499 | ||
|
|
ad9dd1762b |
@@ -18,7 +18,7 @@ on:
|
|||||||
- .gitea/workflows/deploy.yml
|
- .gitea/workflows/deploy.yml
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PORTAL_RELEASE: v0.1.0
|
PORTAL_RELEASE: v0.2.0
|
||||||
INSTANCE: uhhm-portal
|
INSTANCE: uhhm-portal
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -167,10 +167,14 @@ The rules every page here follows:
|
|||||||
The exact structs live in portal's `src/content.rs`; the shape:
|
The exact structs live in portal's `src/content.rs`; the shape:
|
||||||
|
|
||||||
```
|
```
|
||||||
Question id (doubles as the URL path), name, description,
|
Question id (derived from the file's path - see routing
|
||||||
qualifies (Kanidm group gate), followup (nav-hidden
|
below - declare only to override), name,
|
||||||
until the visitor carries a chain),
|
description, qualifies (Kanidm group gate),
|
||||||
responsible {name, contact}, alternatives[]
|
requires_chain (question ref the visitor's ?chain=
|
||||||
|
lineage must end at), followup (nav-hidden until
|
||||||
|
the visitor carries a chain; inferred from the
|
||||||
|
tree when unset), responsible {name, contact},
|
||||||
|
alternatives[]
|
||||||
Alternative name, description, action, consequence[label],
|
Alternative name, description, action, consequence[label],
|
||||||
encouragements[], images[] (1 = banner, 2+ = card deck),
|
encouragements[], images[] (1 = banner, 2+ = card deck),
|
||||||
record_as (bucket), self_transition {bucket, to, label},
|
record_as (bucket), self_transition {bucket, to, label},
|
||||||
@@ -208,9 +212,54 @@ review resource's transitions — fireable by whoever holds one specific
|
|||||||
record's `?chain=` link plus its matching email (the unsubscribe
|
record's `?chain=` link plus its matching email (the unsubscribe
|
||||||
pattern).
|
pattern).
|
||||||
|
|
||||||
|
## Routing: the tree is the router
|
||||||
|
|
||||||
|
The `questions/` directory tree is the URL tree — `index.yaml` names
|
||||||
|
its directory, everything else appends its stem:
|
||||||
|
|
||||||
|
```
|
||||||
|
questions/
|
||||||
|
index.yaml /
|
||||||
|
applied.yaml /applied
|
||||||
|
develop/
|
||||||
|
index.yaml /develop
|
||||||
|
proposal.yaml /develop/proposal
|
||||||
|
proposed.yaml /develop/proposed
|
||||||
|
review/
|
||||||
|
_section.yaml (not a page - defaults for the directory)
|
||||||
|
index.yaml /review
|
||||||
|
[record].yaml /review/<any value>
|
||||||
|
```
|
||||||
|
|
||||||
|
- `id:` is derived from the path; declaring it still wins (legacy),
|
||||||
|
with a lint warning when it disagrees.
|
||||||
|
- `action:` and `requires_chain:` take relative refs — `proposed`
|
||||||
|
names a sibling, `../x` climbs, `/x` is absolute. A directory is a
|
||||||
|
self-contained flow: `git mv` renames every internal edge with it.
|
||||||
|
- Files nested in a subdirectory infer `followup: true` unless
|
||||||
|
they're the directory's `index.yaml` — declare `followup: false`
|
||||||
|
on a nested page that should stay in the nav. Top-level files keep
|
||||||
|
the flat-repo default (not a followup).
|
||||||
|
- `_section.yaml` applies `qualifies`, `requires_chain`, and
|
||||||
|
`responsible` to every page at or below its directory (nearest
|
||||||
|
ancestor wins; a page's own declaration always overrides). A URL
|
||||||
|
prefix is a trust boundary.
|
||||||
|
- Any other `_`-prefixed file is skipped entirely — drafts live in
|
||||||
|
the tree without being served.
|
||||||
|
- `[name].yaml` is a dynamic page: it serves every `/dir/<value>`,
|
||||||
|
with the segment substituted into `{name}` placeholders in the
|
||||||
|
page's resource `key`s (`/review/<chain-hash>` shows that one
|
||||||
|
record). One per directory; never in the nav; not a valid `action`
|
||||||
|
target.
|
||||||
|
- `requires_chain: <ref>` gates a page on provenance instead of
|
||||||
|
identity: the visitor's `?chain=` lineage must verifiably end at an
|
||||||
|
answer to the referenced question, otherwise the page renders a
|
||||||
|
pointer there instead of its alternatives.
|
||||||
|
|
||||||
## Adding a page
|
## Adding a page
|
||||||
|
|
||||||
Drop a `questions/<name>.yaml` with a unique `id`, reference that `id`
|
Drop a YAML file where its URL should live (`questions/foo.yaml` →
|
||||||
from some alternative's `action`, push. Lint runs, portal hot-reloads,
|
`/foo`, `questions/flow/step.yaml` → `/flow/step`), reference it from
|
||||||
the page is live — no registration, no deploy. Or propose it through
|
some alternative's `action`, push. Lint runs, portal hot-reloads, the
|
||||||
`/develop-proposal` and let the loop do the pushing.
|
page is live — no registration, no deploy. Or propose it through
|
||||||
|
`/develop/proposal` and let the loop do the pushing.
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
id: /applied
|
|
||||||
route: ^/applied
|
|
||||||
followup: true
|
followup: true
|
||||||
name: What happens now that you've applied?
|
name: What happens now that you've applied?
|
||||||
description: >
|
description: >
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
id: /develop
|
|
||||||
route: ^/develop
|
|
||||||
name: Development proposals
|
name: Development proposals
|
||||||
qualifies: owners
|
qualifies: owners
|
||||||
description: >
|
description: >
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
id: /develop-proposal
|
# Nested for the flow, but a public entry point - without this it
|
||||||
route: ^/develop-proposal
|
# would infer followup and drop out of the nav.
|
||||||
|
followup: false
|
||||||
name: How can this website improve?
|
name: How can this website improve?
|
||||||
description: >
|
description: >
|
||||||
This site is built on the same question architecture you're using
|
This site is built on the same question architecture you're using
|
||||||
@@ -13,7 +14,7 @@ alternatives:
|
|||||||
a page under questions/, or aggregates.yaml — verbatim, so it
|
a page under questions/, or aggregates.yaml — verbatim, so it
|
||||||
has to be complete, valid YAML for that file, not a diff.
|
has to be complete, valid YAML for that file, not a diff.
|
||||||
Nothing outside those files is in scope.
|
Nothing outside those files is in scope.
|
||||||
action: /proposed
|
action: proposed
|
||||||
consequence: [Propose it]
|
consequence: [Propose it]
|
||||||
record_as: development_proposals
|
record_as: development_proposals
|
||||||
encouragements:
|
encouragements:
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
id: /proposed
|
# Reached from the proposal form only - and provably so: the visitor
|
||||||
route: ^/proposed
|
# must hold a ?chain= lineage ending at an answer to proposal.yaml.
|
||||||
followup: true
|
requires_chain: proposal
|
||||||
name: Proposal received
|
name: Proposal received
|
||||||
description: >
|
description: >
|
||||||
It's in the queue. An owner reads every proposal in full — approved
|
It's in the queue. An owner reads every proposal in full — approved
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
id: /
|
|
||||||
name: What are you here for?
|
name: What are you here for?
|
||||||
description: >
|
description: >
|
||||||
Strategies that address problems — applied in software.
|
Strategies that address problems — applied in software.
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
id: /project
|
|
||||||
route: ^/project
|
|
||||||
followup: true
|
followup: true
|
||||||
name: So, what happens now?
|
name: So, what happens now?
|
||||||
description: >
|
description: >
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Dynamic page: /review/<chain-hash> shows one development proposal,
|
||||||
|
# addressed by its record key. The {record} placeholder receives the
|
||||||
|
# URL segment; the section's qualifies (plus the resource's own
|
||||||
|
# requires_group) keeps it owner-only.
|
||||||
|
name: One proposal
|
||||||
|
description: >
|
||||||
|
A single development proposal, addressed by its record key — link or
|
||||||
|
paste a chain hash from the desk.
|
||||||
|
alternatives:
|
||||||
|
- name: Record
|
||||||
|
description: ""
|
||||||
|
features:
|
||||||
|
- name: ""
|
||||||
|
description: ""
|
||||||
|
resource:
|
||||||
|
source:
|
||||||
|
kind: kv
|
||||||
|
bucket: development_proposals
|
||||||
|
key: "{record}"
|
||||||
|
requires_group: owners
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Everything under /review is the owners' area - one gate for the
|
||||||
|
# whole directory instead of a qualifies flag per file.
|
||||||
|
qualifies: owners
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
id: /review
|
|
||||||
route: ^/review
|
|
||||||
name: The review desk
|
name: The review desk
|
||||||
qualifies: owners
|
|
||||||
description: >
|
description: >
|
||||||
Sign in as an organizational owner to see what's come in.
|
Sign in as an organizational owner to see what's come in.
|
||||||
alternatives:
|
alternatives:
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
id: /subscribed
|
|
||||||
route: ^/subscribed
|
|
||||||
followup: true
|
followup: true
|
||||||
name: What should you expect?
|
name: What should you expect?
|
||||||
description: >
|
description: >
|
||||||
|
|||||||
Reference in New Issue
Block a user